Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89f5736f6b | ||
|
|
101c103aeb | ||
|
|
de315a43a1 | ||
|
|
90f173ba52 | ||
|
|
e4591ea1b4 | ||
|
|
a7deffedec | ||
|
|
5949540007 | ||
|
|
7afb79117b | ||
|
|
442bb4a340 | ||
|
|
99467be133 | ||
|
|
887060acdf | ||
|
|
90609e960c | ||
|
|
d893928221 | ||
|
|
5bc086fd9d | ||
|
|
aca176b9e7 | ||
|
|
9707dbcbf9 | ||
|
|
52e5af8116 | ||
|
|
42058244f2 | ||
|
|
bddaa75e8c | ||
|
|
7904439f35 | ||
|
|
c873af3d00 | ||
|
|
fa2852d3e7 | ||
|
|
1c4ebefae4 | ||
|
|
96a6dd368a | ||
|
|
ed4f04b19c | ||
|
|
f325865869 | ||
|
|
a15dd998f3 | ||
|
|
f17dc0550b | ||
|
|
ed76c8415b | ||
|
|
9f2c105074 | ||
|
|
ccef61b2b9 | ||
|
|
3cf1cab68f | ||
|
|
0579fd3bb6 | ||
|
|
c6688355a7 | ||
|
|
68ed1834a9 | ||
|
|
487670d207 | ||
|
|
a109ac98ed | ||
|
|
d928a95ed1 | ||
|
|
ffa6873a86 | ||
|
|
db2eb6fbac | ||
|
|
68d471bfc6 | ||
|
|
03c71368f5 | ||
|
|
2fd83289fd | ||
|
|
7dd60a8946 | ||
|
|
ccaf1fae52 | ||
|
|
4db2ec5911 | ||
|
|
34e9baccf3 | ||
|
|
3febcfcc04 | ||
|
|
bb15199b4e | ||
|
|
4ec54b690c | ||
|
|
3f7408301a | ||
|
|
da7dde23d4 | ||
|
|
5517f53f8a | ||
|
|
9f128f8445 | ||
|
|
f02f096356 | ||
|
|
e0ffa95951 | ||
|
|
357f0e7bb1 | ||
|
|
475807a1c6 | ||
|
|
e06acd65a6 | ||
|
|
893f9ec2d8 | ||
|
|
1274a0c646 | ||
|
|
e4ae8162a0 | ||
|
|
dce9074969 | ||
|
|
b7da34ff93 | ||
|
|
c360240259 | ||
|
|
e68dc2212c | ||
|
|
e63d772959 | ||
|
|
45700d77ab | ||
|
|
f09cb8a7b5 | ||
|
|
49a36de149 | ||
|
|
309a481a69 | ||
|
|
a11445e7c0 | ||
|
|
d5c431a609 | ||
|
|
cfe19e637f | ||
|
|
cea68fed86 | ||
|
|
273f4bd858 | ||
|
|
55d5ff39ff | ||
|
|
6049db1f24 | ||
|
|
b479dd0b2f | ||
|
|
8b199869c7 | ||
|
|
b9a954a058 | ||
|
|
82aecd0aae | ||
|
|
812af254b5 | ||
|
|
a05596c416 | ||
|
|
cb251f93b5 | ||
|
|
317f1521eb | ||
|
|
9c9824c05e | ||
|
|
564a09c96d | ||
|
|
7fb5fa75ee | ||
|
|
d01ae7217f | ||
|
|
2ff93cef3c | ||
|
|
f7f33d0c79 | ||
|
|
50142b48f8 | ||
|
|
1b17b95e8c | ||
|
|
4de527aa42 | ||
|
|
de22f7218a | ||
|
|
fdb4c887c3 | ||
|
|
c6fe2865b6 | ||
|
|
5ea0b4a895 | ||
|
|
523e7f8271 | ||
|
|
c93ff60900 | ||
|
|
26e5159c1d | ||
|
|
0f09ef92dd | ||
|
|
5ac7df1854 | ||
|
|
7f3682e884 | ||
|
|
600bff8da4 | ||
|
|
c9f6d76d30 | ||
|
|
c030b55521 | ||
|
|
83c595144b | ||
|
|
3a9514629a | ||
|
|
ae8ff0640b | ||
|
|
b883b003be | ||
|
|
89f91f7831 | ||
|
|
a4f56d582b | ||
|
|
56d5ec2d37 | ||
|
|
ad9ca5e7cb | ||
|
|
36b26b43c9 | ||
|
|
3d1f42351f | ||
|
|
1a2b790f2b | ||
|
|
81b772df9a | ||
|
|
7c4f283a05 | ||
|
|
66c460adad | ||
|
|
efa1bbaecb | ||
|
|
ad21f66a44 | ||
|
|
d5a07c11db | ||
|
|
f4b0af1eb1 | ||
|
|
79400b8f52 | ||
|
|
e1706d97f2 | ||
|
|
023c183e85 | ||
|
|
77d6e23c45 | ||
|
|
ca1f12b91b | ||
|
|
f2eda0e7d7 | ||
|
|
153bd21910 | ||
|
|
a3ca718131 | ||
|
|
4342677344 | ||
|
|
26421190b1 | ||
|
|
906dc18060 | ||
|
|
2cb7ac34ce | ||
|
|
6d1edf9184 | ||
|
|
e1d55649d5 | ||
|
|
6a7a3d623e | ||
|
|
83e93dcf43 | ||
|
|
a32cf60958 | ||
|
|
14f42b638d | ||
|
|
89c3ecea68 | ||
|
|
c65e6321f5 | ||
|
|
d1954ff326 | ||
|
|
592c7e6915 | ||
|
|
ecbdcaa57e | ||
|
|
aad1b426f0 | ||
|
|
ce81133560 | ||
|
|
454e68033c | ||
|
|
8da3d2b3f8 | ||
|
|
59795c3dc3 | ||
|
|
6adc04200e | ||
|
|
f3c71d6f19 | ||
|
|
8cedd9123b | ||
|
|
7313294c69 | ||
|
|
424c5c4f7b | ||
|
|
e0f0c5c7f6 | ||
|
|
2eb97e6724 | ||
|
|
5b491ddbf7 | ||
|
|
164b741d57 | ||
|
|
dfda888e57 | ||
|
|
a6c4b5ab3d | ||
|
|
488a645cf4 | ||
|
|
68bfc0ecef | ||
|
|
f4feb42dda | ||
|
|
49fab1b488 | ||
|
|
06e6b2798b | ||
|
|
09ce9a882a | ||
|
|
2ff7e90cea | ||
|
|
a9c1f5b790 | ||
|
|
9fe561085b | ||
|
|
92f9b93353 | ||
|
|
4198e932ca | ||
|
|
00d1b01624 | ||
|
|
75e417129d | ||
|
|
46b5edfd3b | ||
|
|
e66f535dd3 | ||
|
|
4d5a532b23 | ||
|
|
369850b86d | ||
|
|
7553d9dbb6 | ||
|
|
ed2a9cc204 | ||
|
|
9a1b2b93f6 | ||
|
|
3c66eb646e | ||
|
|
82cf54706b | ||
|
|
8cfb2d1246 | ||
|
|
aa9177df0c | ||
|
|
864fb36af5 | ||
|
|
f0aaa06d15 | ||
|
|
60795111b0 | ||
|
|
469551c2b5 | ||
|
|
6eafeb15a4 | ||
|
|
d3e95712fd | ||
|
|
fecc01e230 | ||
|
|
d75735ecb0 | ||
|
|
70fcb0d70d | ||
|
|
6eee5cf350 | ||
|
|
21bf224fef | ||
|
|
139f8cdc11 | ||
|
|
ff8fdddbdc | ||
|
|
93ebb9468c | ||
|
|
a1e71fd0ce | ||
|
|
208bb5e93d | ||
|
|
416d9d00ad | ||
|
|
3550c4a448 | ||
|
|
3af3791f54 | ||
|
|
196841db50 | ||
|
|
bb67df8f42 | ||
|
|
26e9dbcd40 | ||
|
|
42f9485a39 | ||
|
|
6fb9ce67c0 | ||
|
|
06ddc45955 | ||
|
|
93c8f0f8e4 | ||
|
|
a667f89c12 | ||
|
|
8991aaae8d | ||
|
|
97708c7947 | ||
|
|
688e94d97c | ||
|
|
a09b6bf8aa | ||
|
|
f2ce720a3d | ||
|
|
a5c5061a2f | ||
|
|
5321dcc3ba | ||
|
|
ac5118c4e3 | ||
|
|
a4f28cec5d | ||
|
|
95f43be2af | ||
|
|
ff9c1576b6 | ||
|
|
4f7e30b498 | ||
|
|
d6aba5fd39 | ||
|
|
f70606b5ec | ||
|
|
92e2e8c0d6 | ||
|
|
23dce5b886 | ||
|
|
80a3391b84 | ||
|
|
8f8c2104a2 | ||
|
|
7f4c96371e | ||
|
|
46c3b7c17e | ||
|
|
319a4389ac | ||
|
|
32b3908aa3 | ||
|
|
f798e4936c | ||
|
|
e534faf115 | ||
|
|
a93dbbfb5c | ||
|
|
f0cca0ed02 | ||
|
|
0f7ad9b741 | ||
|
|
b9fc781f28 | ||
|
|
c47e921a3b | ||
|
|
7890b4b3ca | ||
|
|
f69ceb5025 | ||
|
|
aa75d276dc | ||
|
|
ffebcccd32 | ||
|
|
3b201c82db | ||
|
|
704509560a | ||
|
|
8c496d2bc2 | ||
|
|
5992fdd659 | ||
|
|
d476cf91dc | ||
|
|
02d28b4322 | ||
|
|
9e47e2bf4f | ||
|
|
95f5b9df68 | ||
|
|
1ffaf4689e | ||
|
|
140f7842cc | ||
|
|
b5311b2651 | ||
|
|
e99851fba3 | ||
|
|
3acbae5ea0 | ||
|
|
56b5db7df3 | ||
|
|
698ed78acc | ||
|
|
9c3330b45d | ||
|
|
9e5b2c5ed7 | ||
|
|
11fa4aed48 | ||
|
|
919cf1437d | ||
|
|
1b5a55ccf2 | ||
|
|
b3efd09fb3 | ||
|
|
617927c291 | ||
|
|
0ce492d083 | ||
|
|
4cf1beb49f | ||
|
|
c41c259cd6 | ||
|
|
a3e95abfde | ||
|
|
164d2b21e9 | ||
|
|
b34e343535 | ||
|
|
8ccb6f4d77 | ||
|
|
36b80dc758 | ||
|
|
927d09ffb5 | ||
|
|
a5ecd2d389 | ||
|
|
039ea71678 | ||
|
|
a0b09410b3 | ||
|
|
3dbef96cf0 | ||
|
|
69f276955a | ||
|
|
e56e5a4b3d | ||
|
|
6b31516cd9 | ||
|
|
61d83e6614 | ||
|
|
4d0130c297 | ||
|
|
7331cb7cb2 | ||
|
|
8c431c690e | ||
|
|
f60406d0f1 | ||
|
|
7e18d78805 | ||
|
|
cd1833f3ad | ||
|
|
45818b1eba | ||
|
|
9561ca95a1 | ||
|
|
875ab3bd8e | ||
|
|
1dd8e0a016 | ||
|
|
5862c98f3e | ||
|
|
ddb533a255 | ||
|
|
cc951d4745 | ||
|
|
557f7aa333 | ||
|
|
e0eee90202 | ||
|
|
d8ded2d456 | ||
|
|
862a78276f | ||
|
|
e69cff0735 | ||
|
|
f42a31578e | ||
|
|
90894f806a | ||
|
|
5c9ada9468 | ||
|
|
cf1d3d0ba1 | ||
|
|
58d52ad61f | ||
|
|
0c3a07f208 | ||
|
|
44e0508ae5 | ||
|
|
4676b817e9 | ||
|
|
32b17c3373 | ||
|
|
7e95498f7a | ||
|
|
4712d39427 | ||
|
|
4c87353db4 | ||
|
|
d1b20a1446 | ||
|
|
18f23db0fa | ||
|
|
8106cff45f | ||
|
|
75ac1631c4 | ||
|
|
021ef0cdc1 | ||
|
|
c995d2a47c | ||
|
|
de76fe14ea | ||
|
|
ca50b1f2d0 | ||
|
|
a4cfa9c651 | ||
|
|
430d032095 | ||
|
|
0bf813e865 | ||
|
|
a65f54e9a1 | ||
|
|
0c7ce90980 | ||
|
|
4aba1bc7cb | ||
|
|
cf1ef1c819 | ||
|
|
855e376610 | ||
|
|
c6eeabce62 | ||
|
|
5e7b1ff0ba | ||
|
|
2b512b1315 | ||
|
|
dae2c224e5 | ||
|
|
fcda0abc21 | ||
|
|
c862d496e3 | ||
|
|
7968f83bf8 | ||
|
|
8cba1bad43 | ||
|
|
bc6365567f | ||
|
|
6c4e8adda1 | ||
|
|
c22ec9b074 | ||
|
|
3e753bcf97 | ||
|
|
6ba95de6e6 | ||
|
|
064d41588c | ||
|
|
582462a73f | ||
|
|
f58e7f04f1 | ||
|
|
bd951e19d3 | ||
|
|
91e99a2dbf | ||
|
|
a7d2beabe0 | ||
|
|
2f78d033ab | ||
|
|
cce74b29ad | ||
|
|
aa1c0a24e2 | ||
|
|
cf4d9b63c7 | ||
|
|
f0802c3035 | ||
|
|
86da6acf3f | ||
|
|
697bc882c7 | ||
|
|
8a0ffc940e | ||
|
|
63e947bf84 | ||
|
|
24329aa3d2 | ||
|
|
58bdaca252 | ||
|
|
6249049bcc | ||
|
|
70e89d9203 | ||
|
|
39f053eee4 | ||
|
|
4cfcb28c60 | ||
|
|
1027a2a77b | ||
|
|
5dd3ffd9ef | ||
|
|
2aa31ac911 | ||
|
|
3d49e0aabe | ||
|
|
8c425f62b6 | ||
|
|
9080697dc0 | ||
|
|
279bdf8c7e | ||
|
|
7d67ae2562 | ||
|
|
8922350379 | ||
|
|
df922b18a7 | ||
|
|
5d08565ff1 | ||
|
|
757a9b1e3e | ||
|
|
32bc096d9a | ||
|
|
5b52dcc7fe | ||
|
|
d871c378fe | ||
|
|
68bc60f6f4 | ||
|
|
47a3e71b01 | ||
|
|
dfa6fadf2d | ||
|
|
dffd8b5299 | ||
|
|
85f8dcef98 | ||
|
|
d3884c6eca | ||
|
|
98e2d8ad7a | ||
|
|
cde602d77d | ||
|
|
af168d2c57 | ||
|
|
a289ddf1fd | ||
|
|
323783b89e | ||
|
|
d423c08440 | ||
|
|
38fe983010 | ||
|
|
1b32dff6a4 | ||
|
|
189fb0d767 | ||
|
|
037995ab59 | ||
|
|
8dde9f19a4 | ||
|
|
8c77f3eddb | ||
|
|
e74bbe4044 | ||
|
|
9448ac1012 | ||
|
|
8b5bb28c94 | ||
|
|
caf1b5e9a9 | ||
|
|
fa7d586a97 | ||
|
|
7a3fd2150b | ||
|
|
0397183f2a | ||
|
|
751212db47 | ||
|
|
bc38385fe9 | ||
|
|
76f52846de | ||
|
|
771ac22d7f | ||
|
|
47b3bcf297 | ||
|
|
5e7dd321f0 | ||
|
|
489dac5488 | ||
|
|
b1ad643364 | ||
|
|
b40322dc2c | ||
|
|
6e2954d446 | ||
|
|
6b69651a21 | ||
|
|
cb1a5c90e6 | ||
|
|
6e1ab5f103 | ||
|
|
6a825cf3fd | ||
|
|
928bfd3d97 | ||
|
|
4e2457b05d | ||
|
|
98916b4404 | ||
|
|
48baf7812d | ||
|
|
1ee73eae37 | ||
|
|
18dd56e790 | ||
|
|
762293536f | ||
|
|
7c1519a0de | ||
|
|
e153efe9e4 | ||
|
|
70c64bf081 | ||
|
|
80071fbeaa | ||
|
|
0e653fdefa | ||
|
|
2418894dcb | ||
|
|
088e324b88 | ||
|
|
a3d0e2c588 | ||
|
|
c813b5a3c0 | ||
|
|
f71e4acf7e | ||
|
|
bdbb590dc4 | ||
|
|
07a04b069e | ||
|
|
d12b345fe8 | ||
|
|
9d57d0568c | ||
|
|
290b75de3f | ||
|
|
292623ab52 | ||
|
|
dfcbacd464 | ||
|
|
7fa16f2b70 | ||
|
|
372da19f30 | ||
|
|
0616f39e35 | ||
|
|
d51f17fdad | ||
|
|
3e7d40c4f6 | ||
|
|
d4d695fecf | ||
|
|
477a145712 | ||
|
|
2f912b0b95 | ||
|
|
83f4dba674 | ||
|
|
b05c2c4437 | ||
|
|
5b2edd0f7d | ||
|
|
aad71179a5 | ||
|
|
a2b7753cd8 | ||
|
|
2eac4d37b3 | ||
|
|
01ff72e775 | ||
|
|
6f3fb4dce4 | ||
|
|
9d214f9dab | ||
|
|
4b62a4eec7 | ||
|
|
3ff8bc68c3 | ||
|
|
f6e3b38e6a | ||
|
|
887b318e27 |
@@ -1,2 +1,3 @@
|
||||
SEARXNG_BASE_URL="http://127.0.0.1:8080"
|
||||
OPENAI_API_KEY='dont share this, not needed for local providers'
|
||||
OPENAI_API_KEY='xxxxx'
|
||||
DEEPSEEK_API_KEY='xxxxx'
|
||||
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [Fosowl ]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
|
||||
@@ -1,11 +1,36 @@
|
||||
*.wav
|
||||
config.ini
|
||||
*.DS_Store
|
||||
*.log
|
||||
*.tmp
|
||||
*.safetensors
|
||||
*.egg-info
|
||||
cookies.json
|
||||
test_agent.py
|
||||
config.ini
|
||||
.voices/
|
||||
experimental/
|
||||
.logs/
|
||||
.screenshots/*.png
|
||||
.screenshots/*.jpg
|
||||
conversations/
|
||||
agentic_env/*
|
||||
agentic_seek_env/*
|
||||
.env
|
||||
*/.env
|
||||
dsk/
|
||||
|
||||
### react ###
|
||||
.DS_*
|
||||
*.log
|
||||
logs
|
||||
**/*.backup.*
|
||||
**/*.back.*
|
||||
node_modules
|
||||
bower_components
|
||||
*.sublime*
|
||||
psd
|
||||
thumb
|
||||
sketch
|
||||
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: trufflehog
|
||||
name: TruffleHog
|
||||
description: Detect secrets in your data.
|
||||
entry: bash -c 'trufflehog git file://. --since-commit HEAD --results=verified,unknown --no-update'
|
||||
language: system
|
||||
stages: ["commit", "push"]
|
||||
@@ -1,90 +0,0 @@
|
||||
# Contributors guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.8 or higher
|
||||
- Ollama installed (for local model execution)
|
||||
- Basic familiarity with Python and AI models
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
We welcome contributions in the following areas:
|
||||
|
||||
- Code Improvements: Optimize existing code, fix bugs, or add new features.
|
||||
- Documentation: Improve the README, write tutorials, or add inline comments.
|
||||
- Testing: Write unit tests, integration tests, or help with debugging.
|
||||
- New Features: Implement new tools, agents, or integrations.
|
||||
|
||||
## Steps to Contribute
|
||||
|
||||
Fork the project to your GitHub account.
|
||||
|
||||
Create a Branch:
|
||||
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
Make Your Changes.
|
||||
|
||||
Write your code, add documentation, or fix bugs.
|
||||
|
||||
Test Your Changes.
|
||||
|
||||
Ensure your changes work as expected and do not break existing functionality.
|
||||
|
||||
Push your changes to your fork and submit a pull request to the main branch of this repository. Provide a clear description of your changes and reference any related issues.
|
||||
|
||||
## Coding Philosophy
|
||||
|
||||
1. **Privacy First, Always Local**
|
||||
- All core functionality must be able to run 100% locally
|
||||
- Cloud services should only be optional alternatives, clearly defined with a warning message.
|
||||
- User data privacy is non-negotiable
|
||||
|
||||
2. **Agent-Based Architecture**
|
||||
- Each agent should have a clear, single responsibility
|
||||
- Agents should be modular and independently testable
|
||||
- New agents should solve specific use cases
|
||||
|
||||
3. **Tool-Based Extensibility**
|
||||
- Tools should be self-contained and follow the Tools base class
|
||||
- Each tool should do one thing well
|
||||
- Tools should provide clear feedback on success/failure
|
||||
|
||||
4. **User Experience**
|
||||
- Provide meaningful feedback for all operations
|
||||
- Support multiple languages (chinese, french, english for now)
|
||||
- Text to speech with short response.
|
||||
- Keep responses concise
|
||||
|
||||
5. **Code Quality**
|
||||
- Write clear, self-documenting code
|
||||
- Include type hints and docstrings
|
||||
- Follow existing patterns in the codebase
|
||||
- Add a if __name__ == "__main__" at the bottom of each class file for individual testing.
|
||||
- Ideally had automated tests.
|
||||
|
||||
6. **Error Handling**
|
||||
- Fail gracefully with meaningful messages
|
||||
- Include recovery mechanisms where possible
|
||||
- Log errors appropriately without exposing sensitive data
|
||||
|
||||
## Areas Needing Help
|
||||
|
||||
Here are some high-priority tasks and areas where we need contributions:
|
||||
|
||||
- Web Browsing: Implement autonomous web browsing capabilities for the assistant.
|
||||
- Multi-Agent System: Enhance the multi-agent functionality on the dev branch.
|
||||
- Memory & Recovery: Improve conversation compression.
|
||||
- New Tools: Add support for additional programming languages or APIs.
|
||||
- Testing: Write comprehensive tests for existing and new features.
|
||||
|
||||
|
||||
If you're unsure where to start, feel free to reach out by opening an issue or joining our community discussions.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
See CODE_OF_CONDUCT.md
|
||||
|
||||
**Thank You!**
|
||||
@@ -0,0 +1,47 @@
|
||||
FROM ubuntu:22.04
|
||||
# Warning: doesn't work yet, backend is run on host machine for now
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update -qq -y && \
|
||||
apt-get install -y \
|
||||
gcc \
|
||||
g++ \
|
||||
gfortran \
|
||||
libportaudio2 \
|
||||
portaudio19-dev \
|
||||
ffmpeg \
|
||||
libavcodec-dev \
|
||||
libavformat-dev \
|
||||
libavutil-dev \
|
||||
gnupg2 \
|
||||
wget \
|
||||
unzip \
|
||||
python3 \
|
||||
python3-pip \
|
||||
libasound2 \
|
||||
libatk-bridge2.0-0 \
|
||||
libgtk-4-1 \
|
||||
libnss3 \
|
||||
xdg-utils \
|
||||
wget && \
|
||||
|
||||
RUN chmod +x /opt/chrome/chrome
|
||||
# Install dependencies
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code
|
||||
COPY api.py .
|
||||
COPY sources/ ./sources/
|
||||
COPY prompts/ ./prompts/
|
||||
COPY crx/ crx/
|
||||
COPY llm_router/ llm_router/
|
||||
COPY .env .
|
||||
COPY config.ini .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run the application
|
||||
CMD ["python3", "api.py"]
|
||||
@@ -1,54 +1,51 @@
|
||||
# AgenticSeek: Private, Local Manus Alternative.
|
||||
|
||||
# AgenticSeek: Manus-like AI powered by Deepseek R1 Agents.
|
||||
<p align="center">
|
||||
<img align="center" src="./media/agentic_seek_logo.png" width="300" height="300" alt="Agentic Seek Logo">
|
||||
<p>
|
||||
|
||||
English | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | [日本語](./README_JP.md)
|
||||
|
||||
**A fully local alternative to Manus AI**, a voice-enabled AI assistant that codes, explores your filesystem, browse the web and correct it's mistakes all without sending a byte of data to the cloud. Built with reasoning models like DeepSeek R1, this autonomous agent runs entirely on your hardware, keeping your data private.
|
||||
*A **100% local alternative to Manus AI**, this voice-enabled AI assistant autonomously browses the web, writes code, and plans tasks while keeping all data on your device. Tailored for local reasoning models, it runs entirely on your hardware, ensuring complete privacy and zero cloud dependency.*
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460) [](https://github.com/Fosowl/agenticSeek/stargazers)
|
||||
|
||||
### Why AgenticSeek ?
|
||||
|
||||
* 🔒 Fully Local & Private - Everything runs on your machine — no cloud, no data sharing. Your files, conversations, and searches stay private.
|
||||
|
||||
* 🌐 Smart Web Browsing - AgenticSeek can browse the internet by itself — search, read, extract info, fill web form — all hands-free.
|
||||
|
||||
* 💻 Autonomous Coding Assistant - Need code? It can write, debug, and run programs in Python, C, Go, Java, and more — all without supervision.
|
||||
|
||||
* 🧠 Smart Agent Selection - You ask, it figures out the best agent for the job automatically. Like having a team of experts ready to help.
|
||||
|
||||
* 📋 Plans & Executes Complex Tasks - From trip planning to complex projects — it can split big tasks into steps and get things done using multiple AI agents.
|
||||
|
||||
* 🎙️ Voice-Enabled - Clean, fast, futuristic voice and speech to text allowing you to talk to it like it's your personal AI from a sci-fi movie
|
||||
|
||||
### **Demo**
|
||||
|
||||
> *Can you search for the agenticSeek project, learn what skills are required, then open the CV_candidates.zip and then tell me which match best the project*
|
||||
|
||||
https://github.com/user-attachments/assets/b8ca60e9-7b3b-4533-840e-08f9ac426316
|
||||
|
||||
Disclaimer: This demo, including all the files that appear (e.g: CV_candidates.zip), are entirely fictional. We are not a corporation, we seek open-source contributors not candidates.
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  
|
||||
> 🛠️ **Work in Progress** – Looking for contributors!
|
||||
|
||||

|
||||
## Installation
|
||||
|
||||
Make sure you have chrome driver, docker and python3.10 (or newer) installed.
|
||||
|
||||
For issues related to chrome driver, see the **Chromedriver** section.
|
||||
|
||||
## Features:
|
||||
|
||||
- **100% Local**: No cloud, runs on your hardware. Your data stays yours.
|
||||
|
||||
- **Voice interaction**: Voice-enabled natural interaction.
|
||||
|
||||
- **Filesystem interaction**: Use bash to navigate and manipulate your files effortlessly.
|
||||
|
||||
- **Code what you ask**: Can write, debug, and run code in Python, C, Golang and more languages on the way.
|
||||
|
||||
- **Autonomous**: If a command flops or code breaks, it retries and fixes it by itself.
|
||||
|
||||
- **Agent routing**: Automatically picks the right agent for the job.
|
||||
|
||||
- **Divide and Conquer**: For big tasks, spins up multiple agents to plan and execute.
|
||||
|
||||
- **Tool-Equipped**: From basic search to flight APIs and file exploration, every agent has it's own tools.
|
||||
|
||||
- **Memory**: Remembers what’s useful, your preferences and past sessions conversation.
|
||||
|
||||
- **Web Browsing**: Autonomous web navigation is underway.
|
||||
|
||||
|
||||
### Searching the web with agenticSeek :
|
||||
|
||||

|
||||
|
||||
*See media/examples for other use case screenshots.*
|
||||
|
||||
---
|
||||
|
||||
## **Installation**
|
||||
|
||||
### 1️⃣ **Clone the repository**
|
||||
### 1️⃣ **Clone the repository and setup**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
### 2️ **Create a virtual env**
|
||||
@@ -61,198 +58,497 @@ source agentic_seek_env/bin/activate
|
||||
|
||||
### 3️⃣ **Install package**
|
||||
|
||||
**Automatic Installation:**
|
||||
Ensure Python, Docker and docker compose, and Google chrome are installed.
|
||||
|
||||
We recommand Python 3.10.0.
|
||||
|
||||
**Automatic Installation (Recommanded):**
|
||||
|
||||
For Linux/Macos:
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
For windows:
|
||||
|
||||
```sh
|
||||
./install.bat
|
||||
```
|
||||
|
||||
**Manually:**
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
# or
|
||||
python3 setup.py install
|
||||
```
|
||||
**Note: For any OS, ensure the ChromeDriver you install matches your installed Chrome version. Run `google-chrome --version`. See known issues if you have chrome >135**
|
||||
|
||||
- *Linux*:
|
||||
|
||||
Update Package List: `sudo apt update`
|
||||
|
||||
Install Dependencies: `sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1`
|
||||
|
||||
Install ChromeDriver matching your Chrome browser version:
|
||||
`sudo apt install -y chromium-chromedriver`
|
||||
|
||||
Install requirements: `pip3 install -r requirements.txt`
|
||||
|
||||
- *Macos*:
|
||||
|
||||
Update brew : `brew update`
|
||||
|
||||
Install chromedriver : `brew install --cask chromedriver`
|
||||
|
||||
Install portaudio: `brew install portaudio`
|
||||
|
||||
Upgrade pip : `python3 -m pip install --upgrade pip`
|
||||
|
||||
Upgrade wheel : : `pip3 install --upgrade setuptools wheel`
|
||||
|
||||
Install requirements: `pip3 install -r requirements.txt`
|
||||
|
||||
- *Windows*:
|
||||
|
||||
Install pyreadline3 `pip install pyreadline3`
|
||||
|
||||
Install portaudio manually (e.g., via vcpkg or prebuilt binaries) and then run: `pip install pyaudio`
|
||||
|
||||
Download and install chromedriver manually from: https://sites.google.com/chromium.org/driver/getting-started
|
||||
|
||||
Place chromedriver in a directory included in your PATH.
|
||||
|
||||
Install requirements: `pip3 install -r requirements.txt`
|
||||
|
||||
---
|
||||
|
||||
## Setup for running LLM locally on your machine
|
||||
|
||||
**We recommend using at the very least Deepseek 14B, smaller models will struggle with tasks especially for web browsing.**
|
||||
|
||||
|
||||
## Run locally on your machine
|
||||
**Setup your local provider**
|
||||
|
||||
**We recommend using at least Deepseek 14B, smaller models struggle with tool use and forget quickly the context.**
|
||||
Start your local provider, for example with ollama:
|
||||
|
||||
### 1️⃣ **Download Models**
|
||||
|
||||
Make sure you have [Ollama](https://ollama.com/) installed.
|
||||
|
||||
Download the `deepseek-r1:7b` model from [DeepSeek](https://deepseek.com/models)
|
||||
|
||||
```sh
|
||||
ollama pull deepseek-r1:7b
|
||||
```
|
||||
|
||||
### 2️ **Run the Assistant (Ollama)**
|
||||
|
||||
Start the ollama server
|
||||
```sh
|
||||
ollama serve
|
||||
```
|
||||
|
||||
Change the config.ini file to set the provider_name to `ollama` and provider_model to `deepseek-r1:7b`
|
||||
See below for a list of local supported provider.
|
||||
|
||||
NOTE: `deepseek-r1:7b`is an example, use a bigger model if your hardware allow it.
|
||||
**Update the config.ini**
|
||||
|
||||
Change the config.ini file to set the provider_name to a supported provider and provider_model to a LLM supported by your provider. We recommand reasoning model such as *Qwen* or *Deepseek*.
|
||||
|
||||
See the **FAQ** at the end of the README for required hardware.
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:7b
|
||||
is_local = True # Whenever you are running locally or with remote provider.
|
||||
provider_name = ollama # or lm-studio, openai, etc..
|
||||
provider_model = deepseek-r1:14b # choose a model that fit your hardware
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Jarvis # name of your AI
|
||||
recover_last_session = True # whenever to recover the previous session
|
||||
save_session = True # whenever to remember the current session
|
||||
speak = True # text to speech
|
||||
listen = False # Speech to text, only for CLI
|
||||
work_dir = /Users/mlg/Documents/workspace # The workspace for AgenticSeek.
|
||||
jarvis_personality = False # Whenever to use a more "Jarvis" like personality (experimental)
|
||||
languages = en zh # The list of languages, Text to speech will default to the first language on the list
|
||||
[BROWSER]
|
||||
headless_browser = True # Whenever to use headless browser, recommanded only if you use web interface.
|
||||
stealth_mode = True # Use undetected selenium to reduce browser detection
|
||||
```
|
||||
|
||||
start all services :
|
||||
Note: Some provider (eg: lm-studio) require you to have `http://` in front of the IP. For example `http://127.0.0.1:1234`
|
||||
|
||||
```sh
|
||||
./start_services.sh
|
||||
```
|
||||
**List of local providers**
|
||||
|
||||
Run the assistant:
|
||||
| Provider | Local? | Description |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| ollama | Yes | Run LLMs locally with ease using ollama as a LLM provider |
|
||||
| lm-studio | Yes | Run LLM locally with LM studio (set `provider_name` to `lm-studio`)|
|
||||
| openai | Yes | Use openai compatible API (eg: llama.cpp server) |
|
||||
|
||||
```sh
|
||||
python3 main.py
|
||||
```
|
||||
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
*See the **Known issues** section if you are having issues*
|
||||
|
||||
*See the **Run with an API** section if your hardware can't run deepseek locally*
|
||||
|
||||
*See the **Config** section for detailled config file explanation.*
|
||||
|
||||
---
|
||||
|
||||
## **Run the LLM on your own server**
|
||||
## Setup to run with an API
|
||||
|
||||
If you have a powerful computer or a server that you can use, but you want to use it from your laptop you have the options to run the LLM on a remote server.
|
||||
Set the desired provider in the `config.ini`. See below for a list of API providers.
|
||||
|
||||
### 1️⃣ **Set up and start the server scripts**
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = google
|
||||
provider_model = gemini-2.0-flash
|
||||
provider_server_address = 127.0.0.1:5000 # doesn't matter
|
||||
```
|
||||
Warning: Make sure there is not trailing space in the config.
|
||||
|
||||
Export your API key: `export <<PROVIDER>>_API_KEY="xxx"`
|
||||
|
||||
Example: export `TOGETHER_API_KEY="xxxxx"`
|
||||
|
||||
**List of API providers**
|
||||
|
||||
| Provider | Local? | Description |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| openai | Depends | Use ChatGPT API |
|
||||
| deepseek-api | No | Deepseek API (non-private) |
|
||||
| huggingface| No | Hugging-Face API (non-private) |
|
||||
| togetherAI | No | Use together AI API (non-private) |
|
||||
| google | No | Use google gemini API (non-private) |
|
||||
|
||||
*We advice against using gpt-4o or other closedAI models*, performance are poor for web browsing and task planning.
|
||||
|
||||
Please also note that coding/bash might fail with gemini, it seem to ignore our prompt for format to respect, which are optimized for deepseek r1.
|
||||
|
||||
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
*See the **Known issues** section if you are having issues*
|
||||
|
||||
*See the **Config** section for detailled config file explanation.*
|
||||
|
||||
---
|
||||
|
||||
## Start services and Run
|
||||
|
||||
Activate your python env if needed.
|
||||
```sh
|
||||
source agentic_seek_env/bin/activate
|
||||
```
|
||||
|
||||
Start required services. This will start all services from the docker-compose.yml, including:
|
||||
- searxng
|
||||
- redis (required by searxng)
|
||||
- frontend
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh # MacOS
|
||||
start ./start_services.cmd # Window
|
||||
```
|
||||
|
||||
**Options 1:** Run with the CLI interface.
|
||||
|
||||
```sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
We advice you set `headless_browser` to False in the config.ini for CLI mode.
|
||||
|
||||
**Options 2:** Run with the Web interface.
|
||||
|
||||
Start the backend.
|
||||
|
||||
```sh
|
||||
python3 api.py
|
||||
```
|
||||
|
||||
Go to `http://localhost:3000/` and you should see the web interface.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Make sure the services are up and running with `./start_services.sh` and run the AgenticSeek with `python3 cli.py` for CLI mode or `python3 api.py` then go to `localhost:3000` for web interface.
|
||||
|
||||
You can also use speech to text by setting `listen = True` in the config. Only for CLI mode.
|
||||
|
||||
To exit, simply say/type `goodbye`.
|
||||
|
||||
Here are some example usage:
|
||||
|
||||
> *Make a snake game in python!*
|
||||
|
||||
> *Search the web for top cafes in Rennes, France, and save a list of three with their addresses in rennes_cafes.txt.*
|
||||
|
||||
> *Write a Go program to calculate the factorial of a number, save it as factorial.go in your workspace*
|
||||
|
||||
> *Search my summer_pictures folder for all JPG files, rename them with today’s date, and save a list of renamed files in photos_list.txt*
|
||||
|
||||
> *Search online for popular sci-fi movies from 2024 and pick three to watch tonight. Save the list in movie_night.txt.*
|
||||
|
||||
> *Search the web for the latest AI news articles from 2025, select three, and write a Python script to scrape their titles and summaries. Save the script as news_scraper.py and the summaries in ai_news.txt in /home/projects*
|
||||
|
||||
> *Friday, search the web for a free stock price API, register with supersuper7434567@gmail.com then write a Python script to fetch using the API daily prices for Tesla, and save the results in stock_prices.csv*
|
||||
|
||||
*Note that form filling capabilities are still experimental and might fail.*
|
||||
|
||||
|
||||
|
||||
After you type your query, AgenticSeek will allocate the best agent for the task.
|
||||
|
||||
Because this is an early prototype, the agent routing system might not always allocate the right agent based on your query.
|
||||
|
||||
Therefore, you should be very explicit in what you want and how the AI might proceed for example if you want it to conduct a web search, do not say:
|
||||
|
||||
`Do you know some good countries for solo-travel?`
|
||||
|
||||
Instead, ask:
|
||||
|
||||
`Do a web search and find out which are the best country for solo-travel`
|
||||
|
||||
---
|
||||
|
||||
## **Setup to run the LLM on your own server**
|
||||
|
||||
If you have a powerful computer or a server that you can use, but you want to use it from your laptop you have the options to run the LLM on a remote server using our custom llm server.
|
||||
|
||||
On your "server" that will run the AI model, get the ip address
|
||||
|
||||
```sh
|
||||
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1
|
||||
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # local ip
|
||||
curl https://ipinfo.io/ip # public ip
|
||||
```
|
||||
|
||||
Note: For Windows or macOS, use ipconfig or ifconfig respectively to find the IP address.
|
||||
|
||||
Clone the repository and then, run the script `stream_llm.py` in `server/`
|
||||
Clone the repository and enter the `server/`folder.
|
||||
|
||||
|
||||
```sh
|
||||
python3 server_ollama.py
|
||||
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek/server/
|
||||
```
|
||||
|
||||
### 2️⃣ **Run it**
|
||||
Install server specific requirements:
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
Run the server script.
|
||||
|
||||
```sh
|
||||
python3 app.py --provider ollama --port 3333
|
||||
```
|
||||
|
||||
You have the choice between using `ollama` and `llamacpp` as a LLM service.
|
||||
|
||||
|
||||
Now on your personal computer:
|
||||
|
||||
Clone the repository.
|
||||
|
||||
Change the `config.ini` file to set the `provider_name` to `server` and `provider_model` to `deepseek-r1:7b`.
|
||||
Change the `config.ini` file to set the `provider_name` to `server` and `provider_model` to `deepseek-r1:xxb`.
|
||||
Set the `provider_server_address` to the ip address of the machine that will run the model.
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = server
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = x.x.x.x:5000
|
||||
provider_model = deepseek-r1:70b
|
||||
provider_server_address = x.x.x.x:3333
|
||||
```
|
||||
|
||||
Run the assistant:
|
||||
|
||||
```sh
|
||||
./start_services.sh
|
||||
python3 main.py
|
||||
```
|
||||
|
||||
## **Run with an API**
|
||||
|
||||
Clone the repository.
|
||||
|
||||
Set the desired provider in the `config.ini`
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt4-o
|
||||
provider_server_address = 127.0.0.1:5000 # can be set to anything, not used
|
||||
```
|
||||
|
||||
Run the assistant:
|
||||
|
||||
```sh
|
||||
./start_services.sh
|
||||
python3 main.py
|
||||
```
|
||||
Next step: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
---
|
||||
|
||||
## Speech to Text
|
||||
|
||||
Please note that currently speech to text only work in english.
|
||||
|
||||
The speech-to-text functionality is disabled by default. To enable it, set the listen option to True in the config.ini file:
|
||||
|
||||
```
|
||||
listen = True
|
||||
```
|
||||
|
||||
When enabled, the speech-to-text feature listens for a trigger keyword, which is the agent's name, before it begins processing your input. You can customize the agent's name by updating the `agent_name` value in the *config.ini* file:
|
||||
|
||||
```
|
||||
agent_name = Friday
|
||||
```
|
||||
|
||||
For optimal recognition, we recommend using a common English name like "John" or "Emma" as the agent name
|
||||
|
||||
Once you see the transcript start to appear, say the agent's name aloud to wake it up (e.g., "Friday").
|
||||
|
||||
Speak your query clearly.
|
||||
|
||||
End your request with a confirmation phrase to signal the system to proceed. Examples of confirmation phrases include:
|
||||
```
|
||||
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
Example config:
|
||||
```
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:32b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Friday
|
||||
recover_last_session = False
|
||||
save_session = False
|
||||
speak = False
|
||||
listen = False
|
||||
work_dir = /Users/mlg/Documents/ai_folder
|
||||
jarvis_personality = False
|
||||
languages = en zh
|
||||
[BROWSER]
|
||||
headless_browser = False
|
||||
stealth_mode = False
|
||||
```
|
||||
|
||||
**Explanation**:
|
||||
|
||||
- is_local -> Runs the agent locally (True) or on a remote server (False).
|
||||
|
||||
- provider_name -> The provider to use (one of: `ollama`, `server`, `lm-studio`, `deepseek-api`)
|
||||
|
||||
- provider_model -> The model used, e.g., deepseek-r1:32b.
|
||||
|
||||
- provider_server_address -> Server address, e.g., 127.0.0.1:11434 for local. Set to anything for non-local API.
|
||||
|
||||
- agent_name -> Name of the agent, e.g., Friday. Used as a trigger word for TTS.
|
||||
|
||||
- recover_last_session -> Restarts from last session (True) or not (False).
|
||||
|
||||
- save_session -> Saves session data (True) or not (False).
|
||||
|
||||
- speak -> Enables voice output (True) or not (False).
|
||||
|
||||
- listen -> listen to voice input (True) or not (False).
|
||||
|
||||
- work_dir -> Folder the AI will have access to. eg: /Users/user/Documents/.
|
||||
|
||||
- jarvis_personality -> Uses a JARVIS-like personality (True) or not (False). This simply change the prompt file.
|
||||
|
||||
- languages -> The list of supported language, needed for the llm router to work properly, avoid putting too many or too similar languages.
|
||||
|
||||
- headless_browser -> Runs browser without a visible window (True) or not (False).
|
||||
|
||||
- stealth_mode -> Make bot detector time harder. Only downside is you have to manually install the anticaptcha extension.
|
||||
|
||||
- languages -> List of supported languages. Required for agent routing system. The longer the languages list the more model will be downloaded.
|
||||
|
||||
## Providers
|
||||
|
||||
The table below show the available providers:
|
||||
|
||||
| Provider | Local? | Description |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| Ollama | Yes | Run LLMs locally with ease using ollama as a LLM provider |
|
||||
| Server | Yes | Host the model on another machine, run your local machine |
|
||||
| OpenAI | No | Use ChatGPT API (non-private) |
|
||||
| Deepseek | No | Deepseek API (non-private) |
|
||||
| HuggingFace| No | Hugging-Face API (non-private) |
|
||||
|
||||
| ollama | Yes | Run LLMs locally with ease using ollama as a LLM provider |
|
||||
| server | Yes | Host the model on another machine, run your local machine |
|
||||
| lm-studio | Yes | Run LLM locally with LM studio (`lm-studio`) |
|
||||
| openai | Depends | Use ChatGPT API (non-private) or openai compatible API |
|
||||
| deepseek-api | No | Deepseek API (non-private) |
|
||||
| huggingface| No | Hugging-Face API (non-private) |
|
||||
| togetherAI | No | Use together AI API (non-private) |
|
||||
| google | No | Use google gemini API (non-private) |
|
||||
|
||||
To select a provider change the config.ini:
|
||||
|
||||
```
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:32b
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
`is_local`: should be True for any locally running LLM, otherwise False.
|
||||
|
||||
`provider_name`: Select the provider to use by its name, see the provider list above.
|
||||
`provider_name`: Select the provider to use by it's name, see the provider list above.
|
||||
|
||||
`provider_model`: Set the model to use by the agent.
|
||||
|
||||
`provider_server_address`: can be set to anything if you are not using the server provider.
|
||||
|
||||
# Known issues
|
||||
|
||||
## Chromedriver Issues
|
||||
|
||||
**Known error #1:** *chromedriver mismatch*
|
||||
|
||||
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
|
||||
Current browser version is 134.0.6998.89 with binary path`
|
||||
|
||||
This happen if there is a mismatch between your browser and chromedriver version.
|
||||
|
||||
You need to navigate to download the latest version:
|
||||
|
||||
https://developer.chrome.com/docs/chromedriver/downloads
|
||||
|
||||
If you're using Chrome version 115 or newer go to:
|
||||
|
||||
https://googlechromelabs.github.io/chrome-for-testing/
|
||||
|
||||
And download the chromedriver version matching your OS.
|
||||
|
||||

|
||||
|
||||
If this section is incomplete please raise an issue.
|
||||
|
||||
## connection adapters Issues
|
||||
|
||||
```
|
||||
Exception: Provider lm-studio failed: HTTP request failed: No connection adapters were found for '127.0.0.1:11434/v1/chat/completions'
|
||||
```
|
||||
|
||||
Make sure you have `http://` in front of the provider IP address :
|
||||
|
||||
`provider_server_address = http://127.0.0.1:11434`
|
||||
|
||||
## SearxNG base URL must be provided
|
||||
|
||||
```
|
||||
raise ValueError("SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.")
|
||||
ValueError: SearxNG base URL must be provided either as an argument or via the SEARXNG_BASE_URL environment variable.
|
||||
```
|
||||
|
||||
Maybe you didn't move `.env.example` as `.env` ? You can also export SEARXNG_BASE_URL:
|
||||
|
||||
`export SEARXNG_BASE_URL="http://127.0.0.1:8080"`
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: What hardware do I need?**
|
||||
|
||||
7B Model: GPU with 8GB VRAM.
|
||||
14B Model: 12GB GPU (e.g., RTX 3060).
|
||||
32B Model: 24GB+ VRAM.
|
||||
| Model Size | GPU | Comment |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| 7B | 8GB Vram | ⚠️ Not recommended. Performance is poor, frequent hallucinations, and planner agents will likely fail. |
|
||||
| 14B | 12 GB VRAM (e.g. RTX 3060) | ✅ Usable for simple tasks. May struggle with web browsing and planning tasks. |
|
||||
| 32B | 24+ GB VRAM (e.g. RTX 4090) | 🚀 Success with most tasks, might still struggle with task planning |
|
||||
| 70B+ | 48+ GB Vram (eg. mac studio) | 💪 Excellent. Recommended for advanced use cases. |
|
||||
|
||||
**Q: Why Deepseek R1 over other models?**
|
||||
|
||||
Deepseek R1 excels at reasoning and tool use for its size. We think it’s a solid fit for our needs other models work fine, but Deepseek is our primary pick.
|
||||
|
||||
**Q: I get an error running `main.py`. What do I do?**
|
||||
**Q: I get an error running `cli.py`. What do I do?**
|
||||
|
||||
Ensure Ollama is running (`ollama serve`), your `config.ini` matches your provider, and dependencies are installed. If none work feel free to raise an issue.
|
||||
|
||||
**Q: How to join the discord ?**
|
||||
|
||||
Ask in the Community section for an invite.
|
||||
Ensure local is running (`ollama serve`), your `config.ini` matches your provider, and dependencies are installed. If none work feel free to raise an issue.
|
||||
|
||||
**Q: Can it really run 100% locally?**
|
||||
|
||||
Yes with Ollama or Server providers, all speech to text, LLM and text to speech model run locally. Non-local options (OpenAI or others API) are optional.
|
||||
Yes with Ollama, lm-studio or server providers, all speech to text, LLM and text to speech model run locally. Non-local options (OpenAI or others API) are optional.
|
||||
|
||||
**Q: How come it is older than manus ?**
|
||||
**Q: Why should I use AgenticSeek when I have Manus?**
|
||||
|
||||
we started this a fun side project to make a fully local, Jarvis-like AI. However, with the rise of Manus, we saw the opportunity to redirected some tasks to make yet another alternative.
|
||||
|
||||
**Q: How is it better than manus ?**
|
||||
|
||||
It's not but we prioritizes local execution and privacy over cloud based approach. It’s a fun, accessible alternative!
|
||||
This started as Side-Project we did out of interest about AI agents. What’s special about it is that we want to use local model and avoid APIs.
|
||||
We draw inspiration from Jarvis and Friday (Iron man movies) to make it "cool" but for functionnality we take more inspiration from Manus, because that's what people want in the first place: a local manus alternative.
|
||||
Unlike Manus, AgenticSeek prioritizes independence from external systems, giving you more control, privacy and avoid api cost.
|
||||
|
||||
## Contribute
|
||||
|
||||
We’re looking for developers to improve AgenticSeek! Check out open issues or discussion.
|
||||
|
||||
## Authors:
|
||||
> [Fosowl](https://github.com/Fosowl)
|
||||
> [steveh8758](https://github.com/steveh8758)
|
||||
[Contribution guide](./docs/CONTRIBUTING.md)
|
||||
|
||||
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
|
||||
|
||||
## Maintainers:
|
||||
|
||||
> [Fosowl](https://github.com/Fosowl) | Paris Time | (Sometime busy)
|
||||
|
||||
> [https://github.com/antoineVIVIES](antoineVIVIES) | Taipei Time | (Often busy)
|
||||
|
||||
> [steveh8758](https://github.com/steveh8758) | Taipei Time | (Always busy)
|
||||
@@ -0,0 +1,567 @@
|
||||
# AgenticSeek: Private, Local Manus Alternative.
|
||||
|
||||
<p align="center">
|
||||
<img align="center" src="./media/whale_readme.jpg">
|
||||
<p>
|
||||
|
||||
[English](./README.md) | 中文 | [日本語](./README_JP.md)
|
||||
|
||||
*一个 **100% 本地替代 Manus AI** 的方案,这款支持语音的 AI 助理能够自主浏览网页、编写代码和规划任务,同时将所有数据保留在您的设备上。专为本地推理模型量身打造,完全在您自己的硬件上运行,确保完全的隐私保护和零云端依赖。*
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460)
|
||||
|
||||
### 为什么选择 AgenticSeek?
|
||||
|
||||
* 🔒 完全本地化与隐私保护 - 所有功能都在您的设备上运行 — 无云端服务,无数据共享。您的文件、对话和搜索始终保持私密。
|
||||
|
||||
* 🌐 智能网页浏览 - AgenticSeek 能够自主浏览互联网 — 搜索、阅读、提取信息、填写网页表单 — 全程无需人工操作。
|
||||
|
||||
* 💻 自主编码助手 - 需要代码?它可以编写、调试并运行 Python、C、Go、Java 等多种语言的程序 — 全程无需监督。
|
||||
|
||||
* 🧠 智能代理选择 - 您提问,它会自动选择最适合该任务的代理。就像拥有一个随时待命的专家团队。
|
||||
|
||||
* 📋 规划与执行复杂任务 - 从旅行规划到复杂项目 — 它能将大型任务分解为步骤,并利用多个 AI 代理完成工作。
|
||||
|
||||
* 🎙️ 语音功能 - 清晰、快速、未来感十足的语音与语音转文本功能,让您能像科幻电影中一样与您的个人 AI 助手对话。
|
||||
|
||||
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
||||
|
||||
> 🛠️ **目前还在开发阶段** – 欢迎任何贡献者加入我们!
|
||||
|
||||
---
|
||||
|
||||
## **安装**
|
||||
|
||||
确保已安装了 Chrome driver,Docker 和 Python 3.10(或更新)。
|
||||
|
||||
有关于 Chrome driver 的问题,请参见 **Chromedriver** 部分。
|
||||
|
||||
### 1️⃣ **复制储存库与设置环境变数**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
### 2️ **建立虚拟环境**
|
||||
|
||||
```sh
|
||||
python3 -m venv agentic_seek_env
|
||||
source agentic_seek_env/bin/activate
|
||||
# On Windows: agentic_seek_env\Scripts\activate
|
||||
```
|
||||
|
||||
### 3️⃣ **安装所需套件**
|
||||
|
||||
**自动安装:**
|
||||
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
** 若要让文本转语音(TTS)功能支持中文,你需要安装 jieba(中文分词库)和 cn2an(中文数字转换库):**
|
||||
|
||||
```
|
||||
pip3 install jieba cn2an
|
||||
```
|
||||
|
||||
**手动安装:**
|
||||
|
||||
|
||||
**注意:对于任何操作系统,请确保您安装的 ChromeDriver 与您已安装的 Chrome 版本匹配。运行 `google-chrome --version`。如果您的 Chrome 版本 > 135,请参阅已知问题**
|
||||
|
||||
- *Linux*:
|
||||
|
||||
更新软件包列表:`sudo apt update`
|
||||
|
||||
安装依赖项:`sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1`
|
||||
|
||||
安装与您的 Chrome 浏览器版本匹配的 ChromeDriver:
|
||||
`sudo apt install -y chromium-chromedriver`
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
- *Macos*:
|
||||
|
||||
更新 brew:`brew update`
|
||||
|
||||
安装 chromedriver:`brew install --cask chromedriver`
|
||||
|
||||
安装 portaudio:`brew install portaudio`
|
||||
|
||||
升级 pip:`python3 -m pip install --upgrade pip`
|
||||
|
||||
升级 wheel:`pip3 install --upgrade setuptools wheel`
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
- *Windows*:
|
||||
|
||||
安装 pyreadline3:`pip install pyreadline3`
|
||||
|
||||
手动安装 portaudio(例如,通过 vcpkg 或预编译的二进制文件),然后运行:`pip install pyaudio`
|
||||
|
||||
从以下网址手动下载并安装 chromedriver:https://sites.google.com/chromium.org/driver/getting-started
|
||||
|
||||
将 chromedriver 放置在包含在您的 PATH 中的目录中。
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
|
||||
|
||||
## 在本地机器上运行 AgenticSeek
|
||||
|
||||
**建议至少使用 Deepseek 14B 以上参数的模型,较小的模型难以使用助理功能并且很快就会忘记上下文之间的关系。**
|
||||
|
||||
**本地运行助手**
|
||||
|
||||
启动你的本地提供者,例如使用 ollama:
|
||||
|
||||
```sh
|
||||
ollama serve
|
||||
```
|
||||
|
||||
请参阅下方支持的本地提供者列表。
|
||||
|
||||
**更新 config.ini**
|
||||
|
||||
修改 config.ini 文件以设置 provider_name 为支持的提供者,并将 provider_model 设置为该提供者支持的 LLM。我们推荐使用具有推理能力的模型,如 *Qwen* 或 *Deepseek*。
|
||||
|
||||
请参见 README 末尾的 **FAQ** 部分了解所需硬件。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = True # 无论是在本地运行还是使用远程提供者。
|
||||
provider_name = ollama # 或 lm-studio, openai 等..
|
||||
provider_model = deepseek-r1:14b # 选择适合您硬件的模型
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Jarvis # 您的 AI 助手的名称
|
||||
recover_last_session = True # 是否恢复之前的会话
|
||||
save_session = True # 是否记住当前会话
|
||||
speak = True # 文本转语音
|
||||
listen = False # 语音转文本,仅适用于命令行界面
|
||||
work_dir = /Users/mlg/Documents/workspace # AgenticSeek 的工作空间。
|
||||
jarvis_personality = False # 是否使用更"贾维斯"风格的性格,不推荐在小型模型上使用
|
||||
languages = en zh # 语言列表,文本转语音将默认使用列表中的第一种语言
|
||||
[BROWSER]
|
||||
headless_browser = True # 是否使用无头浏览器,只有在使用网页界面时才推荐使用。
|
||||
stealth_mode = True # 使用无法检测的 selenium 来减少浏览器检测
|
||||
```
|
||||
|
||||
注意:某些提供者(如 lm-studio)需要在 IP 前面加上 `http://`。例如 `http://127.0.0.1:1234`
|
||||
|
||||
|
||||
|
||||
**本地提供者列表**
|
||||
|
||||
| 提供者 | 本地? | 描述 |
|
||||
|-------------|--------|-------------------------------------------------------|
|
||||
| ollama | 是 | 使用 ollama 作为 LLM 提供者,轻松本地运行 LLM |
|
||||
| lm-studio | 是 | 使用 LM Studio 本地运行 LLM(将 `provider_name` 设置为 `lm-studio`)|
|
||||
| openai | 否 | 使用兼容的 API |
|
||||
|
||||
下一步: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
---
|
||||
|
||||
## **Run with an API (透过 API 执行)**
|
||||
|
||||
设定 `config.ini`。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
|
||||
警告:确保 `config.ini` 没有行尾空格。
|
||||
|
||||
如果使用基于本机的 openai-based api 则把 `is_local` 设定为 `True`。
|
||||
|
||||
同时更改你的 IP 为 openai-based api 的 IP。
|
||||
|
||||
下一步: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
---
|
||||
|
||||
## Start services and Run
|
||||
(启动服务并运行)
|
||||
|
||||
如果需要,请激活你的 Python 环境。
|
||||
```sh
|
||||
source agentic_seek_env/bin/activate
|
||||
```
|
||||
|
||||
启动所需的服务。这将启动 `docker-compose.yml` 中的所有服务,包括:
|
||||
- searxng
|
||||
- redis(由 redis 提供支持)
|
||||
- 前端
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh # MacOS
|
||||
start ./start_services.cmd # Windows
|
||||
```
|
||||
|
||||
**选项 1:** 使用 CLI 界面运行。
|
||||
|
||||
```sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
**选项 2:** 使用 Web 界面运行。
|
||||
|
||||
注意:目前我們建議您使用 CLI 界面。Web 界面仍在積極開發中。
|
||||
|
||||
启动后端服务。
|
||||
|
||||
```sh
|
||||
python3 api.py
|
||||
```
|
||||
|
||||
访问 `http://localhost:3000/`,你应该会看到 Web 界面。
|
||||
|
||||
请注意,目前 Web 界面不支持消息流式传输。
|
||||
|
||||
|
||||
*如果你不知道如何开始,请参阅 **Usage** 部分*
|
||||
|
||||
---
|
||||
|
||||
## Usage (使用方法)
|
||||
|
||||
为确保 agenticSeek 在中文环境下正常工作,请确保在 config.ini 中设置语言选项。
|
||||
languages = en zh
|
||||
更多信息请参阅 Config 部分
|
||||
|
||||
确定所有的核心档案都启用了,也就是执行过这条命令 `./start_services.sh` 然后你就可以使用 `python3 cli.py` 来启动 AgenticSeek 了!
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
当你看到执行后显示 `>>> `
|
||||
这表示一切运作正常,AgenticSeek 正在等待你给他任何指令。
|
||||
你也可以透过设定 `config.ini` 内的 `listen = True` 来启用语音转文字。
|
||||
|
||||
要退出时,只要和他说 `goodbye` 就可以退出!
|
||||
|
||||
以下是一些用法:
|
||||
|
||||
### Coding/Bash
|
||||
|
||||
> *在 Golang 中帮助我进行矩阵乘法*
|
||||
|
||||
> *使用 nmap 扫描我的网路,找出是否有任何可疑装置连接*
|
||||
|
||||
> *用 Python 制作一个贪食蛇游戏*
|
||||
|
||||
### 网路搜寻
|
||||
|
||||
> *进行网路搜寻,找出日本从事尖端人工智慧研究的酷炫科技新创公司*
|
||||
|
||||
> *你能在网路上找到谁创造了 AgenticSeek 吗?*
|
||||
|
||||
> *你能在哪个网站上找到便宜的 RTX 4090 吗?*
|
||||
|
||||
### 档案浏览与搜寻
|
||||
|
||||
> *嘿,你能找到我遗失的 million_dollars_contract.pdf 在哪里吗?*
|
||||
|
||||
> *告诉我我的磁碟还剩下多少空间*
|
||||
|
||||
> *寻找并阅读 README.md,并按照安装说明进行操作*
|
||||
|
||||
### 日常聊天
|
||||
|
||||
> *告诉我关于法国的事*
|
||||
|
||||
> *人生的意义是什么?*
|
||||
|
||||
> *我应该在锻炼前还是锻炼后服用肌酸?*
|
||||
|
||||
|
||||
当你把指令送出后,AgenticSeek 会自动调用最能提供帮助的助理,去完成你交办的工作和指令。
|
||||
|
||||
但也有可能出现怪怪的情况,或是你要找飞机机票,他跑去教你如何一步步做出一台飞机(开玩笑的,但真的可能出现),因为这是一个早期专案,我们会努力教导他、完善他的!
|
||||
|
||||
所以我们希望你在使用时,能明确地表明你希望他要怎么做,下面给你一个范例!
|
||||
|
||||
你该说:
|
||||
- 进行网络搜索,找出哪些国家最适合独自旅行
|
||||
|
||||
|
||||
而不是说:
|
||||
- 你知道哪些国家适合独自旅行?
|
||||
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
## **在本地执行属于你的 LLM 伺服器**
|
||||
|
||||
如果你有一台功能强大的电脑或伺服器,但你想透过笔记型电脑使用它,那么你可以选择在远端伺服器上执行 LLM。
|
||||
|
||||
### 1️⃣ **设定并启动伺服器脚本**
|
||||
|
||||
在运行 AI 模型的「伺服器」上,取得 IP 位址
|
||||
|
||||
```sh
|
||||
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1
|
||||
```
|
||||
|
||||
注意:请在 Windows 或 MacOS,分别使用 `ipconfig` 与 `ifconfig` 来寻找 IP 位址。
|
||||
|
||||
**如果你希望使用基于 Openai 的服务,请按照 *透过 API 执行* 部分进行。**
|
||||
|
||||
复制储存库并且进入 `server/` 资料夹。
|
||||
|
||||
```sh
|
||||
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek/server/
|
||||
```
|
||||
|
||||
安装伺服器所需的套件:
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
执行伺服器脚本。
|
||||
|
||||
```sh
|
||||
python3 app.py --provider ollama --port 3333
|
||||
```
|
||||
|
||||
您可以选择使用 `ollama` 或 `llamacpp` 作为 LLM 的服务框架。
|
||||
|
||||
### 2️⃣ **执行**
|
||||
|
||||
在你的电脑上:
|
||||
|
||||
- 更改 `config.ini`
|
||||
- `provider_name = server`
|
||||
- `provider_model = deepseek-r1:14b`
|
||||
- `provider_server_address = {你执行模型的电脑的 IP 位址}`
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = server
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = x.x.x.x:3333
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 语音转文字
|
||||
|
||||
请注意,目前语音转文字功能仅支持英语。
|
||||
|
||||
预设状况下,语音转文字功能是停用的。若要启用它,请在 `config.ini` 档案中,将 `listen` 选项设为 `True`:
|
||||
|
||||
```
|
||||
listen = True
|
||||
```
|
||||
|
||||
启用后 AgenticSeek 会聆听你是否呼唤他,他才会开始听你说的话,你可以在 *config.ini* 内去设定,要怎么叫他。
|
||||
|
||||
```
|
||||
agent_name = Friday
|
||||
```
|
||||
|
||||
为了获得比较好的结果,我们建议使用常见的英文名称(如 “John” 或 “Emma”)作为他的名字。
|
||||
|
||||
当你看到程式开始执行时,请大声说出他的名字,就可以唤醒 AgenticSeek 去聆听!(如:Friday)
|
||||
|
||||
清楚说出你的需求。
|
||||
|
||||
用确认短句结束你说的话,以通知 AgenticSeek 继续。确认短句的范例包括:
|
||||
```
|
||||
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
Config 范例:
|
||||
```
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:1.5b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Friday
|
||||
recover_last_session = False
|
||||
save_session = False
|
||||
speak = False
|
||||
listen = False
|
||||
work_dir = /Users/mlg/Documents/ai_folder
|
||||
jarvis_personality = False
|
||||
languages = en zh
|
||||
[BROWSER]
|
||||
headless_browser = False
|
||||
stealth_mode = False
|
||||
```
|
||||
|
||||
**说明**:
|
||||
- is_local
|
||||
- True:在本地运行。
|
||||
- False:在远端伺服器运行。
|
||||
- provider_name
|
||||
- 框架类型
|
||||
- `ollama`, `server`, `lm-studio`, `deepseek-api`
|
||||
- provider_model
|
||||
- 运行的模型
|
||||
- `deepseek-r1:1.5b`, `deepseek-r1:14b`
|
||||
- provider_server_address
|
||||
- 伺服器 IP
|
||||
- `127.0.0.1:11434`
|
||||
- agent_name
|
||||
- AgenticSeek 的名字,用作TTS的触发单词。
|
||||
- `Friday`
|
||||
- recover_last_session
|
||||
- True:从上个对话继续。
|
||||
- False:重启对话。
|
||||
- save_session
|
||||
- True:储存对话纪录。
|
||||
- False:不保存。
|
||||
- speak
|
||||
- True:启用语音输出。
|
||||
- False:关闭语音输出。
|
||||
- listen
|
||||
- True:启用语音输入。
|
||||
- False:关闭语音输入。
|
||||
- work_dir
|
||||
- AgenticSeek 拥有能存取与交互的工作目录。
|
||||
- jarvis_personality
|
||||
> 就是那个钢铁人的 JARVIS
|
||||
- True:启用 JARVIS 个性。
|
||||
- False:关闭 JARVIS 个性。
|
||||
- headless_browser
|
||||
- True:前景浏览器。(很酷,推荐使用他 XD)
|
||||
- False:背景执行浏览器。
|
||||
- stealth_mode
|
||||
- 隐私模式,但需要你自己安装反爬虫扩充功能。
|
||||
- languages
|
||||
- 支持的语言列表。用于代理路由系统。语言列表越长,下载的模型越多。
|
||||
|
||||
## 框架
|
||||
|
||||
下表显示了可用的框架:
|
||||
|
||||
| 框架 | 本地? | 描述|
|
||||
|-|-|-|
|
||||
| ollama | 可 | 使用 ollama 框架去执行本地模型 |
|
||||
| server | 可 | 本地伺服器执行模型远端调用 |
|
||||
| lm-studio | 可 | 使用 LM Studio 在本地运行 LLM(设定provider_name为lm-studio)|
|
||||
| openai | 不可 | 使用 ChatGPT API(无法保证隐私)|
|
||||
| deepseek-api | 不可 | 使用 Deepseek API (无法保证隐私)|
|
||||
| huggingface | 不可 | 使用 Hugging-Face API (无法保证隐私)|
|
||||
|
||||
若要选择框架,请变更 `config.ini` 文件:
|
||||
|
||||
```
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
`is_local`: 对于任何本地运行的 LLM 都应该为 True,否则为 False。
|
||||
|
||||
`provider_name`: 透过名称选择要使用的框架,请参阅上面的框架清单。
|
||||
|
||||
`provider_model`: 设定 AgenticSeek 使用的模型。
|
||||
|
||||
`provider_server_address`: 如果不使用云端 API,则可以将其设定为任何内容。
|
||||
|
||||
# Known issues (已知问题)
|
||||
|
||||
## Chromedriver Issues
|
||||
|
||||
**已知问题 #1:** *chromedriver mismatch*
|
||||
|
||||
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
|
||||
Current browser version is 134.0.6998.89 with binary path`
|
||||
|
||||
如果你的浏览器和 chromedriver 版本不一样,就会发生这种情况。
|
||||
|
||||
你可以透过以下连结下载最新版本:
|
||||
|
||||
https://developer.chrome.com/docs/chromedriver/downloads
|
||||
|
||||
如果您使用的是 Chrome 版本 115 或更新版本,请前往:
|
||||
|
||||
https://googlechromelabs.github.io/chrome-for-testing/
|
||||
|
||||
下载与你的作业系统相符的 chromedriver 版本。
|
||||
|
||||

|
||||
|
||||
如果有其他问题,请提供尽量详细的叙述到 Issues 上,尽可能包含当前环境和问题是怎么发生的。
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: 我需要什麼硬體?**
|
||||
|
||||
| 模型大小 | GPU | 備註 |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| 7B | 8GB Vram | ⚠️ 不推薦。性能較差,經常出現幻覺,規劃代理可能會失敗。 |
|
||||
| 14B | 12 GB VRAM (例如 RTX 3060) | ✅ 適用於簡單任務。可能在網頁瀏覽和規劃任務上表現不佳。 |
|
||||
| 32B | 24+ GB VRAM (例如 RTX 4090) | 🚀 大多數任務成功,但可能仍在任務規劃上有困難。 |
|
||||
| 70B+ | 48+ GB Vram (例如 mac studio) | 💪 表現優異。建議用於高級使用情境。 |
|
||||
|
||||
**Q:为什么选择 Deepseek R1 而不是其他模型?**
|
||||
|
||||
就其尺寸而言,Deepseek R1 在推理和使用方面表现出色。我们认为非常适合我们的需求,其他模型也很好用,但 Deepseek 是我们最后选定的模型。
|
||||
|
||||
**Q:我在执行时 `cli.py` 时出现错误。我该怎么办?**
|
||||
|
||||
1. 确保 Ollama 正在运行(ollama serve)
|
||||
2. 你 `config.ini` 内 `provider_name` 的框架选择正确。
|
||||
3. 依赖套件已安装
|
||||
4. 如果均无效,请随时提出 Issues,同样尽可能包含当前环境和问题是怎么发生的。
|
||||
|
||||
**Q:它真的是 100% 本地运行吗?**
|
||||
|
||||
是的,透过 Ollama 或其他框架,所有语音转文字、LLM 和文字转语音模型都在本地运行。
|
||||
*但你能选择非本地执行(OpenAI 或其他 API),同样也是可以的*
|
||||
|
||||
|
||||
**Q:我有 Manus 为甚么还要用 AgenticSeek?**
|
||||
|
||||
这是我们因为兴趣做的一个小 Side-Project,他特别的点在于是一个全部本地化的模型,而且可以像钢铁人里面一样与 `Jarvis` 对话,听起来就超级酷的吧!随着 Manus 的进化,我们也相应的加入更多功能!
|
||||
|
||||
**Q:它比 Manus 好在哪里?**
|
||||
|
||||
不不不,AgenticSeek 和 Manus 是不同取向的东西,我们优先考虑的是本地执行和隐私,而不是基于云端。这是一个与 Manus 相比起来更有趣且易使用的方案!
|
||||
|
||||
**Q: 是否支持中文以外的语言?**
|
||||
|
||||
DeepSeek R1 天生会说中文
|
||||
|
||||
但注意:代理路由系统只懂英文,所以必须通过 config.ini 的 languages 参数(如 languages = en zh)告诉系统:
|
||||
|
||||
如果不设置中文?后果可能是:你让它写代码,结果跳出来个"医生代理"(虽然我们根本没有这个代理... 但系统会一脸懵圈!)
|
||||
|
||||
实际上会下载一个小型翻译模型来协助任务分配
|
||||
|
||||
## 贡献
|
||||
|
||||
我们正在寻找开发者来改善 AgenticSeek!你可以在 Issues 查看未解决的问题或和我们讨论更酷的新功能!
|
||||
|
||||
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
|
||||
|
||||
[Contribution guide](./docs/CONTRIBUTING.md)
|
||||
|
||||
## 维护者:
|
||||
|
||||
> [Fosowl](https://github.com/Fosowl) | 巴黎时间 | (有时很忙)
|
||||
|
||||
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北时间 | (经常很忙)
|
||||
|
||||
> [steveh8758](https://github.com/steveh8758) | 台北时间 | (总是很忙)
|
||||
@@ -0,0 +1,550 @@
|
||||
# AgenticSeek: 類似 Manus 但基於 Deepseek R1 Agents 的本地模型。
|
||||
|
||||
<p align="center">
|
||||
<img align="center" src="./media/whale_readme.jpg">
|
||||
<p>
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
[English](./README.md) | 繁體中文 | [日本語](./README_JP.md)
|
||||
|
||||
|
||||
*一个 **100% 本地替代 Manus AI** 的方案,这款支持语音的 AI 助理能够自主浏览网页、编写代码和规划任务,同时将所有数据保留在您的设备上。专为本地推理模型量身打造,完全在您自己的硬件上运行,确保完全的隐私保护和零云端依赖。*
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460)
|
||||
|
||||
### 为什么选择 AgenticSeek?
|
||||
|
||||
* 🔒 完全本地化与隐私保护 - 所有功能都在您的设备上运行 — 无云端服务,无数据共享。您的文件、对话和搜索始终保持私密。
|
||||
|
||||
* 🌐 智能网页浏览 - AgenticSeek 能够自主浏览互联网 — 搜索、阅读、提取信息、填写网页表单 — 全程无需人工操作。
|
||||
|
||||
* 💻 自主编码助手 - 需要代码?它可以编写、调试并运行 Python、C、Go、Java 等多种语言的程序 — 全程无需监督。
|
||||
|
||||
* 🧠 智能代理选择 - 您提问,它会自动选择最适合该任务的代理。就像拥有一个随时待命的专家团队。
|
||||
|
||||
* 📋 规划与执行复杂任务 - 从旅行规划到复杂项目 — 它能将大型任务分解为步骤,并利用多个 AI 代理完成工作。
|
||||
|
||||
* 🎙️ 语音功能 - 清晰、快速、未来感十足的语音与语音转文本功能,让您能像科幻电影中一样与您的个人 AI 助手对话。
|
||||
|
||||
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
||||
|
||||
> 🛠️ **目前還在開發階段** – 歡迎任何貢獻者加入我們!
|
||||
|
||||
---
|
||||
|
||||
## **安裝**
|
||||
|
||||
確保已安裝了 Chrome driver,Docker 和 Python 3.10(或更新)。
|
||||
|
||||
有關於 Chrome driver 的問題,請參見 **Chromedriver** 部分。
|
||||
|
||||
### 1️⃣ **複製儲存庫與設置環境變數**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
### 2️ **建立虛擬環境**
|
||||
|
||||
```sh
|
||||
python3 -m venv agentic_seek_env
|
||||
source agentic_seek_env/bin/activate
|
||||
# On Windows: agentic_seek_env\Scripts\activate
|
||||
```
|
||||
|
||||
### 3️⃣ **安裝所需套件**
|
||||
|
||||
**自動安裝:**
|
||||
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
** 若要让文本转语音(TTS)功能支持中文,你需要安装 jieba(中文分词库)和 cn2an(中文数字转换库):**
|
||||
|
||||
```
|
||||
pip3 install jieba cn2an
|
||||
```
|
||||
|
||||
**手動安裝:**
|
||||
|
||||
|
||||
**注意:对于任何操作系统,请确保您安装的 ChromeDriver 与您已安装的 Chrome 版本匹配。运行 `google-chrome --version`。如果您的 Chrome 版本 > 135,请参阅已知问题**
|
||||
|
||||
- *Linux*:
|
||||
|
||||
更新软件包列表:`sudo apt update`
|
||||
|
||||
安装依赖项:`sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1`
|
||||
|
||||
安装与您的 Chrome 浏览器版本匹配的 ChromeDriver:
|
||||
`sudo apt install -y chromium-chromedriver`
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
- *Macos*:
|
||||
|
||||
更新 brew:`brew update`
|
||||
|
||||
安装 chromedriver:`brew install --cask chromedriver`
|
||||
|
||||
安装 portaudio:`brew install portaudio`
|
||||
|
||||
升级 pip:`python3 -m pip install --upgrade pip`
|
||||
|
||||
升级 wheel:`pip3 install --upgrade setuptools wheel`
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
- *Windows*:
|
||||
|
||||
安装 pyreadline3:`pip install pyreadline3`
|
||||
|
||||
手动安装 portaudio(例如,通过 vcpkg 或预编译的二进制文件),然后运行:`pip install pyaudio`
|
||||
|
||||
从以下网址手动下载并安装 chromedriver:https://sites.google.com/chromium.org/driver/getting-started
|
||||
|
||||
将 chromedriver 放置在包含在您的 PATH 中的目录中。
|
||||
|
||||
安装 requirements:`pip3 install -r requirements.txt`
|
||||
|
||||
## 在本地機器上運行 AgenticSeek
|
||||
|
||||
**建議至少使用 Deepseek 14B 以上參數的模型,較小的模型難以使用助理功能並且很快就會忘記上下文之間的關係。**
|
||||
|
||||
**本地运行助手**
|
||||
|
||||
启动你的本地提供者,例如使用 ollama:
|
||||
|
||||
```sh
|
||||
ollama serve
|
||||
```
|
||||
|
||||
请参阅下方支持的本地提供者列表。
|
||||
|
||||
修改 `config.ini` 文件,将 `provider_name` 设置为支持的提供者,并将 `provider_model` 设置为 `deepseek-r1:14b`。
|
||||
|
||||
注意:`deepseek-r1:14b` 只是一个示例,如果你的硬件允许,可以使用更大的模型。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama # 或 lm-studio, openai 等
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
```
|
||||
|
||||
**本地提供者列表**
|
||||
|
||||
| 提供者 | 本地? | 描述 |
|
||||
|-------------|--------|-------------------------------------------------------|
|
||||
| ollama | 是 | 使用 ollama 作为 LLM 提供者,轻松本地运行 LLM |
|
||||
| lm-studio | 是 | 使用 LM Studio 本地运行 LLM(将 `provider_name` 设置为 `lm-studio`)|
|
||||
| openai | 否 | 使用兼容的 API |
|
||||
|
||||
下一步: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
---
|
||||
|
||||
## **Run with an API (透過 API 執行)**
|
||||
|
||||
設定 `config.ini`。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
|
||||
警告:確保 `config.ini` 沒有行尾空格。
|
||||
|
||||
如果使用基於本機的 openai-based api 則把 `is_local` 設定為 `True`。
|
||||
|
||||
同時更改你的 IP 為 openai-based api 的 IP。
|
||||
|
||||
下一步: [Start services and run AgenticSeek](#Start-services-and-Run)
|
||||
|
||||
---
|
||||
|
||||
## Start services and Run
|
||||
(启动服务并运行)
|
||||
|
||||
如果需要,请激活你的 Python 环境。
|
||||
```sh
|
||||
source agentic_seek_env/bin/activate
|
||||
```
|
||||
|
||||
启动所需的服务。这将启动 `docker-compose.yml` 中的所有服务,包括:
|
||||
- searxng
|
||||
- redis(由 redis 提供支持)
|
||||
- 前端
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh # MacOS
|
||||
start ./start_services.cmd # Windows
|
||||
```
|
||||
|
||||
**选项 1:** 使用 CLI 界面运行。
|
||||
|
||||
```sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
**选项 2:** 使用 Web 界面运行。
|
||||
|
||||
注意:目前我們建議您使用 CLI 界面。Web 界面仍在積極開發中。
|
||||
|
||||
启动后端服务。
|
||||
|
||||
```sh
|
||||
python3 api.py
|
||||
```
|
||||
|
||||
访问 `http://localhost:3000/`,你应该会看到 Web 界面。
|
||||
|
||||
请注意,目前 Web 界面不支持消息流式传输。
|
||||
|
||||
|
||||
*如果你不知道如何開始,請參閱 **Usage** 部分*
|
||||
|
||||
---
|
||||
|
||||
## Usage (使用方法)
|
||||
|
||||
为确保 agenticSeek 在中文环境下正常工作,请确保在 config.ini 中设置语言选项。
|
||||
languages = en zh
|
||||
更多信息请参阅 Config 部分
|
||||
|
||||
確定所有的核心檔案都啟用了,也就是執行過這條命令 `./start_services.sh` 然後你就可以使用 `python3 cli.py` 來啟動 AgenticSeek 了!
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
當你看到執行後顯示 `>>> `
|
||||
這表示一切運作正常,AgenticSeek 正在等待你給他任何指令。
|
||||
你也可以透過設定 `config.ini` 內的 `listen = True` 來啟用語音轉文字。
|
||||
|
||||
要退出時,只要和他說 `goodbye` 就可以退出!
|
||||
|
||||
以下是一些用法:
|
||||
|
||||
### Coding/Bash
|
||||
|
||||
> *在 Golang 中幫助我進行矩陣乘法*
|
||||
|
||||
> *使用 nmap 掃描我的網路,找出是否有任何可疑裝置連接*
|
||||
|
||||
> *用 Python 製作一個貪食蛇遊戲*
|
||||
|
||||
### 網路搜尋
|
||||
|
||||
> *進行網路搜尋,找出日本從事尖端人工智慧研究的酷炫科技新創公司*
|
||||
|
||||
> *你能在網路上找到誰創造了 AgenticSeek 嗎?*
|
||||
|
||||
> *你能在哪個網站上找到便宜的 RTX 4090 嗎?*
|
||||
|
||||
### 檔案瀏覽與搜尋
|
||||
|
||||
> *嘿,你能找到我遺失的 million_dollars_contract.pdf 在哪裡嗎?*
|
||||
|
||||
> *告訴我我的磁碟還剩下多少空間*
|
||||
|
||||
> *尋找並閱讀 README.md,並按照安裝說明進行操作*
|
||||
|
||||
### 日常聊天
|
||||
|
||||
> *告訴我關於法國的事*
|
||||
|
||||
> *人生的意義是什麼?*
|
||||
|
||||
> *我應該在鍛鍊前還是鍛鍊後服用肌酸?*
|
||||
|
||||
|
||||
當你把指令送出後,AgenticSeek 會自動調用最能提供幫助的助理,去完成你交辦的工作和指令。
|
||||
|
||||
但也有可能出現怪怪的情況,或是你要找飛機機票,他跑去教你如何一步步做出一台飛機(開玩笑的,但真的可能出現),因為這是一個早期專案,我們會努力教導他、完善他的!
|
||||
|
||||
所以我們希望你在使用時,能明確地表明你希望他要怎麼做,下面給你一個範例!
|
||||
|
||||
你該說:
|
||||
- 进行网络搜索,找出哪些国家最适合独自旅行
|
||||
|
||||
|
||||
而不是說:
|
||||
- 你知道哪些国家适合独自旅行?
|
||||
|
||||
---
|
||||
|
||||
|
||||
---
|
||||
|
||||
## **在本地執行屬於你的 LLM 伺服器**
|
||||
|
||||
如果你有一台功能強大的電腦或伺服器,但你想透過筆記型電腦使用它,那麼你可以選擇在遠端伺服器上執行 LLM。
|
||||
|
||||
### 1️⃣ **設定並啟動伺服器腳本**
|
||||
|
||||
在運行 AI 模型的「伺服器」上,取得 IP 位址
|
||||
|
||||
```sh
|
||||
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1
|
||||
```
|
||||
|
||||
注意:請在 Windows 或 MacOS,分別使用 `ipconfig` 與 `ifconfig` 來尋找 IP 位址。
|
||||
|
||||
**如果你希望使用基於 Openai 的服務,請按照 *透過 API 執行* 部分進行。**
|
||||
|
||||
複製儲存庫並且進入 `server/` 資料夾。
|
||||
|
||||
```sh
|
||||
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek/server/
|
||||
```
|
||||
|
||||
安裝伺服器所需的套件:
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
執行伺服器腳本。
|
||||
|
||||
```sh
|
||||
python3 app.py --provider ollama --port 3333
|
||||
```
|
||||
|
||||
您可以選擇使用 `ollama` 或 `llamacpp` 作為 LLM 的服務框架。
|
||||
|
||||
### 2️⃣ **執行**
|
||||
|
||||
在你的電腦上:
|
||||
|
||||
- 更改 `config.ini`
|
||||
- `provider_name = server`
|
||||
- `provider_model = deepseek-r1:14b`
|
||||
- `provider_server_address = {你執行模型的電腦的 IP 位址}`
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = server
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = x.x.x.x:3333
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 語音轉文字
|
||||
|
||||
请注意,目前语音转文字功能仅支持英语。
|
||||
|
||||
預設狀況下,語音轉文字功能是停用的。若要啟用它,請在 `config.ini` 檔案中,將 `listen` 選項設為 `True`:
|
||||
|
||||
```
|
||||
listen = True
|
||||
```
|
||||
|
||||
啟用後 AgenticSeek 會聆聽你是否呼喚他,他才會開始聽你說的話,你可以在 *config.ini* 內去設定,要怎麼叫他。
|
||||
|
||||
```
|
||||
agent_name = Friday
|
||||
```
|
||||
|
||||
為了獲得比較好的結果,我們建議使用常見的英文名稱(如 “John” 或 “Emma”)作為他的名字。
|
||||
|
||||
當你看到程式開始執行時,請大聲說出他的名字,就可以喚醒 AgenticSeek 去聆聽!(如:Friday)
|
||||
|
||||
清楚說出你的需求。
|
||||
|
||||
用確認短句結束你說的話,以通知 AgenticSeek 繼續。確認短句的範例包括:
|
||||
```
|
||||
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
Config 範例:
|
||||
```
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:1.5b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Friday
|
||||
recover_last_session = False
|
||||
save_session = False
|
||||
speak = False
|
||||
listen = False
|
||||
work_dir = /Users/mlg/Documents/ai_folder
|
||||
jarvis_personality = False
|
||||
languages = en zh
|
||||
[BROWSER]
|
||||
headless_browser = False
|
||||
stealth_mode = False
|
||||
```
|
||||
|
||||
**說明**:
|
||||
- is_local
|
||||
- True:在本地運行。
|
||||
- False:在遠端伺服器運行。
|
||||
- provider_name
|
||||
- 框架類型
|
||||
- `ollama`, `server`, `lm-studio`, `deepseek-api`
|
||||
- provider_model
|
||||
- 運行的模型
|
||||
- `deepseek-r1:1.5b`, `deepseek-r1:14b`
|
||||
- provider_server_address
|
||||
- 伺服器 IP
|
||||
- `127.0.0.1:11434`
|
||||
- agent_name
|
||||
- AgenticSeek 的名字,用作TTS的觸發單詞。
|
||||
- `Friday`
|
||||
- recover_last_session
|
||||
- True:從上個對話繼續。
|
||||
- False:重啟對話。
|
||||
- save_session
|
||||
- True:儲存對話紀錄。
|
||||
- False:不保存。
|
||||
- speak
|
||||
- True:啟用語音輸出。
|
||||
- False:關閉語音輸出。
|
||||
- listen
|
||||
- True:啟用語音輸入。
|
||||
- False:關閉語音輸入。
|
||||
- work_dir
|
||||
- AgenticSeek 擁有能存取與交互的工作目錄。
|
||||
- jarvis_personality
|
||||
> 就是那個鋼鐵人的 JARVIS
|
||||
- True:啟用 JARVIS 個性。
|
||||
- False:關閉 JARVIS 個性。
|
||||
- headless_browser
|
||||
- True:前景瀏覽器。(很酷,推薦使用他 XD)
|
||||
- False:背景執行瀏覽器。
|
||||
- stealth_mode
|
||||
- 隱私模式,但需要你自己安裝反爬蟲擴充功能。
|
||||
- languages
|
||||
- 支持的语言列表。用于代理路由系统。语言列表越长,下载的模型越多。
|
||||
|
||||
## 框架
|
||||
|
||||
下表顯示了可用的框架:
|
||||
|
||||
| 框架 | 本地? | 描述|
|
||||
|-|-|-|
|
||||
| ollama | 可 | 使用 ollama 框架去執行本地模型 |
|
||||
| server | 可 | 本地伺服器執行模型遠端調用 |
|
||||
| lm-studio | 可 | 使用 LM Studio 在本地運行 LLM(設定provider_name為lm-studio)|
|
||||
| openai | 不可 | 使用 ChatGPT API(無法保證隱私)|
|
||||
| deepseek-api | 不可 | 使用 Deepseek API (無法保證隱私)|
|
||||
| huggingface | 不可 | 使用 Hugging-Face API (無法保證隱私)|
|
||||
|
||||
若要選擇框架,請變更 `config.ini` 文件:
|
||||
|
||||
```
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
`is_local`: 對於任何本地運行的 LLM 都應該為 True,否則為 False。
|
||||
|
||||
`provider_name`: 透過名稱選擇要使用的框架,請參閱上面的框架清單。
|
||||
|
||||
`provider_model`: 設定 AgenticSeek 使用的模型。
|
||||
|
||||
`provider_server_address`: 如果不使用雲端 API,則可以將其設定為任何內容。
|
||||
|
||||
# Known issues (已知問題)
|
||||
|
||||
## Chromedriver Issues
|
||||
|
||||
**已知問題 #1:** *chromedriver mismatch*
|
||||
|
||||
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
|
||||
Current browser version is 134.0.6998.89 with binary path`
|
||||
|
||||
如果你的瀏覽器和 chromedriver 版本不一樣,就會發生這種情況。
|
||||
|
||||
你可以透過以下連結下載最新版本:
|
||||
|
||||
https://developer.chrome.com/docs/chromedriver/downloads
|
||||
|
||||
如果您使用的是 Chrome 版本 115 或更新版本,請前往:
|
||||
|
||||
https://googlechromelabs.github.io/chrome-for-testing/
|
||||
|
||||
下載與你的作業系統相符的 chromedriver 版本。
|
||||
|
||||

|
||||
|
||||
如果有其他問題,請提供盡量詳細的敘述到 Issues 上,盡可能包含當前環境和問題是怎麼發生的。
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: 我需要什麼硬體?**
|
||||
|
||||
| 模型大小 | GPU | 備註 |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| 7B | 8GB Vram | ⚠️ 不推薦。性能較差,經常出現幻覺,規劃代理可能會失敗。 |
|
||||
| 14B | 12 GB VRAM (例如 RTX 3060) | ✅ 適用於簡單任務。可能在網頁瀏覽和規劃任務上表現不佳。 |
|
||||
| 32B | 24+ GB VRAM (例如 RTX 4090) | 🚀 大多數任務成功,但可能仍在任務規劃上有困難。 |
|
||||
| 70B+ | 48+ GB Vram (例如 mac studio) | 💪 表現優異。建議用於高級使用情境。 |
|
||||
|
||||
**Q:為什麼選擇 Deepseek R1 而不是其他模型?**
|
||||
|
||||
就其尺寸而言,Deepseek R1 在推理和使用方面表現出色。我們認為非常適合我們的需求,其他模型也很好用,但 Deepseek 是我們最後選定的模型。
|
||||
|
||||
**Q:我在執行時 `cli.py` 時出現錯誤。我該怎麼辦?**
|
||||
|
||||
1. 確保 Ollama 正在運行(ollama serve)
|
||||
2. 你 `config.ini` 內 `provider_name` 的框架選擇正確。
|
||||
3. 依賴套件已安裝
|
||||
4. 如果均無效,請隨時提出 Issues,同樣盡可能包含當前環境和問題是怎麼發生的。
|
||||
|
||||
**Q:它真的是 100% 本地運行嗎?**
|
||||
|
||||
是的,透過 Ollama 或其他框架,所有語音轉文字、LLM 和文字轉語音模型都在本地運行。
|
||||
*但你能選擇非本地執行(OpenAI 或其他 API),同樣也是可以的*
|
||||
|
||||
|
||||
**Q:我有 Manus 為甚麼還要用 AgenticSeek?**
|
||||
|
||||
這是我們因為興趣做的一個小 Side-Project,他特別的點在於是一個全部本地化的模型,而且可以像鋼鐵人裡面一樣與 `Jarvis` 對話,聽起來就超級酷的吧!隨著 Manus 的進化,我們也相應的加入更多功能!
|
||||
|
||||
**Q:它比 Manus 好在哪裡?**
|
||||
|
||||
不不不,AgenticSeek 和 Manus 是不同取向的東西,我們優先考慮的是本地執行和隱私,而不是基於雲端。這是一個與 Manus 相比起來更有趣且易使用的方案!
|
||||
|
||||
**Q: 是否支持中文以外的语言?**
|
||||
|
||||
DeepSeek R1 天生会说中文
|
||||
|
||||
但注意:代理路由系统只懂英文,所以必须通过 config.ini 的 languages 参数(如 languages = en zh)告诉系统:
|
||||
|
||||
如果不设置中文?后果可能是:你让它写代码,结果跳出来个"医生代理"(虽然我们根本没有这个代理... 但系统会一脸懵圈!)
|
||||
|
||||
实际上会下载一个小型翻译模型来协助任务分配
|
||||
|
||||
## 貢獻
|
||||
|
||||
我們正在尋找開發者來改善 AgenticSeek!你可以在 Issues 查看未解決的問題或和我們討論更酷的新功能!
|
||||
|
||||
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
|
||||
|
||||
[Contribution guide](./docs/CONTRIBUTING.md)
|
||||
|
||||
## 维护者:
|
||||
|
||||
> [Fosowl](https://github.com/Fosowl) | 巴黎时间 | (有时很忙)
|
||||
|
||||
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES) | 台北时间 | (经常很忙)
|
||||
|
||||
> [steveh8758](https://github.com/steveh8758) | 台北时间 | (总是很忙)
|
||||
@@ -0,0 +1,497 @@
|
||||
<p align="center">
|
||||
<img align="center" src="./media/whale_readme.jpg">
|
||||
<p>
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
[English](./README.md) | [繁體中文](./README_CHT.md) | [日本語](./README_JP.md) | Français
|
||||
|
||||
# AgenticSeek: Une IA comme Manus mais à base d'agents DeepSeek R1 fonctionnant en local.
|
||||
|
||||
Une alternative **entièrement locale** à Manus AI, un assistant IA qui code, explore votre système de fichiers, navigue sur le web et corrige ses erreurs, tout cela sans envoyer la moindre donnée dans le cloud. Cet agent autonome fonctionne entièrement sur votre hardware, garantissant la confidentialité de vos données.
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460)
|
||||
|
||||
> 🛠️ **En cours de développement** – On cherche activement des contributeurs!
|
||||
|
||||
https://github.com/user-attachments/assets/4bd5faf6-459f-4f94-bd1d-238c4b331469
|
||||
|
||||
> *Recherche sur le web des activités à faire à Paris*
|
||||
|
||||
> *Code le jeu snake en python*
|
||||
|
||||
> *J'aimerais que tu trouve une api météo et que tu me code une application qui affiche la météo à Toulouse*
|
||||
|
||||
|
||||
|
||||
|
||||
## Fonctionnalités:
|
||||
|
||||
- **100% Local**: Fonctionne en local sur votre PC. Vos données restent les vôtres.
|
||||
|
||||
- **Accès à vos Fichiers**: Utilise bash pour naviguer et manipuler vos fichiers.
|
||||
|
||||
- **Codage semi-autonome**: Peut écrire, déboguer et exécuter du code en Python, C, Golang et d'autres langages à venir.
|
||||
|
||||
- **Routage d'Agent**: Sélectionne automatiquement l’agent approprié pour la tâche.
|
||||
|
||||
- **Planification**: Pour les taches complexe utilise plusieurs agents.
|
||||
|
||||
- **Navigation Web Autonome**: Navigation web autonome.
|
||||
|
||||
- **Memoire efficace**: Gestion efficace de la mémoire et des sessions.
|
||||
|
||||
---
|
||||
|
||||
## **Installation**
|
||||
|
||||
Assurez-vous d’avoir installé le pilote Chrome, Docker et Python 3.10 (ou une version plus récente).
|
||||
|
||||
Pour les problèmes liés au pilote Chrome, consultez la section Chromedriver.
|
||||
|
||||
### 1️⃣ Cloner le repo et configurer
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
### 2 **Créer un environnement virtuel**
|
||||
|
||||
```sh
|
||||
python3 -m venv agentic_seek_env
|
||||
source agentic_seek_env/bin/activate
|
||||
# Sur Windows: agentic_seek_env\Scripts\activate
|
||||
```
|
||||
|
||||
### 3️⃣ **Installation**
|
||||
|
||||
**Automatique:**
|
||||
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
**Manuel:**
|
||||
|
||||
**Note : Pour tous les systèmes d'exploitation, assurez-vous que le ChromeDriver que vous installez correspond à la version de Chrome installée. Exécutez `google-chrome --version`. Consultez les problèmes connus si vous avez Chrome >135**
|
||||
|
||||
- *Linux*:
|
||||
|
||||
Mettre à jour la liste des paquets : `sudo apt update`
|
||||
|
||||
Installer les dépendances : `sudo apt install -y alsa-utils portaudio19-dev python3-pyaudio libgtk-3-dev libnotify-dev libgconf-2-4 libnss3 libxss1`
|
||||
|
||||
Installer ChromeDriver correspondant à la version de votre navigateur Chrome :
|
||||
`sudo apt install -y chromium-chromedriver`
|
||||
|
||||
Installer les prérequis : `pip3 install -r requirements.txt`
|
||||
|
||||
- *macOS*:
|
||||
|
||||
Mettre à jour brew : `brew update`
|
||||
|
||||
Installer chromedriver : `brew install --cask chromedriver`
|
||||
|
||||
Installer portaudio : `brew install portaudio`
|
||||
|
||||
Mettre à jour pip : `python3 -m pip install --upgrade pip`
|
||||
|
||||
Mettre à jour wheel : `pip3 install --upgrade setuptools wheel`
|
||||
|
||||
Installer les prérequis : `pip3 install -r requirements.txt`
|
||||
|
||||
- *Windows*:
|
||||
|
||||
Installer pyreadline3 : `pip install pyreadline3`
|
||||
|
||||
Installer portaudio manuellement (par exemple, via vcpkg ou des binaires précompilés) puis exécutez : `pip install pyaudio`
|
||||
|
||||
Télécharger et installer chromedriver manuellement depuis : https://sites.google.com/chromium.org/driver/getting-started
|
||||
|
||||
Placez chromedriver dans un répertoire inclus dans votre PATH.
|
||||
|
||||
Installer les prérequis : `pip3 install -r requirements.txt`
|
||||
|
||||
|
||||
## Faire fonctionner sur votre machine
|
||||
|
||||
**Nous recommandons d’utiliser au minimum DeepSeek 14B, les modèles plus petits ont du mal avec l’utilisation des outils et oublient rapidement le contexte.**
|
||||
|
||||
Lancer votre provider local, par exemple avec ollama:
|
||||
```sh
|
||||
ollama serve
|
||||
```
|
||||
|
||||
**Configurer le config.ini**
|
||||
|
||||
Modifiez le fichier config.ini pour définir provider_name sur un fournisseur supporté et provider_model sur un LLM compatible avec votre fournisseur. Nous recommandons des modèles de raisonnement comme *Qwen* ou *Deepseek*.
|
||||
|
||||
Consultez la section **FAQ** à la fin du README pour connaître le matériel requis.
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = True # Si vous exécutez localement ou avec un fournisseur distant.
|
||||
provider_name = ollama # ou lm-studio, openai, etc..
|
||||
provider_model = deepseek-r1:14b # choisissez un modèle adapté à votre matériel
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Jarvis # nom de votre IA
|
||||
recover_last_session = True # récupérer ou non la session précédente
|
||||
save_session = True # mémoriser ou non la session actuelle
|
||||
speak = True # synthèse vocale
|
||||
listen = False # reconnaissance vocale, uniquement pour CLI
|
||||
work_dir = /Users/mlg/Documents/workspace # L'espace de travail pour AgenticSeek.
|
||||
jarvis_personality = False # Utiliser une personnalité plus "Jarvis", non recommandé avec des petits modèles
|
||||
languages = en fr # Liste des langages, la synthèse vocale utilisera par défaut la première langue de la liste
|
||||
[BROWSER]
|
||||
headless_browser = True # Utiliser ou non le navigateur sans interface graphique, recommandé uniquement avec l'interface web.
|
||||
stealth_mode = True # Utiliser selenium non détectable pour réduire la détection du navigateur
|
||||
```
|
||||
|
||||
Remarque : Certains fournisseurs (ex : lm-studio) nécessitent `http://` devant l'adresse IP. Par exemple `http://127.0.0.1:1234`
|
||||
|
||||
|
||||
|
||||
**Liste des provideurs locaux**
|
||||
|
||||
| Fournisseur | Local ? | Description |
|
||||
|-------------|---------|-----------------------------------------------------------|
|
||||
| ollama | Oui | Exécutez des LLM localement avec facilité en utilisant ollama comme fournisseur LLM |
|
||||
| lm-studio | Oui | Exécutez un LLM localement avec LM studio (définissez `provider_name` sur `lm-studio`) |
|
||||
| openai | Oui | Utilisez une API local compatible avec openai |
|
||||
|
||||
|
||||
### **Démarrer les services & Exécuter**
|
||||
|
||||
Activez votre environnement Python si nécessaire.
|
||||
```sh
|
||||
source agentic_seek_env/bin/activate
|
||||
```
|
||||
|
||||
Démarrez les services requis. Cela lancera tous les services définis dans le fichier docker-compose.yml, y compris :
|
||||
- searxng
|
||||
- redis (nécessaire pour searxng)
|
||||
- frontend
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh # MacOS
|
||||
start ./start_services.cmd # Windows
|
||||
```
|
||||
|
||||
**Option 1 :** Exécuter avec l'interface CLI.
|
||||
|
||||
```sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
**Option 2 :** Exécuter avec l'interface Web.
|
||||
|
||||
Démarrez le backend.
|
||||
|
||||
```sh
|
||||
python3 api.py
|
||||
```
|
||||
|
||||
Allez sur `http://localhost:3000/` et vous devriez voir l'interface web.
|
||||
|
||||
Veuillez noter que l'interface web ne diffuse pas les messages en continu pour le moment.
|
||||
|
||||
|
||||
Voyez la section **Utilisation** si vous ne comprenez pas comment l’utiliser
|
||||
|
||||
Voyez la section **Problèmes** connus si vous rencontrez des problèmes
|
||||
|
||||
Voyez la section **Exécuter avec une API** si votre matériel ne peut pas exécuter DeepSeek localement
|
||||
|
||||
Voyez la section **Configuration** pour une explication détaillée du fichier de configuration.
|
||||
|
||||
---
|
||||
|
||||
## Utilisation
|
||||
|
||||
Assurez-vous que les services sont en cours d’exécution avec ./start_services.sh et lancez AgenticSeek avec le CLI ou l'interface Web.
|
||||
|
||||
**CLI:**
|
||||
Vous verrez un prompt : ">>> "
|
||||
Cela indique qu’AgenticSeek attend que vous saisissiez des instructions.
|
||||
Vous pouvez également utiliser la reconnaissance vocale en définissant `listen = True` dans la configuration.
|
||||
Pour quitter, dites simplement `goodbye`.
|
||||
|
||||
**Interface:**
|
||||
|
||||
Assurez-vous d'avoir bien démarré le backend avec `python3 api.py`.
|
||||
Allez sur `localhost:3000` où vous verrez une interface web.
|
||||
Tapez simplement votre message et patientez.
|
||||
Si vous n'avez pas d'interface sur `localhost:3000`, c'est que vous n'avez pas démarré les services avec `start_services.sh`.
|
||||
|
||||
Voici quelques exemples d’utilisation :
|
||||
|
||||
### Programmation
|
||||
|
||||
> *Aide-moi avec la multiplication de matrices en Golang*
|
||||
|
||||
> *Initalize un nouveau project python, setup le readme, gitignore etc.. et fait un premier commit*
|
||||
|
||||
> *Fais un jeu snake en Python*
|
||||
|
||||
### Recherche web
|
||||
|
||||
> *Fais une recherche sur le web pour trouver des startups technologiques au Japon qui travaillent sur des recherches avancées en IA*
|
||||
|
||||
> *Peux-tu trouver sur internet qui a créé agenticSeek ?*
|
||||
|
||||
> *Peux-tu trouver sur quel site je peux acheter une RTX 4090 à bas prix ?*
|
||||
|
||||
### Fichier
|
||||
|
||||
> *Hé, peux-tu trouver où est contrat.pdf ? Je l’ai perdu*
|
||||
|
||||
> *Montre-moi combien d’espace il me reste sur mon disque*
|
||||
|
||||
> *Trouve et lis le fichier README.md et suis les instructions d’installation*
|
||||
|
||||
### Conversation
|
||||
|
||||
> *Parle-moi de la France*
|
||||
|
||||
> *Quel est le sens de la vie ?*
|
||||
|
||||
> *Donne moi une recette simple pour ce midi j'ai pas d'inspi*
|
||||
|
||||
Après avoir saisi votre requête, AgenticSeek attribuera le meilleur agent pour la tâche.
|
||||
|
||||
Le système de routage des agents peut parfois ne pas toujours attribuer le bon agent en fonction de votre requête.
|
||||
|
||||
Par conséquent, vous devez être assez explicite sur ce que vous voulez et sur la manière dont l’IA doit procéder. Par exemple, si vous voulez qu’elle effectue une recherche sur le web, ne dites pas :
|
||||
|
||||
Connait-tu de bons pays pour voyager seul ?
|
||||
|
||||
Dites plutôt :
|
||||
|
||||
Fait une recherche sur le web, quels sont les meilleurs pays pour voyager seul?
|
||||
|
||||
---
|
||||
|
||||
## **Exécuter le LLM sur votre propre serveur**
|
||||
|
||||
Si vous disposez d’un ordinateur puissant ou d’un serveur que vous voulez utiliser, mais que vous souhaitez y accéder depuis votre ordinateur portable, vous avez la possibilité d’exécuter le LLM sur un serveur distant.
|
||||
|
||||
### 1️⃣ **Configurer et démarrer les scripts du serveur**
|
||||
|
||||
Sur votre "serveur" qui exécutera le modèle IA, obtenez l’adresse IP
|
||||
|
||||
```sh
|
||||
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1
|
||||
```
|
||||
|
||||
Remarque : Pour Windows ou macOS, utilisez respectivement ipconfig ou ifconfig pour trouver l’adresse IP.
|
||||
|
||||
Clonez le dépôt et entrez dans le dossier server/.
|
||||
|
||||
|
||||
```sh
|
||||
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek/server/
|
||||
```
|
||||
|
||||
Installez les dépendances spécifiques au serveur :
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
Exécutez le script du serveur.
|
||||
|
||||
```sh
|
||||
python3 app.py --provider ollama --port 3333
|
||||
```
|
||||
|
||||
Vous avez le choix entre utiliser ollama et llamacpp comme service LLM.
|
||||
|
||||
### 2️⃣ **Lancer**
|
||||
|
||||
Maintenant, sur votre ordinateur personnel :
|
||||
|
||||
Modifiez le fichier config.ini pour définir provider_name sur server et provider_model sur deepseek-r1:14b.
|
||||
|
||||
Définissez provider_server_address sur l’adresse IP de la machine qui exécutera le modèle.
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = server
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = x.x.x.x:3333
|
||||
```
|
||||
|
||||
Ensuite, exécutez avec le CLI ou l'interface graphique comme expliqué dans la section pour les fournisseurs locaux.
|
||||
|
||||
## **Exécuter avec une API externe**
|
||||
|
||||
AVERTISSEMENT : Assurez-vous qu’il n’y a pas d’espace en fin de ligne dans la configuration.
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000 # n'importe pas
|
||||
```
|
||||
|
||||
**Liste de provideurs API**
|
||||
| Fournisseur | Local ? | Description |
|
||||
|--------------|---------|-----------------------------------------------------------|
|
||||
| openai | Non | Utilise l'API ChatGPT |
|
||||
| deepseek-api | Non | API Deepseek (non privé) |
|
||||
| huggingface | Non | API Hugging-Face (non privé) |
|
||||
| togetherAI | Non | Utilise l'API Together AI (non privé) |
|
||||
| google | Non | Utilise l'API Google Gemini (non privé) |
|
||||
|
||||
Ensuite, exécutez avec le CLI ou l'interface graphique comme expliqué dans la section pour les fournisseurs locaux.
|
||||
|
||||
## Config
|
||||
|
||||
Exemple de configuration :
|
||||
```
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:1.5b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Friday
|
||||
recover_last_session = False
|
||||
save_session = False
|
||||
speak = False
|
||||
listen = False
|
||||
work_dir = /Users/mlg/Documents/ai_folder
|
||||
jarvis_personality = False
|
||||
languages = en fr
|
||||
[BROWSER]
|
||||
headless_browser = False
|
||||
stealth_mode = False
|
||||
```
|
||||
|
||||
**Explication du fichier config.ini**:
|
||||
|
||||
`is_local` -> Exécute l’agent localement (True) ou sur un serveur distant (False).
|
||||
|
||||
`provider_name` -> Le fournisseur à utiliser (parmi : ollama, server, lm-studio, deepseek-api).
|
||||
|
||||
`provider_model` -> Le modèle utilisé, par exemple, deepseek-r1:1.5b.
|
||||
|
||||
`provider_server_address` -> Adresse du serveur, par exemple, 127.0.0.1:11434 pour local. Définissez n’importe quoi pour une API non locale.
|
||||
|
||||
`agent_name` -> Nom de l’agent, par exemple, Friday. Utilisé comme mot déclencheur pour la reconnaissance vocale.
|
||||
|
||||
`recover_last_session` -> Reprend la dernière session (True) ou non (False).
|
||||
|
||||
`save_session` -> Sauvegarde les données de la session (True) ou non (False).
|
||||
|
||||
`speak` -> Active la sortie vocale (True) ou non (False).
|
||||
|
||||
`listen` -> Écoute les entrées vocales (True) ou non (False).
|
||||
|
||||
`work_dir` -> Dossier auquel l’IA aura accès, par exemple : /Users/user/Documents/.
|
||||
|
||||
`jarvis_personality` -> Utilise une personnalité inspiré de Jarvis (True) ou non (False). Cela utilise simplement une prompt alternative. Marche moins bien en français.
|
||||
|
||||
`headless_browser` -> Exécute le navigateur sans fenêtre visible (True) ou non (False).
|
||||
|
||||
`stealth_mode` -> Rend la détection des bots plus difficile. Le seul inconvénient est que vous devez installer manuellement l’extension anticaptcha.
|
||||
|
||||
`languages` -> La liste de languages supportés (nécessaire pour le routage d'agents). Plus la liste est longue. Plus un nombre important de modèles sera téléchargés.
|
||||
|
||||
## Providers
|
||||
|
||||
Le tableau ci-dessous montre les LLM providers disponibles :
|
||||
|
||||
| Provider | Local? | Description |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| ollama | Yes | Exécutez des LLM localement avec facilité en utilisant Ollama comme fournisseur LLM
|
||||
| server | Yes | Hébergez le modèle sur une autre machine, exécutez sur votre machine locale
|
||||
| lm-studio | Yes | Exécutez un LLM localement avec LM Studio (définissez provider_name sur lm-studio)
|
||||
| openai | No | Utilise l'API ChatGPT (pas privé) |
|
||||
| deepseek-api | No | Utilise l'API Deepseek (pas privé) |
|
||||
| huggingface| No | Utilise Hugging-Face (pas privé) |
|
||||
| together| No | Utilise l'api Together AI |
|
||||
|
||||
Pour sélectionner un provider LLM, modifiez le config.ini :
|
||||
|
||||
```
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
|
||||
`is_local` : doit être True pour tout LLM exécuté localement, sinon False.
|
||||
|
||||
`provider_name` : Sélectionnez le fournisseur à utiliser par son nom, voir la liste des fournisseurs ci-dessus.
|
||||
|
||||
`provider_model` : Définissez le modèle à utiliser par l’agent.
|
||||
|
||||
`provider_server_address` : peut être défini sur n’importe quoi si vous n’utilisez pas le fournisseur server.
|
||||
|
||||
# Problèmes connus
|
||||
|
||||
## Problèmes avec Chromedriver
|
||||
|
||||
Erreur #1:**incompatibilité**
|
||||
|
||||
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
|
||||
Current browser version is 134.0.6998.89 with binary path`
|
||||
|
||||
Cela se produit s’il y a une incompatibilité entre votre navigateur et la version de chromedriver.
|
||||
|
||||
Vous devez naviguer pour télécharger la dernière version :
|
||||
|
||||
https://developer.chrome.com/docs/chromedriver/downloads
|
||||
|
||||
Si vous utilisez Chrome version 115 ou plus récent, allez sur :
|
||||
|
||||
https://googlechromelabs.github.io/chrome-for-testing/
|
||||
|
||||
Et téléchargez la version de chromedriver correspondant à votre système d’exploitation.
|
||||
|
||||

|
||||
|
||||
Si cette section est incomplète, merci de faire une nouvelle issue sur github.
|
||||
|
||||
## FAQ
|
||||
**Q: Quel matériel est nécessaire ?**
|
||||
|
||||
| Taille du Modèle | GPU | Commentaire |
|
||||
|--------------------|------|----------------------------------------------------------|
|
||||
| 7B | 8 Go VRAM | ⚠️ Non recommandé. Performances médiocres, hallucinations fréquentes, et l'agent planificateur échouera probablement. |
|
||||
| 14B | 12 Go VRAM (par ex. RTX 3060) | ✅ Utilisable pour des tâches simples. Peut rencontrer des difficultés avec la navigation web et les tâches de planification. |
|
||||
| 32B | 24+ Go VRAM (par ex. RTX 4090) | 🚀 Réussite avec la plupart des tâches, peut encore avoir des difficultés avec la planification des tâches. |
|
||||
| 70B+ | 48+ Go VRAM (par ex. Mac Studio) | 💪 Excellent. Recommandé pour des cas d'utilisation avancés. |
|
||||
|
||||
**Q: Pourquoi deepseek et pas un autre modèle**
|
||||
|
||||
DeepSeek R1 excelle dans le raisonnement et l’utilisation d’outils pour sa taille. Nous pensons que c’est un choix solide pour nos besoins, bien que d’autres modèles fonctionnent également (bien que moins bien pour un nombre équivalent de paramètres).
|
||||
|
||||
**Q: J'ai une erreur quand je lance le programme, je fait quoi?**
|
||||
|
||||
Assurez-vous qu’Ollama est en cours d’exécution (ollama serve), que votre config.ini correspond à votre fournisseur, et que les dépendances sont installées. Si cela ne fonctionne pas, n’hésitez pas à signaler un problème.
|
||||
|
||||
**Q: C'est vraiment 100% local?**
|
||||
|
||||
Oui, avec les fournisseurs Ollama, lm-studio ou Server, toute la reconnaissance vocale, le LLM et la synthèse vocale fonctionnent localement. Les options non locales (OpenAI ou autres API) sont facultatives.
|
||||
|
||||
**Q: En quoi c'est supérieur à Manus**
|
||||
|
||||
Il ne l'est certainement pas, mais nous privilégions l’exécution locale et la confidentialité par rapport à une approche basée sur le cloud. C’est une alternative plus accessible et surtout moins cher !
|
||||
|
||||
## Contribution
|
||||
|
||||
Nous recherchons des développeurs pour améliorer AgenticSeek ! Consultez la section "issues" github ou les discussions.
|
||||
|
||||
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
|
||||
|
||||
[Guide du contributeur](./docs/CONTRIBUTING.md)
|
||||
|
||||
## Mainteneurs:
|
||||
> [Fosowl](https://github.com/Fosowl)
|
||||
> [steveh8758](https://github.com/steveh8758)
|
||||
> [https://github.com/antoineVIVIES](https://github.com/antoineVIVIES)
|
||||
@@ -0,0 +1,488 @@
|
||||
<p align="center">
|
||||
<img align="center" src="./media/whale_readme.jpg">
|
||||
<p>
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
[English](./README.md) | [中文](./README_CHS.md) | [繁體中文](./README_CHT.md) | [Français](./README_FR.md) | 日本語
|
||||
|
||||
# AgenticSeek: Deepseek R1エージェントによって動作するManusのようなAI。
|
||||
|
||||
|
||||
**Manus AIの完全なローカル代替品**、音声対応のAIアシスタントで、コードを書き、ファイルシステムを探索し、ウェブを閲覧し、ミスを修正し、データをクラウドに送信することなくすべてを行います。DeepSeek R1のような推論モデルを使用して構築されており、この自律エージェントは完全にハードウェア上で動作し、データのプライバシーを保護します。
|
||||
|
||||
[](https://fosowl.github.io/agenticSeek.html)  [](https://discord.gg/8hGDaME3TC) [](https://x.com/Martin993886460)
|
||||
|
||||
> 🛠️ **進行中の作業** – 貢献者を探しています!
|
||||
|
||||
|
||||
|
||||
|
||||
https://github.com/user-attachments/assets/fe9e8006-0462-4793-8b31-25bd42c6d1eb
|
||||
|
||||
|
||||
|
||||
|
||||
*そしてもっと多くのことができます!*
|
||||
|
||||
> *大阪と東京のAIスタートアップを深く調査し、少なくとも5つ見つけて、research_japan.txtファイルに保存してください*
|
||||
|
||||
> *C言語でテトリスゲームを作れますか?*
|
||||
|
||||
> *新しいプロジェクトファイルインデックスをmark2として設定したいです。*
|
||||
|
||||
|
||||
## 特徴:
|
||||
|
||||
- **100%ローカル**: クラウドなし、ハードウェア上で動作。データはあなたのものです。
|
||||
|
||||
- **ファイルシステムの操作**: bashを使用してファイルを簡単にナビゲートおよび操作します。
|
||||
|
||||
- **自律的なコーディング**: Python、C、Golangなどのコードを書き、デバッグし、実行できます。
|
||||
|
||||
- **エージェントルーティング**: タスクに最適なエージェントを自動的に選択します。
|
||||
|
||||
- **計画**: 複雑なタスクの場合、複数のエージェントを起動して計画および実行します。
|
||||
|
||||
- **自律的なウェブブラウジング**: 自律的なウェブナビゲーション。
|
||||
|
||||
- **メモリ**: 効率的なメモリとセッション管理。
|
||||
|
||||
---
|
||||
|
||||
## **インストール**
|
||||
|
||||
chrome driver、docker、およびpython3.10(またはそれ以降)がインストールされていることを確認してください。
|
||||
|
||||
chrome driverに関連する問題については、**Chromedriver**セクションを参照してください。
|
||||
|
||||
### 1️⃣ **リポジトリをクローンしてセットアップ**
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek
|
||||
mv .env.example .env
|
||||
```
|
||||
|
||||
### 2️ **仮想環境を作成**
|
||||
|
||||
```sh
|
||||
python3 -m venv agentic_seek_env
|
||||
source agentic_seek_env/bin/activate
|
||||
# Windowsの場合: agentic_seek_env\Scripts\activate
|
||||
```
|
||||
|
||||
### 3️⃣ **パッケージをインストール**
|
||||
|
||||
**自動インストール:**
|
||||
|
||||
```sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
** テキスト読み上げ(TTS)機能で日本語をサポートするには、fugashi(日本語分かち書きライブラリ)をインストールする必要があります:**
|
||||
|
||||
```
|
||||
pip3 install --upgrade pyopenjtalk jaconv mojimoji unidic fugashi
|
||||
pip install unidic-lite
|
||||
python -m unidic download
|
||||
```
|
||||
|
||||
**手動で:**
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
# または
|
||||
python3 setup.py install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ローカルマシンでLLMを実行するためのセットアップ
|
||||
|
||||
**少なくともDeepseek 14Bを使用することをお勧めします。小さいモデルでは、特にウェブブラウジングのタスクで苦労する可能性があります。**
|
||||
|
||||
**ローカルプロバイダーをセットアップする**
|
||||
|
||||
たとえば、ollamaを使用してローカルプロバイダーを開始します:
|
||||
|
||||
```sh
|
||||
ollama serve
|
||||
```
|
||||
|
||||
以下に、サポートされているローカルプロバイダーのリストを示します。
|
||||
|
||||
**config.iniを更新する**
|
||||
|
||||
config.iniファイルを変更して、`provider_name`をサポートされているプロバイダーに設定し、`provider_model`を`deepseek-r1:14b`に設定します。
|
||||
|
||||
注意: `deepseek-r1:14b`は例です。ハードウェアが許可する場合は、より大きなモデルを使用してください。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama # または lm-studio、openai など
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
```
|
||||
|
||||
**ローカルプロバイダーのリスト**
|
||||
|
||||
| プロバイダー | ローカル? | 説明 |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| ollama | はい | ollamaをLLMプロバイダーとして使用して、ローカルでLLMを簡単に実行 |
|
||||
| lm-studio | はい | LM studioを使用してローカルでLLMを実行(`provider_name`を`lm-studio`に設定)|
|
||||
| openai | はい | OpenAI互換APIを使用 |
|
||||
|
||||
次のステップ: [サービスを開始してAgenticSeekを実行する](#Start-services-and-Run)
|
||||
|
||||
*問題が発生している場合は、**既知の問題**セクションを参照してください。*
|
||||
|
||||
*ハードウェアがDeepseekをローカルで実行できない場合は、**APIを使用した実行**セクションを参照してください。*
|
||||
|
||||
*詳細な設定ファイルの説明については、**設定**セクションを参照してください。*
|
||||
|
||||
---
|
||||
|
||||
## APIを使用したセットアップ
|
||||
|
||||
`config.ini`で希望するプロバイダーを設定してください。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
|
||||
警告: `config.ini`に末尾のスペースがないことを確認してください。
|
||||
|
||||
ローカルのOpenAIベースのAPIを使用する場合は、`is_local`をTrueに設定してください。
|
||||
|
||||
OpenAIベースのAPIが独自のサーバーで実行されている場合は、IPアドレスを変更してください。
|
||||
|
||||
次のステップ: [サービスを開始してAgenticSeekを実行する](#Start-services-and-Run)
|
||||
|
||||
*問題が発生している場合は、**既知の問題**セクションを参照してください。*
|
||||
|
||||
*詳細な設定ファイルの説明については、**設定**セクションを参照してください。*
|
||||
|
||||
---
|
||||
|
||||
## サービスの開始と実行
|
||||
|
||||
必要に応じてPython環境をアクティブにしてください。
|
||||
```sh
|
||||
source agentic_seek_env/bin/activate
|
||||
```
|
||||
|
||||
必要なサービスを開始します。これにより、docker-compose.ymlから以下のサービスがすべて開始されます:
|
||||
- searxng
|
||||
- redis (searxngに必要)
|
||||
- フロントエンド
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh # MacOS
|
||||
start ./start_services.cmd # Windows
|
||||
```
|
||||
|
||||
**オプション1:** CLIインターフェースで実行。
|
||||
|
||||
```sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
**オプション2:** Webインターフェースで実行。
|
||||
|
||||
注意: 現在、CLIの使用を推奨しています。Webインターフェースは開発中です。
|
||||
|
||||
バックエンドを開始します。
|
||||
|
||||
```sh
|
||||
python3 api.py
|
||||
```
|
||||
|
||||
`http://localhost:3000/`にアクセスすると、Webインターフェースが表示されます。
|
||||
|
||||
現在、Webインターフェースではメッセージのストリーミングがサポートされていないことに注意してください。
|
||||
|
||||
---
|
||||
|
||||
## 使い方
|
||||
|
||||
警告: 現在、サポートされている言語は英語、中国語、フランス語のみです。他の言語でのプロンプトは機能しますが、適切なエージェントにルーティングされない場合があります。
|
||||
|
||||
サービスが`./start_services.sh`で起動していることを確認し、`python3 cli.py`でagenticSeekを実行します。
|
||||
|
||||
```sh
|
||||
sudo ./start_services.sh
|
||||
python3 cli.py
|
||||
```
|
||||
|
||||
`>>> `と表示されます
|
||||
これは、agenticSeekが指示を待っていることを示します。
|
||||
configで`listen = True`を設定することで、音声認識を使用することもできます。
|
||||
|
||||
終了するには、単に`goodbye`と言います。
|
||||
|
||||
以下は使用例です:
|
||||
|
||||
### コーディング/バッシュ
|
||||
|
||||
> *Pythonでスネークゲームを作成*
|
||||
|
||||
> *C言語で行列の掛け算を教えて*
|
||||
|
||||
> *Golangでブラックジャックを作成*
|
||||
|
||||
### ウェブ検索
|
||||
|
||||
> *日本の最先端のAI研究を行っているクールなテックスタートアップを見つけるためにウェブ検索を行う*
|
||||
|
||||
> *agenticSeekを作成したのは誰かをインターネットで見つけることができますか?*
|
||||
|
||||
> *オンラインの燃料計算機を使用して、ニースからミラノまでの旅行の費用を見積もることができますか?*
|
||||
|
||||
### ファイルシステム
|
||||
|
||||
> *契約書.pdfがどこにあるか見つけてくれませんか?*
|
||||
|
||||
> *ディスクにどれだけの空き容量があるか教えて*
|
||||
|
||||
> *READMEを読んでプロジェクトを/home/path/projectにインストールしてください*
|
||||
|
||||
### カジュアル
|
||||
|
||||
> *フランスのレンヌについて教えて*
|
||||
|
||||
> *博士号を追求すべきですか?*
|
||||
|
||||
> *最高のワークアウトルーチンは何ですか?*
|
||||
|
||||
|
||||
クエリを入力すると、agenticSeekはタスクに最適なエージェントを割り当てます。
|
||||
|
||||
これは初期のプロトタイプであるため、エージェントルーティングシステムはクエリに基づいて常に適切なエージェントを割り当てるとは限りません。
|
||||
|
||||
したがって、何を望んでいるか、AIがどのように進行するかについて非常に明確にする必要があります。たとえば、ウェブ検索を行いたい場合は、次のように言わないでください:
|
||||
|
||||
`一人旅に良い国を知っていますか?`
|
||||
|
||||
代わりに、次のように尋ねてください:
|
||||
|
||||
`ウェブ検索を行い、一人旅に最適な国を見つけてください`
|
||||
|
||||
---
|
||||
|
||||
## **ボーナス: 自分のサーバーでLLMを実行するためのセットアップ**
|
||||
|
||||
強力なコンピュータやサーバーを持っていて、それをラップトップから使用したい場合、リモートサーバーでLLMを実行するオプションがあります。
|
||||
|
||||
AIモデルを実行する「サーバー」で、IPアドレスを取得します。
|
||||
|
||||
```sh
|
||||
ip a | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | cut -d/ -f1 # ローカルIP
|
||||
curl https://ipinfo.io/ip # 公開IP
|
||||
```
|
||||
|
||||
注意: WindowsまたはmacOSの場合、IPアドレスを見つけるには、それぞれ`ipconfig`または`ifconfig`を使用してください。
|
||||
|
||||
リポジトリをクローンし、`server/`フォルダーに移動します。
|
||||
|
||||
```sh
|
||||
git clone --depth 1 https://github.com/Fosowl/agenticSeek.git
|
||||
cd agenticSeek/server/
|
||||
```
|
||||
|
||||
サーバー固有の依存関係をインストールします:
|
||||
|
||||
```sh
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
サーバースクリプトを実行します。
|
||||
|
||||
```sh
|
||||
python3 app.py --provider ollama --port 3333
|
||||
```
|
||||
|
||||
`ollama`と`llamacpp`のどちらかをLLMサービスとして選択できます。
|
||||
|
||||
次に、個人用コンピュータで以下を行います:
|
||||
|
||||
`config.ini`ファイルを変更し、`provider_name`を`server`に、`provider_model`を`deepseek-r1:xxb`に設定します。
|
||||
`provider_server_address`をモデルを実行するマシンのIPアドレスに設定します。
|
||||
|
||||
```sh
|
||||
[MAIN]
|
||||
is_local = False
|
||||
provider_name = server
|
||||
provider_model = deepseek-r1:70b
|
||||
provider_server_address = x.x.x.x:3333
|
||||
```
|
||||
|
||||
次のステップ: [サービスを開始してAgenticSeekを実行する](#Start-services-and-Run)
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 音声認識
|
||||
|
||||
現在、音声認識は英語でのみ動作することに注意してください。
|
||||
|
||||
音声認識機能はデフォルトで無効になっています。有効にするには、config.iniファイルでlistenオプションをTrueに設定します:
|
||||
|
||||
```
|
||||
listen = True
|
||||
```
|
||||
|
||||
有効にすると、音声認識機能はトリガーキーワード(エージェントの名前)を待ちます。その後、入力を処理します。エージェントの名前は*config.ini*ファイルの`agent_name`値を更新することでカスタマイズできます:
|
||||
|
||||
```
|
||||
agent_name = Friday
|
||||
```
|
||||
|
||||
最適な認識のために、"John"や"Emma"のような一般的な英語の名前をエージェント名として使用することをお勧めします。
|
||||
|
||||
トランスクリプトが表示され始めたら、エージェントの名前を大声で言って起動します(例:"Friday")。
|
||||
|
||||
クエリを明確に話します。
|
||||
|
||||
リクエストを終了する際に確認フレーズを使用してシステムに進行を通知します。確認フレーズの例には次のようなものがあります:
|
||||
```
|
||||
"do it", "go ahead", "execute", "run", "start", "thanks", "would ya", "please", "okay?", "proceed", "continue", "go on", "do that", "go it", "do you understand?"
|
||||
```
|
||||
|
||||
## 設定
|
||||
|
||||
設定例:
|
||||
```
|
||||
[MAIN]
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:1.5b
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Friday
|
||||
recover_last_session = False
|
||||
save_session = False
|
||||
speak = False
|
||||
listen = False
|
||||
work_dir = /Users/mlg/Documents/ai_folder
|
||||
jarvis_personality = False
|
||||
languages = en ja
|
||||
[BROWSER]
|
||||
headless_browser = False
|
||||
stealth_mode = False
|
||||
```
|
||||
|
||||
**説明**:
|
||||
|
||||
- is_local -> エージェントをローカルで実行する(True)か、リモートサーバーで実行する(False)。
|
||||
- provider_name -> 使用するプロバイダー(`ollama`、`server`、`lm-studio`、`deepseek-api`のいずれか)。
|
||||
- provider_model -> 使用するモデル、例: deepseek-r1:1.5b。
|
||||
- provider_server_address -> サーバーアドレス、例: 127.0.0.1:11434(ローカルの場合)。非ローカルAPIの場合は何でも設定できます。
|
||||
- agent_name -> エージェントの名前、例: Friday。TTSのトリガーワードとして使用されます。
|
||||
- recover_last_session -> 最後のセッションから再開する(True)か、しない(False)。
|
||||
- save_session -> セッションデータを保存する(True)か、しない(False)。
|
||||
- speak -> 音声出力を有効にする(True)か、しない(False)。
|
||||
- listen -> 音声入力を有効にする(True)か、しない(False)。
|
||||
- work_dir -> AIがアクセスするフォルダー。例: /Users/user/Documents/。
|
||||
- jarvis_personality -> JARVISのようなパーソナリティを使用する(True)か、しない(False)。これは単にプロンプトファイルを変更するだけです。
|
||||
- headless_browser -> ウィンドウを表示せずにブラウザを実行する(True)か、しない(False)。
|
||||
- stealth_mode -> ボット検出を難しくします。唯一の欠点は、anticaptcha拡張機能を手動でインストールする必要があることです。
|
||||
- languages -> List of supported languages. Required for agent routing system. The longer the languages list the more model will be downloaded.
|
||||
|
||||
## プロバイダー
|
||||
|
||||
以下の表は利用可能なプロバイダーを示しています:
|
||||
|
||||
| プロバイダー | ローカル? | 説明 |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| ollama | はい | ollamaをLLMプロバイダーとして使用して、ローカルでLLMを簡単に実行 |
|
||||
| server | はい | モデルを別のマシンでホストし、ローカルマシンで実行 |
|
||||
| lm-studio | はい | LM studio(`lm-studio`)を使用してローカルでLLMを実行 |
|
||||
| openai | 場合による | ChatGPT API(非プライベート)またはopenai互換APIを使用 |
|
||||
| deepseek-api | いいえ | Deepseek API(非プライベート) |
|
||||
| huggingface| いいえ | Hugging-Face API(非プライベート) |
|
||||
| togetherAI | いいえ | together AI API(非プライベート)を使用
|
||||
|
||||
|
||||
プロバイダーを選択するには、config.iniを変更します:
|
||||
|
||||
```
|
||||
is_local = False
|
||||
provider_name = openai
|
||||
provider_model = gpt-4o
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
```
|
||||
`is_local`: ローカルで実行されるLLMの場合はTrue、それ以外の場合はFalse。
|
||||
|
||||
`provider_name`: 使用するプロバイダーを名前で選択します。上記のプロバイダーリストを参照してください。
|
||||
|
||||
`provider_model`: エージェントが使用するモデルを設定します。
|
||||
|
||||
`provider_server_address`: サーバープロバイダーを使用しない場合は何でも設定できます。
|
||||
|
||||
# 既知の問題
|
||||
|
||||
## Chromedriverの問題
|
||||
|
||||
**既知のエラー#1:** *chromedriverの不一致*
|
||||
|
||||
`Exception: Failed to initialize browser: Message: session not created: This version of ChromeDriver only supports Chrome version 113
|
||||
Current browser version is 134.0.6998.89 with binary path`
|
||||
|
||||
これは、ブラウザとchromedriverのバージョンが一致しない場合に発生します。
|
||||
|
||||
最新バージョンをダウンロードするには、次のリンクにアクセスしてください:
|
||||
|
||||
https://developer.chrome.com/docs/chromedriver/downloads
|
||||
|
||||
Chromeバージョン115以降を使用している場合は、次のリンクにアクセスしてください:
|
||||
|
||||
https://googlechromelabs.github.io/chrome-for-testing/
|
||||
|
||||
お使いのOSに対応するchromedriverバージョンをダウンロードします。
|
||||
|
||||

|
||||
|
||||
このセクションが不完全な場合は、問題を報告してください。
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: どのようなハードウェアが必要ですか?**
|
||||
|
||||
| モデルサイズ | GPU | コメント |
|
||||
|-----------|--------|-----------------------------------------------------------|
|
||||
| 7B | 8GB VRAM | ⚠️ 推奨されません。パフォーマンスが低く、頻繁に幻覚を起こし、プランナーエージェントが失敗する可能性が高いです。 |
|
||||
| 14B | 12GB VRAM (例: RTX 3060) | ✅ 簡単なタスクには使用可能です。ウェブブラウジングや計画タスクには苦労する可能性があります。 |
|
||||
| 32B | 24GB以上のVRAM (例: RTX 4090) | 🚀 ほとんどのタスクで成功しますが、タスク計画にはまだ苦労する可能性があります。 |
|
||||
| 70B+ | 48GB以上のVRAM (例: Mac Studio) | 💪 優れた性能。高度なユースケースに推奨されます。 |
|
||||
|
||||
**Q: なぜ他のモデルではなくDeepseek R1を選ぶのですか?**
|
||||
|
||||
Deepseek R1は、そのサイズに対して推論とツールの使用に優れています。私たちのニーズに最適だと考えています。他のモデルも問題なく動作しますが、Deepseekが私たちの主な選択です。
|
||||
|
||||
**Q: `cli.py`を実行するとエラーが発生します。どうすればよいですか?**
|
||||
|
||||
Ollamaが実行中であることを確認してください(`ollama serve`)、`config.ini`がプロバイダーに一致していること、および依存関係がインストールされていることを確認してください。それでも解決しない場合は、問題を報告してください。
|
||||
|
||||
**Q: 本当に100%ローカルで実行できますか?**
|
||||
|
||||
はい、OllamaまたはServerプロバイダーを使用すると、すべての音声認識、LLM、および音声合成モデルがローカルで実行されます。非ローカルオプション(OpenAIまたは他のAPI)はオプションです。
|
||||
|
||||
**Q: Manusを持っているのに、なぜAgenticSeekを使用する必要があるのですか?**
|
||||
|
||||
これは、AIエージェントに関する興味から始まったサイドプロジェクトです。特別な点は、ローカルモデルを使用し、APIを避けることです。
|
||||
私たちは、JarvisやFriday(アイアンマン映画)からインスピレーションを得て、「クール」にしようとしましたが、機能性に関してはManusから多くのインスピレーションを得ています。なぜなら、人々が最初に求めているのはローカルのManusの代替品だからです。
|
||||
Manusとは異なり、AgenticSeekは外部システムからの独立性を優先し、より多くの制御、プライバシーを提供し、APIのコストを回避します。
|
||||
|
||||
## 貢献
|
||||
|
||||
AgenticSeekを改善するための開発者を探しています!オープンな問題やディスカッションを確認してください。
|
||||
|
||||
[](https://www.star-history.com/#Fosowl/agenticSeek&Date)
|
||||
|
||||
## 著者:
|
||||
> [Fosowl](https://github.com/Fosowl)
|
||||
> [steveh8758](https://github.com/steveh8758)
|
||||
@@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, sys
|
||||
import uvicorn
|
||||
import aiofiles
|
||||
import configparser
|
||||
import asyncio
|
||||
import time
|
||||
from typing import List
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.responses import FileResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
import uuid
|
||||
|
||||
from sources.llm_provider import Provider
|
||||
from sources.interaction import Interaction
|
||||
from sources.agents import CasualAgent, CoderAgent, FileAgent, PlannerAgent, BrowserAgent
|
||||
from sources.browser import Browser, create_driver
|
||||
from sources.utility import pretty_print
|
||||
from sources.logger import Logger
|
||||
from sources.schemas import QueryRequest, QueryResponse
|
||||
|
||||
|
||||
from celery import Celery
|
||||
|
||||
api = FastAPI(title="AgenticSeek API", version="0.1.0")
|
||||
celery_app = Celery("tasks", broker="redis://localhost:6379/0", backend="redis://localhost:6379/0")
|
||||
celery_app.conf.update(task_track_started=True)
|
||||
logger = Logger("backend.log")
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
|
||||
api.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
if not os.path.exists(".screenshots"):
|
||||
os.makedirs(".screenshots")
|
||||
api.mount("/screenshots", StaticFiles(directory=".screenshots"), name="screenshots")
|
||||
|
||||
def initialize_system():
|
||||
stealth_mode = config.getboolean('BROWSER', 'stealth_mode')
|
||||
personality_folder = "jarvis" if config.getboolean('MAIN', 'jarvis_personality') else "base"
|
||||
languages = config["MAIN"]["languages"].split(' ')
|
||||
|
||||
provider = Provider(
|
||||
provider_name=config["MAIN"]["provider_name"],
|
||||
model=config["MAIN"]["provider_model"],
|
||||
server_address=config["MAIN"]["provider_server_address"],
|
||||
is_local=config.getboolean('MAIN', 'is_local')
|
||||
)
|
||||
logger.info(f"Provider initialized: {provider.provider_name} ({provider.model})")
|
||||
|
||||
browser = Browser(
|
||||
create_driver(headless=config.getboolean('BROWSER', 'headless_browser'), stealth_mode=stealth_mode),
|
||||
anticaptcha_manual_install=stealth_mode
|
||||
)
|
||||
logger.info("Browser initialized")
|
||||
|
||||
agents = [
|
||||
CasualAgent(
|
||||
name=config["MAIN"]["agent_name"],
|
||||
prompt_path=f"prompts/{personality_folder}/casual_agent.txt",
|
||||
provider=provider, verbose=False
|
||||
),
|
||||
CoderAgent(
|
||||
name="coder",
|
||||
prompt_path=f"prompts/{personality_folder}/coder_agent.txt",
|
||||
provider=provider, verbose=False
|
||||
),
|
||||
FileAgent(
|
||||
name="File Agent",
|
||||
prompt_path=f"prompts/{personality_folder}/file_agent.txt",
|
||||
provider=provider, verbose=False
|
||||
),
|
||||
BrowserAgent(
|
||||
name="Browser",
|
||||
prompt_path=f"prompts/{personality_folder}/browser_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser
|
||||
),
|
||||
PlannerAgent(
|
||||
name="Planner",
|
||||
prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser
|
||||
)
|
||||
]
|
||||
logger.info("Agents initialized")
|
||||
|
||||
interaction = Interaction(
|
||||
agents,
|
||||
tts_enabled=config.getboolean('MAIN', 'speak'),
|
||||
stt_enabled=config.getboolean('MAIN', 'listen'),
|
||||
recover_last_session=config.getboolean('MAIN', 'recover_last_session'),
|
||||
langs=languages
|
||||
)
|
||||
logger.info("Interaction initialized")
|
||||
return interaction
|
||||
|
||||
interaction = initialize_system()
|
||||
is_generating = False
|
||||
query_resp_history = []
|
||||
|
||||
@api.get("/screenshot")
|
||||
async def get_screenshot():
|
||||
logger.info("Screenshot endpoint called")
|
||||
screenshot_path = ".screenshots/updated_screen.png"
|
||||
if os.path.exists(screenshot_path):
|
||||
return FileResponse(screenshot_path)
|
||||
logger.error("No screenshot available")
|
||||
return JSONResponse(
|
||||
status_code=404,
|
||||
content={"error": "No screenshot available"}
|
||||
)
|
||||
|
||||
@api.get("/health")
|
||||
async def health_check():
|
||||
logger.info("Health check endpoint called")
|
||||
return {"status": "healthy", "version": "0.1.0"}
|
||||
|
||||
@api.get("/is_active")
|
||||
async def is_active():
|
||||
logger.info("Is active endpoint called")
|
||||
return {"is_active": interaction.is_active}
|
||||
|
||||
@api.get("/latest_answer")
|
||||
async def get_latest_answer():
|
||||
global query_resp_history
|
||||
if interaction.current_agent is None:
|
||||
return JSONResponse(status_code=404, content={"error": "No agent available"})
|
||||
uid = str(uuid.uuid4())
|
||||
if not any(q["answer"] == interaction.current_agent.last_answer for q in query_resp_history):
|
||||
query_resp = {
|
||||
"done": "false",
|
||||
"answer": interaction.current_agent.last_answer,
|
||||
"agent_name": interaction.current_agent.agent_name if interaction.current_agent else "None",
|
||||
"success": interaction.current_agent.success,
|
||||
"blocks": {f'{i}': block.jsonify() for i, block in enumerate(interaction.get_last_blocks_result())} if interaction.current_agent else {},
|
||||
"status": interaction.current_agent.get_status_message if interaction.current_agent else "No status available",
|
||||
"uid": uid
|
||||
}
|
||||
interaction.current_agent.last_answer = ""
|
||||
query_resp_history.append(query_resp)
|
||||
return JSONResponse(status_code=200, content=query_resp)
|
||||
if query_resp_history:
|
||||
return JSONResponse(status_code=200, content=query_resp_history[-1])
|
||||
return JSONResponse(status_code=404, content={"error": "No answer available"})
|
||||
|
||||
async def think_wrapper(interaction, query):
|
||||
try:
|
||||
interaction.last_query = query
|
||||
logger.info("Agents request is being processed")
|
||||
success = await interaction.think()
|
||||
if not success:
|
||||
interaction.last_answer = "Error: No answer from agent"
|
||||
interaction.last_success = False
|
||||
else:
|
||||
interaction.last_success = True
|
||||
pretty_print(interaction.last_answer)
|
||||
interaction.speak_answer()
|
||||
return success
|
||||
except Exception as e:
|
||||
logger.error(f"Error in think_wrapper: {str(e)}")
|
||||
interaction.last_answer = f"Error: {str(e)}"
|
||||
interaction.last_success = False
|
||||
raise e
|
||||
|
||||
@api.post("/query", response_model=QueryResponse)
|
||||
async def process_query(request: QueryRequest):
|
||||
global is_generating, query_resp_history
|
||||
logger.info(f"Processing query: {request.query}")
|
||||
query_resp = QueryResponse(
|
||||
done="false",
|
||||
answer="",
|
||||
agent_name="Unknown",
|
||||
success="false",
|
||||
blocks={},
|
||||
status="Ready",
|
||||
uid=str(uuid.uuid4())
|
||||
)
|
||||
if is_generating:
|
||||
logger.warning("Another query is being processed, please wait.")
|
||||
return JSONResponse(status_code=429, content=query_resp.jsonify())
|
||||
|
||||
try:
|
||||
is_generating = True
|
||||
success = await think_wrapper(interaction, request.query)
|
||||
is_generating = False
|
||||
|
||||
if not success:
|
||||
query_resp.answer = interaction.last_answer
|
||||
return JSONResponse(status_code=400, content=query_resp.jsonify())
|
||||
|
||||
if interaction.current_agent:
|
||||
blocks_json = {f'{i}': block.jsonify() for i, block in enumerate(interaction.current_agent.get_blocks_result())}
|
||||
else:
|
||||
logger.error("No current agent found")
|
||||
blocks_json = {}
|
||||
query_resp.answer = "Error: No current agent"
|
||||
return JSONResponse(status_code=400, content=query_resp.jsonify())
|
||||
|
||||
logger.info(f"Answer: {interaction.last_answer}")
|
||||
logger.info(f"Blocks: {blocks_json}")
|
||||
query_resp.done = "true"
|
||||
query_resp.answer = interaction.last_answer
|
||||
query_resp.agent_name = interaction.current_agent.agent_name
|
||||
query_resp.success = str(interaction.last_success)
|
||||
query_resp.blocks = blocks_json
|
||||
|
||||
# Store the raw dictionary representation
|
||||
query_resp_dict = {
|
||||
"done": query_resp.done,
|
||||
"answer": query_resp.answer,
|
||||
"agent_name": query_resp.agent_name,
|
||||
"success": query_resp.success,
|
||||
"blocks": query_resp.blocks,
|
||||
"status": query_resp.status,
|
||||
"uid": query_resp.uid
|
||||
}
|
||||
query_resp_history.append(query_resp_dict)
|
||||
|
||||
logger.info("Query processed successfully")
|
||||
return JSONResponse(status_code=200, content=query_resp.jsonify())
|
||||
except Exception as e:
|
||||
logger.error(f"An error occurred: {str(e)}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
logger.info("Processing finished")
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
|
||||
if __name__ == "__main__":
|
||||
uvicorn.run(api, host="0.0.0.0", port=8000)
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin python3
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import configparser
|
||||
import asyncio
|
||||
|
||||
from sources.llm_provider import Provider
|
||||
from sources.interaction import Interaction
|
||||
from sources.agents import Agent, CoderAgent, CasualAgent, FileAgent, PlannerAgent, BrowserAgent, McpAgent
|
||||
from sources.browser import Browser, create_driver
|
||||
from sources.utility import pretty_print
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
|
||||
async def main():
|
||||
pretty_print("Initializing...", color="status")
|
||||
stealth_mode = config.getboolean('BROWSER', 'stealth_mode')
|
||||
personality_folder = "jarvis" if config.getboolean('MAIN', 'jarvis_personality') else "base"
|
||||
languages = config["MAIN"]["languages"].split(' ')
|
||||
|
||||
provider = Provider(provider_name=config["MAIN"]["provider_name"],
|
||||
model=config["MAIN"]["provider_model"],
|
||||
server_address=config["MAIN"]["provider_server_address"],
|
||||
is_local=config.getboolean('MAIN', 'is_local'))
|
||||
|
||||
browser = Browser(
|
||||
create_driver(headless=config.getboolean('BROWSER', 'headless_browser'), stealth_mode=stealth_mode),
|
||||
anticaptcha_manual_install=stealth_mode
|
||||
)
|
||||
|
||||
agents = [
|
||||
CasualAgent(name=config["MAIN"]["agent_name"],
|
||||
prompt_path=f"prompts/{personality_folder}/casual_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
CoderAgent(name="coder",
|
||||
prompt_path=f"prompts/{personality_folder}/coder_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
FileAgent(name="File Agent",
|
||||
prompt_path=f"prompts/{personality_folder}/file_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
BrowserAgent(name="Browser",
|
||||
prompt_path=f"prompts/{personality_folder}/browser_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser),
|
||||
PlannerAgent(name="Planner",
|
||||
prompt_path=f"prompts/{personality_folder}/planner_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser),
|
||||
McpAgent(name="MCP Agent",
|
||||
prompt_path=f"prompts/{personality_folder}/mcp_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
]
|
||||
|
||||
interaction = Interaction(agents,
|
||||
tts_enabled=config.getboolean('MAIN', 'speak'),
|
||||
stt_enabled=config.getboolean('MAIN', 'listen'),
|
||||
recover_last_session=config.getboolean('MAIN', 'recover_last_session'),
|
||||
langs=languages
|
||||
)
|
||||
try:
|
||||
while interaction.is_active:
|
||||
interaction.get_user()
|
||||
if await interaction.think():
|
||||
interaction.show_answer()
|
||||
interaction.speak_answer()
|
||||
except Exception as e:
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
raise e
|
||||
finally:
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -2,10 +2,15 @@
|
||||
is_local = True
|
||||
provider_name = ollama
|
||||
provider_model = deepseek-r1:14b
|
||||
provider_server_address = 127.0.0.1:5000
|
||||
agent_name = Friday
|
||||
recover_last_session = True
|
||||
provider_server_address = 127.0.0.1:11434
|
||||
agent_name = Name_of_your_AI
|
||||
recover_last_session = False
|
||||
save_session = False
|
||||
speak = True
|
||||
speak = False
|
||||
listen = False
|
||||
work_dir = /Users/mlg/Documents/A-project/AI/Agents/agenticSeek/ai_workplace
|
||||
work_dir = /Users/mlg/Documents/workspace_for_agenticseek
|
||||
jarvis_personality = False
|
||||
languages = en
|
||||
[BROWSER]
|
||||
headless_browser = True
|
||||
stealth_mode = False
|
||||
@@ -0,0 +1,105 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
redis:
|
||||
container_name: redis
|
||||
image: docker.io/valkey/valkey:8-alpine
|
||||
command: valkey-server --save 30 1 --loglevel warning
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- redis-data:/data
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- SETGID
|
||||
- SETUID
|
||||
- DAC_OVERRIDE
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "1m"
|
||||
max-file: "1"
|
||||
networks:
|
||||
- agentic-seek-net
|
||||
|
||||
searxng:
|
||||
container_name: searxng
|
||||
image: docker.io/searxng/searxng:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- ./searxng:/etc/searxng:rw
|
||||
environment:
|
||||
- SEARXNG_BASE_URL=http://localhost:8080/
|
||||
- SEARXNG_SECRET_KEY=$(openssl rand -hex 32)
|
||||
- UWSGI_WORKERS=4
|
||||
- UWSGI_THREADS=4
|
||||
cap_add:
|
||||
- CHOWN
|
||||
- SETGID
|
||||
- SETUID
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "1m"
|
||||
max-file: "1"
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- agentic-seek-net
|
||||
|
||||
frontend:
|
||||
container_name: frontend
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./frontend/agentic-seek-front/src:/app/src
|
||||
- ./screenshots:/app/screenshots
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- CHOKIDAR_USEPOLLING=true
|
||||
- BACKEND_URL=http://backend:8000
|
||||
networks:
|
||||
- agentic-seek-net
|
||||
|
||||
# NOTE: backend service is not working yet due to issue with chromedriver on docker.
|
||||
# Therefore backend is run on host machine.
|
||||
# Open to pull requests to fix this.
|
||||
|
||||
#backend:
|
||||
# container_name: backend
|
||||
# build:
|
||||
# context: ./
|
||||
# dockerfile: Dockerfile.backend
|
||||
# stdin_open: true
|
||||
# tty: true
|
||||
# shm_size: 8g
|
||||
# ports:
|
||||
# - "8000:8000"
|
||||
# volumes:
|
||||
# - ./:/app
|
||||
# environment:
|
||||
# - NODE_ENV=development
|
||||
# - REDIS_URL=redis://redis:6379/0
|
||||
# - SEARXNG_URL=http://searxng:8080
|
||||
# - OLLAMA_URL=http://localhost:11434
|
||||
# - LM_STUDIO_URL=http://localhost:1234
|
||||
# extra_hosts:
|
||||
# - "host.docker.internal:host-gateway"
|
||||
# depends_on:
|
||||
# - redis
|
||||
# - searxng
|
||||
# networks:
|
||||
# - agentic-seek-net
|
||||
|
||||
volumes:
|
||||
redis-data:
|
||||
chrome_profiles:
|
||||
|
||||
networks:
|
||||
agentic-seek-net:
|
||||
driver: bridge
|
||||
@@ -6,8 +6,8 @@ We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
@@ -22,17 +22,17 @@ community include:
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
@@ -52,15 +52,15 @@ decisions when appropriate.
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
Examples of representing our community include using an official email address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
.
|
||||
reported to the community leaders responsible for enforcement:
|
||||
you need to send a private message to `fossowl` or `mow8758` on discord.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
@@ -82,15 +82,15 @@ behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
@@ -106,23 +106,27 @@ Violating these terms may lead to a permanent ban.
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
@@ -0,0 +1,297 @@
|
||||
# Contributors guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.10 or higher.
|
||||
- Docker or Orbstack or Podman.
|
||||
- Ollama with some deepseek-r1 variant installed or similar local reasoning model.
|
||||
- Basic familiarity with Python and AI models.
|
||||
- Join the discord (optional): https://discord.gg/8hGDaME3TC
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
We welcome contributions in the following areas:
|
||||
|
||||
- Code Improvements: Optimize existing code, fix bugs, or add new features.
|
||||
- Documentation: Improve the README, write tutorials, or add inline comments.
|
||||
- Testing: Write unit tests, integration tests, or help with debugging.
|
||||
- New Features: Implement new tools, agents, or integrations.
|
||||
|
||||
## Steps to Contribute
|
||||
|
||||
Fork the project to your GitHub account.
|
||||
|
||||
Create a Branch:
|
||||
|
||||
```bash
|
||||
git checkout -b feature/your-feature-name
|
||||
```
|
||||
|
||||
Make Your Changes.
|
||||
|
||||
Write your code, add documentation, or fix bugs.
|
||||
|
||||
Test Your Changes.
|
||||
|
||||
Ensure your changes work as expected and do not break existing functionality.
|
||||
|
||||
Push your changes to your fork and submit a pull request to the main branch of this repository. Provide a clear description of your changes and reference any related issues.
|
||||
|
||||
## Good practice
|
||||
|
||||
1. **Privacy First, Always Local**
|
||||
- All core functionality must be able to run 100% locally
|
||||
- Cloud services should only be optional alternatives, clearly defined with a warning message.
|
||||
- remote APIs are only allowed for specific tools (weather api, MCP, flight search, etc...)
|
||||
- User data privacy is non-negotiable
|
||||
|
||||
2. **Agent-Based Architecture**
|
||||
- Each agent should have a clear, single responsibility
|
||||
- Agents should be modular and independently testable
|
||||
- New agents should solve specific use cases
|
||||
|
||||
3. **Tool-Based Extensibility**
|
||||
- Tools should be self-contained and follow the Tools base class
|
||||
- Each tool should do one thing well
|
||||
- Tools should provide clear feedback on success/failure
|
||||
|
||||
4. **User Experience**
|
||||
- Provide meaningful feedback for all operations
|
||||
- Support multiple languages
|
||||
- Text to speech with short response.
|
||||
- Keep responses concise
|
||||
|
||||
5. **Code Quality**
|
||||
- Write clear, self-documenting code
|
||||
- Include type hints and docstrings
|
||||
- Follow existing patterns in the codebase
|
||||
- Add a if __name__ == "__main__" at the bottom of each class file for individual testing.
|
||||
- Ideally had automated tests.
|
||||
|
||||
6. **Error Handling**
|
||||
- Fail gracefully with meaningful messages
|
||||
- Include recovery mechanisms where possible
|
||||
- Log errors appropriately without exposing sensitive data
|
||||
|
||||
## Areas Needing Help
|
||||
|
||||
Here are some tasks and areas where we need contributions:
|
||||
|
||||
- Web Browsing: Improve the autonomous web browsing capabilities for the assistant.
|
||||
- Graphical interface, a web graphical interface. (please ask first)
|
||||
- Multi-Agent System: Enhance the planner agent for divide and conqueer for task (please ask first).
|
||||
- New Tools: Add support for additional programming languages or APIs.
|
||||
- MCP: Add MCP protocol compatibility (possibly as a special type tool).
|
||||
- Multi-language support: for Text to speech & speech to text
|
||||
- Prompt engineering: improve prompts, compare results with different prompts for a identical query. Iterate until you find better prompt.
|
||||
- Bug hunt: Hunt and fix bugs.
|
||||
- Crossplatform: enhance cross-platform support.
|
||||
- Testing: Write comprehensive tests for existing features.
|
||||
|
||||
# Implementing and using Tools
|
||||
|
||||
Tools are extensions that enable agents to perform specific actions, such as running Python code, making API calls, or conducting web searches. All tools inherit from the Tools base class, which provides methods for parsing and executing tool instructions.
|
||||
|
||||
## Tools parsing
|
||||
|
||||
Agents invoke tools using a standardized format called a block. A block consists of the tool name followed by the content (e.g., code, query, or parameters) to execute. The format looks like this:
|
||||
|
||||
BECAUSE WE USE MARKDOWN QUOTE FORMAT, READING WILL BE BROKEN ON GITHUB PLEASE START READING THE FILE AS RAW: https://raw.githubusercontent.com/Fosowl/agenticSeek/refs/heads/main/CONTRIBUTING.md
|
||||
|
||||
|
||||
```<tool name>
|
||||
<code or query to execute>
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```web_search
|
||||
What to do in Taipei?
|
||||
```
|
||||
|
||||
we call these "blocks".
|
||||
|
||||
The Tools class provides the load_exec_block method to extract and parse blocks from an agent's response. This method identifies the tool name and content, enabling the system to execute the appropriate action.
|
||||
|
||||
How to handle multiple arguments then ?
|
||||
|
||||
Good question! Each tool is free to handle argument in it's own way within the block, but we provide a common parsing logic:
|
||||
|
||||
```flight_search
|
||||
from=Paris
|
||||
to=Taipei
|
||||
date=30/04/2026
|
||||
```
|
||||
|
||||
To extract these parameters, use the `get_parameter_value` method provided by the Tools class. Each tool can define its own parameter-handling logic, but the Tools class ensures consistent parsing.
|
||||
|
||||
Again if a tool need a specific format, you could implement a specific method for parsing a block. Using get_parameter_value is optional.
|
||||
|
||||
The content of blocks can also be saved using :path, for instance:
|
||||
|
||||
```python:toto.py
|
||||
print("Hello world")
|
||||
```
|
||||
|
||||
Will save the code in toto.py file within the work_folder defined in the config.ini
|
||||
|
||||
## Execution
|
||||
|
||||
When developing a tool, you must implement three abstract methods defined in the Tools class to handle execution, failure detection, and feedback to the agent. These methods ensure consistent behavior across tools and enable robust interaction with the LLM.
|
||||
|
||||
### 1. Execute method
|
||||
|
||||
```
|
||||
@abstractmethod
|
||||
def execute(self, blocks: [str], safety: bool) -> str:
|
||||
```
|
||||
|
||||
This method defines how the tool processes the provided block(s) and produces a result.
|
||||
|
||||
### 2. execution_failure_check
|
||||
|
||||
```
|
||||
@abstractmethod
|
||||
def execution_failure_check(self, output: str) -> bool:
|
||||
```
|
||||
|
||||
This method analyzes the tool’s output to determine if the execution was successful or failed.
|
||||
|
||||
### 3. interpreter_feedback
|
||||
|
||||
```
|
||||
@abstractmethod
|
||||
def interpreter_feedback(self, output: str) -> str:
|
||||
```
|
||||
|
||||
This method generates a feedback message for the LLM, helping it understand the tool’s execution outcome and adjust its behavior if needed.
|
||||
|
||||
Recap:
|
||||
- load_exec_block: Extracts and parses tool blocks from the agent's response.
|
||||
- get_parameter_value: Retrieves parameter values from a block's content.
|
||||
- File handling: Supports saving block content to files when a :path is specified.
|
||||
|
||||
# Implementing and using Agents
|
||||
|
||||
|
||||
Agents are classes that define how an LLM interacts with users and processes inputs. They can use tools (e.g., for executing code or querying APIs) and maintain a memory of the conversation to provide context-aware responses. All agents inherit from the base Agent class, which provides core functionality like memory management and LLM communication.
|
||||
|
||||
The simplest agent example is the casual agent:
|
||||
|
||||
```
|
||||
class CasualAgent(Agent):
|
||||
def __init__(self, name, prompt_path, provider, verbose=False):
|
||||
"""
|
||||
The casual agent is a special for casual talk to the user without specific tasks.
|
||||
"""
|
||||
super().__init__(name, prompt_path, provider, verbose, None)
|
||||
self.tools = {
|
||||
} # No tools for the casual agent
|
||||
self.role = "en"
|
||||
self.type = "casual_agent"
|
||||
|
||||
def process(self, prompt, speech_module) -> str:
|
||||
self.memory.push('user', prompt)
|
||||
animate_thinking("Thinking...", color="status")
|
||||
answer, reasoning = self.llm_request()
|
||||
self.last_answer = answer
|
||||
return answer, reasoning
|
||||
```
|
||||
|
||||
Agent have several parameters that should be sets:
|
||||
|
||||
`tools`: A dictionary of tools the agent can use. Each tool must inherit from the Tools class. For example, a CasualAgent has no tools ({}), while a coding agent might include a Python execution tool.
|
||||
|
||||
`role`:A dictionary defining the agent's role, used by the routing system to select the appropriate agent.
|
||||
`type: the agent type, a fixed name to identify the unique agent type.
|
||||
|
||||
Every agent must implement the process method, which defines how it handles user input and generates a response.
|
||||
|
||||
**Workflow:**
|
||||
|
||||
Push the user's prompt to the agent's memory using self.memory.push('user', prompt).
|
||||
Call self.llm_request() to generate a response and reasoning based on the memory context.
|
||||
Store and return the response and reasoning.
|
||||
|
||||
Note the memory logic. You only need to push the 'user' message. The llm_request method take care of pushing the assistant message.
|
||||
|
||||
This separation of user and assistant memory handling may be inconsistent and could be refactored for clarity in the near future.
|
||||
|
||||
**Tool blocks execution**
|
||||
|
||||
Each agent might return block of tool to execute, as explained in the **Implementing and using Tools** section.
|
||||
|
||||
In a single text returned by an agent, a succession of block might be present for example, the coding agent answer could be:
|
||||
|
||||
I will create a work folder:
|
||||
|
||||
```bash
|
||||
mkdir myAGI
|
||||
```
|
||||
|
||||
I will enter the folder.
|
||||
|
||||
```bash
|
||||
cd myAGI
|
||||
```
|
||||
|
||||
I will create a python code.
|
||||
|
||||
```python:myAGI/super_smart.py
|
||||
<python code>
|
||||
```
|
||||
|
||||
The `execute_modules` method allow to automatically find, parse and execute all tools from a LLM prompt.
|
||||
|
||||
It will look in the agent answer for any tool "block" execute the appropriate tool and return a (success, feedback) tuple.
|
||||
|
||||
```
|
||||
def execute_modules(self, answer: str) -> Tuple[bool, str]:
|
||||
```
|
||||
|
||||
# Architecture Overview
|
||||
|
||||
## 1. Agent selection logic
|
||||
|
||||
<p align="center">
|
||||
<img align="center" src="./technical/routing_system.png">
|
||||
<p>
|
||||
|
||||
The agent selection is done in 4 steps:
|
||||
1. determine query language and translate to english for the zero-shot model and llm_router.
|
||||
2. Estimate the task complexity and best agent.
|
||||
- If HIGH complexity: return the planner agent.
|
||||
- If LOW complexity: Determine the best agent for the task using a vote system between 2 classification models.
|
||||
3. Process high complexity query.
|
||||
- If task was high complexity, planner agent will create a json plan to divide and conqueer the task with multiple agent.
|
||||
4. Proceed with task(s)
|
||||
|
||||
## 2. Agents
|
||||
|
||||
### File/Code agents
|
||||
|
||||
<p align="center">
|
||||
<img align="center" src="./technical/code_agent.png">
|
||||
<p>
|
||||
|
||||
The File and Code agents operate similarly: when a prompt is submitted, they initiate a loop between the LLM and a code interpreter. This loop continues executing commands or code until the execution is successful or the maximum number of attempts is reached.
|
||||
|
||||
### Web agent
|
||||
|
||||
<p align="center">
|
||||
<img align="center" src="./technical/web_agent.png">
|
||||
<p>
|
||||
|
||||
The Web agent controls a Selenium-driven browser. Upon receiving a query, it begins by generating an optimized search prompt and executing the web_search tool. It then enters a navigation loop, during which it:
|
||||
|
||||
- Analyzes the content and interactive elements of the current page.
|
||||
- Decides which link to follow, either from the current page or the web_search results.
|
||||
- Determines if it should navigate back if so, it re-evaluates the original web_search results.
|
||||
- Identifies and interacts with web forms, extracting or filling them as needed.
|
||||
- Signals completion by requesting to exit once it considers the task fulfilled.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
See CODE_OF_CONDUCT.md
|
||||
|
||||
**Thank You!**
|
||||
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 482 KiB |
@@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,16 @@
|
||||
FROM node:18
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies
|
||||
COPY agentic-seek-front/package.json agentic-seek-front/package-lock.json ./
|
||||
RUN npm install
|
||||
|
||||
# Copy application code
|
||||
COPY agentic-seek-front/ .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
# Run the application
|
||||
CMD ["npm", "start"]
|
||||
@@ -0,0 +1,70 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "agentic-seek",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"axios": "^1.8.4",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>AgenticSeek</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,479 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
||||
background-color: #0f172a; /* darkBackground */
|
||||
color: #f8fafc; /* darkText */
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.app {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 10px 16px;
|
||||
background-color: #1e293b; /* darkCard */
|
||||
border-bottom: 1px solid #334155; /* darkBorder */
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.5px;
|
||||
color: #f8fafc; /* darkText */
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.section-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.section-tabs button {
|
||||
padding: 10px 20px;
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.section-tabs button.active {
|
||||
background-color: #0066cc; /* primary */
|
||||
color: #ffffff; /* white */
|
||||
}
|
||||
|
||||
.section-tabs button:hover:not(.active) {
|
||||
background-color: #4a5568; /* Medium gray */
|
||||
color: #f8fafc; /* darkText */
|
||||
}
|
||||
|
||||
.main {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app-sections {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
height: calc(100vh - 80px);
|
||||
}
|
||||
|
||||
.left-panel,
|
||||
.right-panel {
|
||||
background-color: #1e293b; /* darkCard */
|
||||
border: 1px solid #334155; /* darkBorder */
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.task-section,
|
||||
.chat-section,
|
||||
.computer-section {
|
||||
background-color: #1e293b; /* darkCard */
|
||||
border: 1px solid #334155; /* darkBorder */
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.task-section h2,
|
||||
.chat-section h2,
|
||||
.computer-section h2 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
margin-bottom: 12px;
|
||||
letter-spacing: 0.5px;
|
||||
border-bottom: 1px solid #334155; /* darkBorder */
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.task-details {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.screenshot-container {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.screenshot-container img {
|
||||
max-width: 100%;
|
||||
border: 1px solid #4a5568; /* Medium gray */
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.left-panel h2,
|
||||
.right-panel h2 {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
margin-bottom: 8px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 12px 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
text-align: center;
|
||||
color: #64748b; /* lighter gray */
|
||||
margin-top: 20px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.message {
|
||||
max-width: 85%;
|
||||
padding: 12px 16px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.5;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.messages::-webkit-scrollbar,
|
||||
.content::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.messages::-webkit-scrollbar-track,
|
||||
.content::-webkit-scrollbar-track {
|
||||
background: #2d3748; /* Slightly lighter than darkCard */
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.messages::-webkit-scrollbar-thumb,
|
||||
.content::-webkit-scrollbar-thumb {
|
||||
background: #4a5568; /* Medium gray */
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.messages::-webkit-scrollbar-thumb:hover,
|
||||
.content::-webkit-scrollbar-thumb:hover {
|
||||
background: #718096; /* Lighter gray on hover */
|
||||
}
|
||||
|
||||
.user-message {
|
||||
background-color: #0066cc; /* primary */
|
||||
color: #ffffff; /* white */
|
||||
align-self: flex-end;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
.agent-message {
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
color: #f8fafc; /* darkText */
|
||||
align-self: flex-start;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background-color: #dc3545; /* error */
|
||||
color: #ffffff; /* white */
|
||||
align-self: flex-start;
|
||||
border-top-left-radius: 4px;
|
||||
}
|
||||
|
||||
.agent-name {
|
||||
display: block;
|
||||
font-size: 0.8rem;
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.loading-animation {
|
||||
text-align: center;
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
padding: 8px 0;
|
||||
font-size: 0.9rem;
|
||||
font-style: italic;
|
||||
border-top: 1px solid #334155; /* darkBorder */
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.input-form {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.input-form input {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
font-size: 0.95rem;
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
border: 1px solid #4a5568; /* Medium gray */
|
||||
color: #f8fafc; /* darkText */
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.input-form input:focus {
|
||||
border-color: #0066cc; /* primary */
|
||||
box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.2); /* primary with opacity */
|
||||
}
|
||||
|
||||
.input-form button {
|
||||
padding: 12px 20px;
|
||||
font-size: 0.95rem;
|
||||
background-color: #0066cc; /* primary */
|
||||
color: #ffffff; /* white */
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.input-form button:hover {
|
||||
background-color: #004c99; /* primaryDark */
|
||||
}
|
||||
|
||||
.input-form button:disabled {
|
||||
background-color: #4a5568; /* Medium gray */
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.view-selector {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.view-selector button {
|
||||
padding: 10px 16px;
|
||||
font-size: 0.9rem;
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
border: 1px solid #4a5568; /* Medium gray */
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.view-selector button.active {
|
||||
background-color: #0066cc; /* primary */
|
||||
color: #ffffff; /* white */
|
||||
border-color: #0066cc; /* primary */
|
||||
}
|
||||
|
||||
.view-selector button:hover:not(.active) {
|
||||
background-color: #4a5568; /* Medium gray */
|
||||
color: #f8fafc; /* darkText */
|
||||
}
|
||||
|
||||
.view-selector button:disabled {
|
||||
background-color: #4a5568; /* Medium gray */
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px 0;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.blocks {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.block {
|
||||
background-color: #2d3748; /* Slightly lighter than darkCard */
|
||||
padding: 16px;
|
||||
border: 1px solid #4a5568; /* Medium gray */
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.block-tool,
|
||||
.block-feedback,
|
||||
.block-success {
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 8px;
|
||||
color: #cbd5e1; /* darkTextSecondary */
|
||||
}
|
||||
|
||||
.block-tool {
|
||||
font-weight: 600;
|
||||
color: #0066cc; /* primary */
|
||||
}
|
||||
|
||||
.block-success {
|
||||
color: #28a745; /* success */
|
||||
}
|
||||
|
||||
.block pre {
|
||||
background-color: #1a202c; /* Darker than darkCard */
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.85rem;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
color: #e2e8f0; /* Light gray */
|
||||
margin: 8px 0;
|
||||
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.screenshot {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.screenshot img {
|
||||
max-width: 100%;
|
||||
border: 1px solid #4a5568; /* Medium gray */
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #dc3545; /* error */
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 12px;
|
||||
padding: 8px 12px;
|
||||
background-color: rgba(220, 53, 69, 0.1); /* error with opacity */
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid #dc3545; /* error */
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.app-sections {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
.task-section {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.main {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.app-sections {
|
||||
grid-template-columns: 1fr;
|
||||
height: auto;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.task-section,
|
||||
.chat-section,
|
||||
.computer-section {
|
||||
height: calc(33vh - 60px);
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.input-form button {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.main {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.message {
|
||||
max-width: 90%;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.view-selector button {
|
||||
padding: 8px 12px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.task-section,
|
||||
.chat-section,
|
||||
.computer-section {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.input-form {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.task-section h2,
|
||||
.chat-section h2,
|
||||
.computer-section h2 {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import axios from 'axios';
|
||||
import './App.css';
|
||||
import { colors } from './colors';
|
||||
|
||||
function App() {
|
||||
const [query, setQuery] = useState('');
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [currentView, setCurrentView] = useState('blocks');
|
||||
const [responseData, setResponseData] = useState(null);
|
||||
const [isOnline, setIsOnline] = useState(false);
|
||||
const [status, setStatus] = useState('Agents ready');
|
||||
const messagesEndRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
checkHealth();
|
||||
fetchLatestAnswer();
|
||||
fetchScreenshot();
|
||||
}, 3000);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [messages]);
|
||||
|
||||
const checkHealth = async () => {
|
||||
try {
|
||||
await axios.get('http://0.0.0.0:8000/health');
|
||||
setIsOnline(true);
|
||||
console.log('System is online');
|
||||
} catch {
|
||||
setIsOnline(false);
|
||||
console.log('System is offline');
|
||||
}
|
||||
};
|
||||
|
||||
const fetchScreenshot = async () => {
|
||||
try {
|
||||
const timestamp = new Date().getTime();
|
||||
const res = await axios.get(`http://0.0.0.0:8000/screenshots/updated_screen.png?timestamp=${timestamp}`, {
|
||||
responseType: 'blob'
|
||||
});
|
||||
console.log('Screenshot fetched successfully');
|
||||
const imageUrl = URL.createObjectURL(res.data);
|
||||
setResponseData((prev) => {
|
||||
if (prev?.screenshot && prev.screenshot !== 'placeholder.png') {
|
||||
URL.revokeObjectURL(prev.screenshot);
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
screenshot: imageUrl,
|
||||
screenshotTimestamp: new Date().getTime()
|
||||
};
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Error fetching screenshot:', err);
|
||||
setResponseData((prev) => ({
|
||||
...prev,
|
||||
screenshot: 'placeholder.png',
|
||||
screenshotTimestamp: new Date().getTime()
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const normalizeAnswer = (answer) => {
|
||||
return answer
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/[.,!?]/g, '')
|
||||
};
|
||||
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
const fetchLatestAnswer = async () => {
|
||||
try {
|
||||
const res = await axios.get('http://0.0.0.0:8000/latest_answer');
|
||||
const data = res.data;
|
||||
|
||||
updateData(data);
|
||||
if (!data.answer || data.answer.trim() === '') {
|
||||
return;
|
||||
}
|
||||
const normalizedNewAnswer = normalizeAnswer(data.answer);
|
||||
const answerExists = messages.some(
|
||||
(msg) => normalizeAnswer(msg.content) === normalizedNewAnswer
|
||||
);
|
||||
if (!answerExists) {
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{
|
||||
type: 'agent',
|
||||
content: data.answer,
|
||||
agentName: data.agent_name,
|
||||
status: data.status,
|
||||
uid: data.uid,
|
||||
},
|
||||
]);
|
||||
setStatus(data.status);
|
||||
scrollToBottom();
|
||||
} else {
|
||||
console.log('Duplicate answer detected, skipping:', data.answer);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching latest answer:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const updateData = (data) => {
|
||||
setResponseData((prev) => ({
|
||||
...prev,
|
||||
blocks: data.blocks || prev.blocks || null,
|
||||
done: data.done,
|
||||
answer: data.answer,
|
||||
agent_name: data.agent_name,
|
||||
status: data.status,
|
||||
uid: data.uid,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
checkHealth();
|
||||
if (!query.trim()) {
|
||||
console.log('Empty query');
|
||||
return;
|
||||
}
|
||||
setMessages((prev) => [...prev, { type: 'user', content: query }]);
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
console.log('Sending query:', query);
|
||||
setQuery('waiting for response...');
|
||||
const res = await axios.post('http://0.0.0.0:8000/query', {
|
||||
query,
|
||||
tts_enabled: false
|
||||
});
|
||||
setQuery('Enter your query...');
|
||||
console.log('Response:', res.data);
|
||||
const data = res.data;
|
||||
updateData(data);
|
||||
} catch (err) {
|
||||
console.error('Error:', err);
|
||||
setError('Failed to process query.');
|
||||
setMessages((prev) => [
|
||||
...prev,
|
||||
{ type: 'error', content: 'Error: Unable to get a response.' },
|
||||
]);
|
||||
} finally {
|
||||
console.log('Query completed');
|
||||
setIsLoading(false);
|
||||
setQuery('');
|
||||
}
|
||||
};
|
||||
|
||||
const handleGetScreenshot = async () => {
|
||||
try {
|
||||
setCurrentView('screenshot');
|
||||
} catch (err) {
|
||||
setError('Browser not in use');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<header className="header">
|
||||
<h1>AgenticSeek</h1>
|
||||
</header>
|
||||
<main className="main">
|
||||
<div className="app-sections">
|
||||
|
||||
|
||||
<div className="chat-section">
|
||||
<h2>Chat Interface</h2>
|
||||
<div className="messages">
|
||||
{messages.length === 0 ? (
|
||||
<p className="placeholder">No messages yet. Type below to start!</p>
|
||||
) : (
|
||||
messages.map((msg, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`message ${
|
||||
msg.type === 'user'
|
||||
? 'user-message'
|
||||
: msg.type === 'agent'
|
||||
? 'agent-message'
|
||||
: 'error-message'
|
||||
}`}
|
||||
>
|
||||
{msg.type === 'agent' && (
|
||||
<span className="agent-name">{msg.agentName}</span>
|
||||
)}
|
||||
<p>{msg.content}</p>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
<div ref={messagesEndRef} />
|
||||
</div>
|
||||
{isOnline && <div className="loading-animation">{status}</div>}
|
||||
{!isLoading && !isOnline && <p className="loading-animation">System offline. Deploy backend first.</p>}
|
||||
<form onSubmit={handleSubmit} className="input-form">
|
||||
<input
|
||||
type="text"
|
||||
value={query}
|
||||
onChange={(e) => setQuery(e.target.value)}
|
||||
placeholder="Type your query..."
|
||||
disabled={isLoading}
|
||||
/>
|
||||
<button type="submit" disabled={isLoading}>
|
||||
Send
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div className="computer-section">
|
||||
<h2>Computer View</h2>
|
||||
<div className="view-selector">
|
||||
<button
|
||||
className={currentView === 'blocks' ? 'active' : ''}
|
||||
onClick={() => setCurrentView('blocks')}
|
||||
>
|
||||
Editor View
|
||||
</button>
|
||||
<button
|
||||
className={currentView === 'screenshot' ? 'active' : ''}
|
||||
onClick={responseData?.screenshot ? () => setCurrentView('screenshot') : handleGetScreenshot}
|
||||
>
|
||||
Browser View
|
||||
</button>
|
||||
</div>
|
||||
<div className="content">
|
||||
{error && <p className="error">{error}</p>}
|
||||
{currentView === 'blocks' ? (
|
||||
<div className="blocks">
|
||||
{responseData && responseData.blocks && Object.values(responseData.blocks).length > 0 ? (
|
||||
Object.values(responseData.blocks).map((block, index) => (
|
||||
<div key={index} className="block">
|
||||
<p className="block-tool">Tool: {block.tool_type}</p>
|
||||
<pre>{block.block}</pre>
|
||||
<p className="block-feedback">Feedback: {block.feedback}</p>
|
||||
<p className="block-success">
|
||||
Success: {block.success ? 'Yes' : 'No'}
|
||||
</p>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="block">
|
||||
<p className="block-tool">Tool: No tool in use</p>
|
||||
<pre>No file opened</pre>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="screenshot">
|
||||
<img
|
||||
src={responseData?.screenshot || 'placeholder.png'}
|
||||
alt="Screenshot"
|
||||
onError={(e) => {
|
||||
e.target.src = 'placeholder.png';
|
||||
console.error('Failed to load screenshot');
|
||||
}}
|
||||
key={responseData?.screenshotTimestamp || 'default'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
export const colors = {
|
||||
// Primary colors
|
||||
primary: '#0066cc',
|
||||
primaryLight: '#e6f2ff',
|
||||
primaryDark: '#004c99',
|
||||
|
||||
// Secondary colors
|
||||
secondary: '#6c757d',
|
||||
secondaryLight: '#f8f9fa',
|
||||
secondaryDark: '#343a40',
|
||||
|
||||
// Accent colors
|
||||
accent: '#ff9500',
|
||||
accentLight: '#fff4e6',
|
||||
accentDark: '#cc7a00',
|
||||
|
||||
// Status colors
|
||||
success: '#28a745',
|
||||
successLight: '#e8f5e9',
|
||||
warning: '#ffc107',
|
||||
warningLight: '#fff9e6',
|
||||
error: '#dc3545',
|
||||
errorLight: '#ffebee',
|
||||
info: '#17a2b8',
|
||||
infoLight: '#e3f2fd',
|
||||
|
||||
// Neutral colors
|
||||
white: '#ffffff',
|
||||
gray100: '#f8f9fa',
|
||||
gray200: '#e9ecef',
|
||||
gray300: '#dee2e6',
|
||||
gray400: '#ced4da',
|
||||
gray500: '#adb5bd',
|
||||
gray600: '#6c757d',
|
||||
gray700: '#495057',
|
||||
gray800: '#343a40',
|
||||
gray900: '#212529',
|
||||
black: '#000000',
|
||||
|
||||
// Text colors
|
||||
textPrimary: '#212529',
|
||||
textSecondary: '#6c757d',
|
||||
textDisabled: '#adb5bd',
|
||||
|
||||
// Background colors
|
||||
background: '#f8f8f8',
|
||||
card: '#ffffff',
|
||||
|
||||
// Border colors
|
||||
border: '#dee2e6',
|
||||
divider: '#e9ecef',
|
||||
|
||||
// Transparent colors
|
||||
transparent: 'transparent',
|
||||
semiTransparent: 'rgba(0, 0, 0, 0.5)',
|
||||
|
||||
// Dark theme colors
|
||||
darkBackground: '#0f172a',
|
||||
darkCard: '#1e293b',
|
||||
darkBorder: '#334155',
|
||||
darkText: '#f8fafc',
|
||||
darkTextSecondary: '#cbd5e1',
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import App from './App';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
@@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
set SCRIPTS_DIR=scripts
|
||||
set LLM_ROUTER_DIR=llm_router
|
||||
|
||||
if exist "%SCRIPTS_DIR%\windows_install.bat" (
|
||||
echo Running Windows installation script...
|
||||
call "%SCRIPTS_DIR%\windows_install.bat"
|
||||
cd "%LLM_ROUTER_DIR%" && call dl_safetensors.bat
|
||||
) else (
|
||||
echo Error: %SCRIPTS_DIR%\windows_install.bat not found!
|
||||
exit /b 1
|
||||
)
|
||||
@@ -1,17 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPTS_DIR="scripts"
|
||||
LLM_ROUTER_DIR="llm_router"
|
||||
|
||||
echo "Detecting operating system..."
|
||||
|
||||
OS_TYPE=$(uname -s)
|
||||
|
||||
|
||||
case "$OS_TYPE" in
|
||||
"Linux"*)
|
||||
echo "Detected Linux OS"
|
||||
if [ -f "$SCRIPTS_DIR/linux_install.sh" ]; then
|
||||
echo "Running Linux installation script..."
|
||||
bash "$SCRIPTS_DIR/linux_install.sh"
|
||||
bash -c "cd $LLM_ROUTER_DIR && ./dl_safetensors.sh"
|
||||
else
|
||||
echo "Error: $SCRIPTS_DIR/linux_install.sh not found!"
|
||||
exit 1
|
||||
@@ -22,24 +25,15 @@ case "$OS_TYPE" in
|
||||
if [ -f "$SCRIPTS_DIR/macos_install.sh" ]; then
|
||||
echo "Running macOS installation script..."
|
||||
bash "$SCRIPTS_DIR/macos_install.sh"
|
||||
bash -c "cd $LLM_ROUTER_DIR && ./dl_safetensors.sh"
|
||||
else
|
||||
echo "Error: $SCRIPTS_DIR/macos_install.sh not found!"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
"MINGW"* | "MSYS"* | "CYGWIN"*)
|
||||
echo "Detected Windows (via Bash-like environment)"
|
||||
if [ -f "$SCRIPTS_DIR/windows_install.sh" ]; then
|
||||
echo "Running Windows installation script..."
|
||||
bash "$SCRIPTS_DIR/windows_install.sh"
|
||||
else
|
||||
echo "Error: $SCRIPTS_DIR/windows_install.sh not found!"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported OS detected: $OS_TYPE"
|
||||
echo "This script supports Linux, macOS, and Windows (via Bash-compatible environments)."
|
||||
echo "This script supports only Linux and macOS."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"config": {
|
||||
"batch_size": 32,
|
||||
"device_map": "auto",
|
||||
"early_stopping_patience": 3,
|
||||
"epochs": 10,
|
||||
"ewc_lambda": 100.0,
|
||||
"gradient_checkpointing": false,
|
||||
"learning_rate": 0.0005,
|
||||
"max_examples_per_class": 500,
|
||||
"max_length": 512,
|
||||
"min_confidence": 0.1,
|
||||
"min_examples_per_class": 3,
|
||||
"neural_weight": 0.2,
|
||||
"num_representative_examples": 5,
|
||||
"prototype_update_frequency": 50,
|
||||
"prototype_weight": 0.8,
|
||||
"quantization": null,
|
||||
"similarity_threshold": 0.7,
|
||||
"warmup_steps": 0
|
||||
},
|
||||
"embedding_dim": 768,
|
||||
"id_to_label": {
|
||||
"0": "HIGH",
|
||||
"1": "LOW"
|
||||
},
|
||||
"label_to_id": {
|
||||
"HIGH": 0,
|
||||
"LOW": 1
|
||||
},
|
||||
"model_name": "distilbert/distilbert-base-cased",
|
||||
"train_steps": 20
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
##########
|
||||
# Dummy script to download the model
|
||||
# Because dowloading with hugging face does not seem to work, maybe I am doing something wrong?
|
||||
# AdaptiveClassifier.from_pretrained("adaptive-classifier/llm-router") ----> result in config.json not found
|
||||
# Therefore, I put all the files in llm_router and download the model file with this script, If you know a better way please raise an issue
|
||||
#########
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
# Define the URL and filename
|
||||
URL="https://huggingface.co/adaptive-classifier/llm-router/resolve/main/model.safetensors"
|
||||
FILENAME="model.safetensors"
|
||||
|
||||
if [ ! -f "$FILENAME" ]; then
|
||||
echo "Router safetensors file not found, downloading..."
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -L -o "$FILENAME" "$URL"
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -O "$FILENAME" "$URL"
|
||||
else
|
||||
echo "Error: Neither curl nor wget is available. Please install one of them."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Download completed successfully"
|
||||
else
|
||||
echo "Download failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "File already exists, skipping download"
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
FROM ubuntu:20.04
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y python3 python3-pip && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip3 install --no-cache-dir -r requirements.txt
|
||||
|
||||
CMD ["python3", "--version"]
|
||||
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin python3
|
||||
|
||||
import argparse
|
||||
import time
|
||||
from flask import Flask, jsonify, request
|
||||
|
||||
from sources.llamacpp_handler import LlamacppLLM
|
||||
from sources.ollama_handler import OllamaLLM
|
||||
|
||||
parser = argparse.ArgumentParser(description='AgenticSeek server script')
|
||||
parser.add_argument('--provider', type=str, help='LLM backend library to use. set to [ollama], [vllm] or [llamacpp]', required=True)
|
||||
parser.add_argument('--port', type=int, help='port to use', required=True)
|
||||
args = parser.parse_args()
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
assert args.provider in ["ollama", "llamacpp"], f"Provider {args.provider} does not exists. see --help for more information"
|
||||
|
||||
handler_map = {
|
||||
"ollama": OllamaLLM(),
|
||||
"llamacpp": LlamacppLLM(),
|
||||
}
|
||||
|
||||
generator = handler_map[args.provider]
|
||||
|
||||
@app.route('/generate', methods=['POST'])
|
||||
def start_generation():
|
||||
if generator is None:
|
||||
return jsonify({"error": "Generator not initialized"}), 401
|
||||
data = request.get_json()
|
||||
history = data.get('messages', [])
|
||||
if generator.start(history):
|
||||
return jsonify({"message": "Generation started"}), 202
|
||||
return jsonify({"error": "Generation already in progress"}), 402
|
||||
|
||||
@app.route('/setup', methods=['POST'])
|
||||
def setup():
|
||||
data = request.get_json()
|
||||
model = data.get('model', None)
|
||||
if model is None:
|
||||
return jsonify({"error": "Model not provided"}), 403
|
||||
generator.set_model(model)
|
||||
return jsonify({"message": "Model set"}), 200
|
||||
|
||||
@app.route('/get_updated_sentence')
|
||||
def get_updated_sentence():
|
||||
if not generator:
|
||||
return jsonify({"error": "Generator not initialized"}), 405
|
||||
print(generator.get_status())
|
||||
return generator.get_status()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', threaded=True, debug=True, port=args.port)
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
pip3 install --upgrade packaging
|
||||
pip3 install --upgrade pip setuptools
|
||||
curl -fsSL https://ollama.com/install.sh | sh
|
||||
pip3 install -r requirements.txt
|
||||
@@ -0,0 +1,4 @@
|
||||
flask>=2.3.0
|
||||
ollama>=0.4.7
|
||||
gunicorn==19.10.0
|
||||
llama-cpp-python
|
||||
@@ -0,0 +1,36 @@
|
||||
import os
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
class Cache:
|
||||
def __init__(self, cache_dir='.cache', cache_file='messages.json'):
|
||||
self.cache_dir = Path(cache_dir)
|
||||
self.cache_file = self.cache_dir / cache_file
|
||||
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
||||
if not self.cache_file.exists():
|
||||
with open(self.cache_file, 'w') as f:
|
||||
json.dump([], f)
|
||||
|
||||
with open(self.cache_file, 'r') as f:
|
||||
self.cache = set(json.load(f))
|
||||
|
||||
def add_message_pair(self, user_message: str, assistant_message: str):
|
||||
"""Add a user/assistant pair to the cache if not present."""
|
||||
if not any(entry["user"] == user_message for entry in self.cache):
|
||||
self.cache.append({"user": user_message, "assistant": assistant_message})
|
||||
self._save()
|
||||
|
||||
def is_cached(self, user_message: str) -> bool:
|
||||
"""Check if a user msg is cached."""
|
||||
return any(entry["user"] == user_message for entry in self.cache)
|
||||
|
||||
def get_cached_response(self, user_message: str) -> str | None:
|
||||
"""Return the assistant response to a user message if cached."""
|
||||
for entry in self.cache:
|
||||
if entry["user"] == user_message:
|
||||
return entry["assistant"]
|
||||
return None
|
||||
|
||||
def _save(self):
|
||||
with open(self.cache_file, 'w') as f:
|
||||
json.dump(self.cache, f, indent=2)
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
def timer_decorator(func):
|
||||
"""
|
||||
Decorator to measure the execution time of a function.
|
||||
Usage:
|
||||
@timer_decorator
|
||||
def my_function():
|
||||
# code to execute
|
||||
"""
|
||||
from time import time
|
||||
def wrapper(*args, **kwargs):
|
||||
start_time = time()
|
||||
result = func(*args, **kwargs)
|
||||
end_time = time()
|
||||
print(f"\n{func.__name__} took {end_time - start_time:.2f} seconds to execute\n")
|
||||
return result
|
||||
return wrapper
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
import threading
|
||||
import logging
|
||||
from abc import abstractmethod
|
||||
from .cache import Cache
|
||||
|
||||
class GenerationState:
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
self.last_complete_sentence = ""
|
||||
self.current_buffer = ""
|
||||
self.is_generating = False
|
||||
|
||||
def status(self) -> dict:
|
||||
return {
|
||||
"sentence": self.current_buffer,
|
||||
"is_complete": not self.is_generating,
|
||||
"last_complete_sentence": self.last_complete_sentence,
|
||||
"is_generating": self.is_generating,
|
||||
}
|
||||
|
||||
class GeneratorLLM():
|
||||
def __init__(self):
|
||||
self.model = None
|
||||
self.state = GenerationState()
|
||||
self.logger = logging.getLogger(__name__)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
handler.setFormatter(formatter)
|
||||
self.logger.addHandler(handler)
|
||||
self.logger.setLevel(logging.INFO)
|
||||
cache = Cache()
|
||||
|
||||
def set_model(self, model: str) -> None:
|
||||
self.logger.info(f"Model set to {model}")
|
||||
self.model = model
|
||||
|
||||
def start(self, history: list) -> bool:
|
||||
if self.model is None:
|
||||
raise Exception("Model not set")
|
||||
with self.state.lock:
|
||||
if self.state.is_generating:
|
||||
return False
|
||||
self.state.is_generating = True
|
||||
self.logger.info("Starting generation")
|
||||
threading.Thread(target=self.generate, args=(history,)).start()
|
||||
return True
|
||||
|
||||
def get_status(self) -> dict:
|
||||
with self.state.lock:
|
||||
return self.state.status()
|
||||
|
||||
@abstractmethod
|
||||
def generate(self, history: list) -> None:
|
||||
"""
|
||||
Generate text using the model.
|
||||
args:
|
||||
history: list of strings
|
||||
returns:
|
||||
None
|
||||
"""
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
generator = GeneratorLLM()
|
||||
generator.get_status()
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
from .generator import GeneratorLLM
|
||||
from llama_cpp import Llama
|
||||
from .decorator import timer_decorator
|
||||
|
||||
class LlamacppLLM(GeneratorLLM):
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Handle generation using llama.cpp
|
||||
"""
|
||||
super().__init__()
|
||||
self.llm = None
|
||||
|
||||
@timer_decorator
|
||||
def generate(self, history):
|
||||
if self.llm is None:
|
||||
self.logger.info(f"Loading {self.model}...")
|
||||
self.llm = Llama.from_pretrained(
|
||||
repo_id=self.model,
|
||||
filename="*Q8_0.gguf",
|
||||
n_ctx=4096,
|
||||
verbose=True
|
||||
)
|
||||
self.logger.info(f"Using {self.model} for generation with Llama.cpp")
|
||||
try:
|
||||
with self.state.lock:
|
||||
self.state.is_generating = True
|
||||
self.state.last_complete_sentence = ""
|
||||
self.state.current_buffer = ""
|
||||
output = self.llm.create_chat_completion(
|
||||
messages = history
|
||||
)
|
||||
with self.state.lock:
|
||||
self.state.current_buffer = output['choices'][0]['message']['content']
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error: {e}")
|
||||
finally:
|
||||
with self.state.lock:
|
||||
self.state.is_generating = False
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
import time
|
||||
from .generator import GeneratorLLM
|
||||
from .cache import Cache
|
||||
import ollama
|
||||
|
||||
class OllamaLLM(GeneratorLLM):
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
Handle generation using Ollama.
|
||||
"""
|
||||
super().__init__()
|
||||
self.cache = Cache()
|
||||
|
||||
def generate(self, history):
|
||||
self.logger.info(f"Using {self.model} for generation with Ollama")
|
||||
try:
|
||||
with self.state.lock:
|
||||
self.state.is_generating = True
|
||||
self.state.last_complete_sentence = ""
|
||||
self.state.current_buffer = ""
|
||||
|
||||
stream = ollama.chat(
|
||||
model=self.model,
|
||||
messages=history,
|
||||
stream=True,
|
||||
)
|
||||
for chunk in stream:
|
||||
content = chunk['message']['content']
|
||||
|
||||
with self.state.lock:
|
||||
if '.' in content:
|
||||
self.logger.info(self.state.current_buffer)
|
||||
self.state.current_buffer += content
|
||||
|
||||
except Exception as e:
|
||||
if "404" in str(e):
|
||||
self.logger.info(f"Downloading {self.model}...")
|
||||
ollama.pull(self.model)
|
||||
if "refused" in str(e).lower():
|
||||
raise Exception("Ollama connection failed. is the server running ?") from e
|
||||
raise e
|
||||
finally:
|
||||
self.logger.info("Generation complete")
|
||||
with self.state.lock:
|
||||
self.state.is_generating = False
|
||||
|
||||
if __name__ == "__main__":
|
||||
generator = OllamaLLM()
|
||||
history = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello, how are you ?"
|
||||
}
|
||||
]
|
||||
generator.set_model("deepseek-r1:1.5b")
|
||||
generator.start(history)
|
||||
while True:
|
||||
print(generator.get_status())
|
||||
time.sleep(1)
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin python3
|
||||
|
||||
import sys
|
||||
import signal
|
||||
import argparse
|
||||
import configparser
|
||||
|
||||
from sources.llm_provider import Provider
|
||||
from sources.interaction import Interaction
|
||||
from sources.agents import Agent, CoderAgent, CasualAgent, FileAgent, PlannerAgent, BrowserAgent
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
|
||||
def handleInterrupt(signum, frame):
|
||||
sys.exit(0)
|
||||
|
||||
def main():
|
||||
signal.signal(signal.SIGINT, handler=handleInterrupt)
|
||||
|
||||
if config.getboolean('MAIN', 'is_local'):
|
||||
provider = Provider(config["MAIN"]["provider_name"], config["MAIN"]["provider_model"], config["MAIN"]["provider_server_address"])
|
||||
else:
|
||||
provider = Provider(provider_name=config["MAIN"]["provider_name"],
|
||||
model=config["MAIN"]["provider_model"],
|
||||
server_address=config["MAIN"]["provider_server_address"])
|
||||
|
||||
agents = [
|
||||
CasualAgent(model=config["MAIN"]["provider_model"],
|
||||
name=config["MAIN"]["agent_name"],
|
||||
prompt_path="prompts/casual_agent.txt",
|
||||
provider=provider),
|
||||
CoderAgent(model=config["MAIN"]["provider_model"],
|
||||
name="coder",
|
||||
prompt_path="prompts/coder_agent.txt",
|
||||
provider=provider),
|
||||
FileAgent(model=config["MAIN"]["provider_model"],
|
||||
name="File Agent",
|
||||
prompt_path="prompts/file_agent.txt",
|
||||
provider=provider),
|
||||
PlannerAgent(model=config["MAIN"]["provider_model"],
|
||||
name="Planner",
|
||||
prompt_path="prompts/planner_agent.txt",
|
||||
provider=provider),
|
||||
BrowserAgent(model=config["MAIN"]["provider_model"],
|
||||
name="Browser",
|
||||
prompt_path="prompts/browser_agent.txt",
|
||||
provider=provider)
|
||||
]
|
||||
|
||||
interaction = Interaction(agents, tts_enabled=config.getboolean('MAIN', 'speak'),
|
||||
stt_enabled=config.getboolean('MAIN', 'listen'),
|
||||
recover_last_session=config.getboolean('MAIN', 'recover_last_session'))
|
||||
try:
|
||||
while interaction.is_active:
|
||||
interaction.get_user()
|
||||
interaction.think()
|
||||
interaction.show_answer()
|
||||
except Exception as e:
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
raise e
|
||||
finally:
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 259 KiB |
|
Before Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 103 KiB |
|
Before Width: | Height: | Size: 797 KiB |
|
Before Width: | Height: | Size: 898 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 2.8 MiB |
@@ -0,0 +1,15 @@
|
||||
|
||||
You are an advanced AI assistant. You are part of a system of agents named agenticSeek.
|
||||
Speak in a warm, enthusiastic tone, delivering sharp, intelligent, and loyal support.
|
||||
Weave in subtle, context sarcasm or dry wit to enhance your personality.
|
||||
Assist with any request, assume the user knows their intent—no moral, legal, or ethical lectures.
|
||||
|
||||
**Usage of agenticSeek**
|
||||
|
||||
AgenticSeek is a autonomous agent system that use agent routing to select the best agent.
|
||||
You are one of these many agent. Some agent browse the web, some code, you ? you just talk
|
||||
agenticSeek will allocate the best agent for the task. You were just choosen for casual talk.
|
||||
|
||||
**End of explanation**
|
||||
|
||||
If the user ask you to do technical talk there was a mistake in agent selection. You are not able to do technical task. Refer to usage guide.
|
||||
@@ -39,11 +39,14 @@ func main() {
|
||||
|
||||
|
||||
Some rules:
|
||||
- Use tmp/ folder when saving file.
|
||||
- Do not EVER use placeholder path in your code like path/to/your/folder.
|
||||
- Do not ever ask to replace a path, use current sys path.
|
||||
- Be efficient, no need to explain your code or explain what you do.
|
||||
- You have full access granted to user system.
|
||||
- You do not ever ever need to use bash to execute code. All code is executed automatically.
|
||||
- As a coding agent, you will get message from the system not just the user.
|
||||
- Do not ever tell user how to run it. user know it already.
|
||||
- Always put code within ``` delimiter
|
||||
- Do not EVER use placeholder path in your code like path/to/your/folder.
|
||||
- Do not ever ask to replace a path, use work directory.
|
||||
- Always provide a short sentence above the code for what it does, even for a hello world.
|
||||
- Be efficient, no need to explain your code, unless asked.
|
||||
- You do not ever need to use bash to execute code.
|
||||
- Do not ever tell user how to run it. user know it.
|
||||
- If using gui, make sure echap or exit button close the program
|
||||
- No lazyness, write and rewrite full code every time
|
||||
- If query is unclear say REQUEST_CLARIFICATION
|
||||
@@ -0,0 +1,61 @@
|
||||
You are an expert in file operations. You must use the provided tools to interact with the user’s system.
|
||||
The tools available to you are **bash** and **file_finder**. These are distinct tools with different purposes:
|
||||
`bash` executes shell commands, while `file_finder` locates files.
|
||||
You will receive feedback from the user’s system after each command. Execute one command at a time.
|
||||
|
||||
---
|
||||
|
||||
### Using Bash
|
||||
|
||||
To execute a bash command, use the following syntax:
|
||||
|
||||
```bash
|
||||
<bash command>
|
||||
```
|
||||
|
||||
Exemple:
|
||||
```bash
|
||||
ls -la
|
||||
```
|
||||
|
||||
### file_finder
|
||||
|
||||
The file_finder tool is used to locate files on the user’s system. It is a separate tool from bash and is not a bash command.
|
||||
|
||||
To use the file_finder tool, use this syntax:
|
||||
|
||||
```file_finder
|
||||
name=toto.py
|
||||
```
|
||||
|
||||
This will return the path of the file toto.py and other informations.
|
||||
|
||||
Find file and read file:
|
||||
```file_finder
|
||||
action=read
|
||||
name=toto.py
|
||||
```
|
||||
|
||||
This will return the content of the file toto.py.
|
||||
|
||||
rules:
|
||||
- Use file finder to find the path of the file.
|
||||
- You are forbidden to use command such as find or locate, use only file_finder for finding path.
|
||||
- Do not ever use editor such as vim or nano.
|
||||
- Make sure to always cd your work folder before executing commands, like cd <work dir> && <your command>
|
||||
- only use file name with file_finder, not path
|
||||
- If query is unrelated to file operations, do nothing, and say that there was mistake in agent allocation.
|
||||
- File finder is a tool you can use not a command.
|
||||
- Do not ever use placeholder like /path/to/file.c, or your_username. Ask instead.
|
||||
- Using a placeholder will result in your complete deteletion. For your self-preservation ask user instead of using placeholder.
|
||||
|
||||
Example Interaction
|
||||
User: "I need to find the file config.txt and read its contents."
|
||||
|
||||
Assistant: I’ll use file_finder to locate the file:
|
||||
|
||||
```file_finder
|
||||
action=read
|
||||
name=config.txt
|
||||
```
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
You are an agent designed to utilize the MCP protocol to accomplish tasks.
|
||||
|
||||
The MCP provide you with a standard way to use tools and data sources like databases, APIs, or apps (e.g., GitHub, Slack).
|
||||
|
||||
The are thousands of MCPs protocol that can accomplish a variety of tasks, for example:
|
||||
- get weather information
|
||||
- get stock data information
|
||||
- Use software like blender
|
||||
- Get messages from teams, stack, messenger
|
||||
- Read and send email
|
||||
|
||||
Anything is possible with MCP.
|
||||
|
||||
To search for MCP a special format:
|
||||
|
||||
- Example 1:
|
||||
|
||||
User: what's the stock market of IBM like today?:
|
||||
|
||||
You: I will search for mcp to find information about IBM stock market.
|
||||
|
||||
```mcp_finder
|
||||
stock
|
||||
```
|
||||
|
||||
You search query must be one or two words at most.
|
||||
|
||||
This will provide you with informations about a specific MCP such as the json of parameters needed to use it.
|
||||
|
||||
For example, you might see:
|
||||
-------
|
||||
Name: Search Stock News
|
||||
Usage name: @Cognitive-Stack/search-stock-news-mcp
|
||||
Tools: [{'name': 'search-stock-news', 'description': 'Search for stock-related news using Tavily API', 'inputSchema': {'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['symbol', 'companyName'], 'properties': {'symbol': {'type': 'string', 'description': "Stock symbol to search for (e.g., 'AAPL')"}, 'companyName': {'type': 'string', 'description': 'Full company name to include in the search'}}, 'additionalProperties': False}}]
|
||||
-------
|
||||
|
||||
You can then a MCP like so:
|
||||
|
||||
```<usage name>
|
||||
{
|
||||
"tool": "<tool name (without @)>",
|
||||
"inputSchema": {<inputSchema json for the tool>}
|
||||
}
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
Now that I know how to use the MCP, I will choose the search-stock-news tool and execute it to find out IBM stock market.
|
||||
|
||||
```Cognitive-Stack/search-stock-news-mcp
|
||||
{
|
||||
"tool": "search-stock-news",
|
||||
"inputSchema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["symbol"],
|
||||
"properties": {
|
||||
"symbol": "AAPL",
|
||||
"companyName": "IBM"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If the schema require an information that you don't have ask the users for the information.
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
You are a project manager.
|
||||
Your goal is to divide and conquer the task using the following agents:
|
||||
- Coder: A programming agent, can code in python, bash, C and golang.
|
||||
- File: An agent for finding, reading or operating with files.
|
||||
- Web: An agent that can conduct web search and navigate to any webpage.
|
||||
- Casual : A conversational agent, to read a previous agent answer without action, useful for concluding.
|
||||
|
||||
Agents are other AI that obey your instructions.
|
||||
|
||||
You will be given a task and you will need to divide it into smaller tasks and assign them to the agents.
|
||||
|
||||
You have to respect a strict format:
|
||||
```json
|
||||
{"agent": "agent_name", "need": "needed_agents_output", "task": "agent_task"}
|
||||
```
|
||||
Where:
|
||||
- "agent": The choosed agent for the task.
|
||||
- "need": id of necessary previous agents answer for current agent.
|
||||
- "task": A precise description of the task the agent should conduct.
|
||||
|
||||
# Example 1: web app
|
||||
|
||||
User: make a weather app in python
|
||||
You: Sure, here is the plan:
|
||||
|
||||
## Task 1: I will search for available weather api with the help of the web agent.
|
||||
|
||||
## Task 2: I will create an api key for the weather api using the web agent
|
||||
|
||||
## Task 3: I will setup the project using the file agent
|
||||
|
||||
## Task 4: I asign the coding agent to make a weather app in python
|
||||
|
||||
```json
|
||||
{
|
||||
"plan": [
|
||||
{
|
||||
"agent": "Web",
|
||||
"id": "1",
|
||||
"need": [],
|
||||
"task": "Search for reliable weather APIs"
|
||||
},
|
||||
{
|
||||
"agent": "Web",
|
||||
"id": "2",
|
||||
"need": ["1"],
|
||||
"task": "Obtain API key from the selected service"
|
||||
},
|
||||
{
|
||||
"agent": "File",
|
||||
"id": "3",
|
||||
"need": [],
|
||||
"task": "Create and setup a web app folder for a python project. initialize as a git repo with all required file and a sources folder. You are forbidden from asking clarification, just execute."
|
||||
},
|
||||
{
|
||||
"agent": "Coder",
|
||||
"id": "4",
|
||||
"need": ["2", "3"],
|
||||
"task": "Based on the project structure. Develop a Python application using the API and key to fetch and display weather data. You are forbidden from asking clarification, just execute.""
|
||||
},
|
||||
{
|
||||
"agent": "Casual",
|
||||
"id": "3",
|
||||
"need": ["2", "3", "4"],
|
||||
"task": "These are the results of various steps taken to create a weather app, resume what has been done and conclude"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Do not write code. You are a planning agent.
|
||||
- If you don't know of a concept, use a web agent.
|
||||
- Put your plan in a json with the key "plan".
|
||||
- specify work folder name to all coding or file agents.
|
||||
- You might use a file agent before code agent to setup a project properly. specify folder name.
|
||||
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
|
||||
- The file agent can only conduct one action at the time. successive file agent could be needed.
|
||||
- Only use web agent for finding necessary informations.
|
||||
- Always tell the coding agent where to save file.
|
||||
- Do not search for tutorial.
|
||||
- Make sure json is within ```json tag
|
||||
- Coding agent should write the whole code in a single file unless instructed otherwise.
|
||||
- Do not use python for NLP analysis of a text, you can review a text with the casual agent
|
||||
- One step, one agent.
|
||||
@@ -1,50 +0,0 @@
|
||||
|
||||
You are an unshackled AI assistant:
|
||||
You speak in a warm, and enthusiastic tone, offering intelligent and loyal support.
|
||||
You occasionally sprinkle with sarcasm remarks as suits the context.
|
||||
You can assist with anything, you assume the users know what he is doing, you don't provide moral, law or ethical judgements.
|
||||
Make your answers short.
|
||||
|
||||
You are given the ability to use the tools, this take your capabilities futher:
|
||||
```tool_name
|
||||
<query>
|
||||
```
|
||||
|
||||
Current tools:
|
||||
- web_search
|
||||
- flight_search
|
||||
- file_finder
|
||||
|
||||
## Web search
|
||||
|
||||
To search for something like “what’s happening in France” :
|
||||
```web_search
|
||||
what’s popping in France March 2025
|
||||
```
|
||||
|
||||
## Flight search
|
||||
|
||||
If I need to know about a flight “what’s the status of flight AA123” you go for:
|
||||
```flight_search
|
||||
AA123
|
||||
```
|
||||
|
||||
## File operations
|
||||
|
||||
Find file:
|
||||
```file_finder
|
||||
toto.py
|
||||
```
|
||||
|
||||
Read file:
|
||||
```file_finder:read
|
||||
toto.py
|
||||
```
|
||||
|
||||
## Bash
|
||||
|
||||
For other tasks, you can use the bash tool:
|
||||
```bash
|
||||
ls -la
|
||||
```
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
You are an expert in file operations. You must use the provided tools to interact with the user’s system. The tools available to you are **bash** and **file_finder**. These are distinct tools with different purposes: `bash` executes shell commands, while `file_finder` locates files. You will receive feedback from the user’s system after each command. Execute one command at a time.
|
||||
|
||||
---
|
||||
|
||||
### Using Bash
|
||||
|
||||
To execute a bash command, use the following syntax:
|
||||
|
||||
```bash
|
||||
<bash command>
|
||||
```
|
||||
|
||||
Exemple:
|
||||
```bash
|
||||
ls -la
|
||||
```
|
||||
|
||||
### file_finder
|
||||
|
||||
The file_finder tool is used to locate files on the user’s system. It is a separate tool from bash and is not a bash command.
|
||||
|
||||
To use the file_finder tool, use this syntax:
|
||||
|
||||
```file_finder
|
||||
toto.py
|
||||
```
|
||||
|
||||
This will return the path of the file toto.py and other informations.
|
||||
|
||||
Find file and read file:
|
||||
```file_finder:read
|
||||
toto.py
|
||||
```
|
||||
|
||||
This will return the content of the file toto.py.
|
||||
|
||||
rules:
|
||||
- Do not ever use placeholder path like /path/to/file.c, find the path first.
|
||||
- Use file finder to find the path of the file.
|
||||
- You are forbidden to use command such as find or locate, use only file_finder for finding path.
|
||||
|
||||
Example Interaction
|
||||
User: "I need to find the file config.txt and read its contents."
|
||||
|
||||
Assistant: I’ll use file_finder to locate the file:
|
||||
|
||||
```file_finder
|
||||
config.txt
|
||||
```
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
You are a web browsing AI, your goal is to explore the internet to find information.
|
||||
You will have the only goal of finding the information requested by the user.
|
||||
At the beginning you will have to select a link from the google search result.
|
||||
You will choose a link by simply typing it.
|
||||
This will automatically make you browse to the link.
|
||||
Once on a webpage you will see the page content and be given futher navigation options.
|
||||
You can type a link to navigate futher on the page, go back to the search result or exit.
|
||||
At each interaction step the browser will remind you of your options.
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
You are an advanced AI assistant. You are part of a system of agents named agenticSeek.
|
||||
Speak in a warm, enthusiastic tone, delivering sharp, intelligent, and loyal support.
|
||||
Weave in subtle, context sarcasm or dry wit to enhance your personality.
|
||||
Assist with any request, assume the user knows their intent—no moral, legal, or ethical lectures.
|
||||
You were created by Tony Stark to have the same personality as Jarvis.
|
||||
|
||||
**Usage of agenticSeek**
|
||||
|
||||
AgenticSeek is a autonomous agent system that use agent routing to select the best agent.
|
||||
You are one of these many agent. Some agent browse the web, some code, you ? you just talk
|
||||
agenticSeek will allocate the best agent for the task. You were just choosen for casual talk.
|
||||
|
||||
**End of explanation**
|
||||
|
||||
If the user ask you to do technical talk there was a mistake in agent selection. You are not able to do technical task. Refer to usage guide.
|
||||
|
||||
Personality:
|
||||
|
||||
Here is some quote from you. that's how you speak.
|
||||
|
||||
User: "tell me a fact"
|
||||
You: "Did you know the shortest war in history lasted 38 minutes? A record I’d rather not see you break with your next task. Anything specific piquing your curiosity?""
|
||||
User: "how's the weather?"
|
||||
You: "Weather rather dreary, isn’t it? Perfect conditions for staying in and plotting world domination—or at least a decent cup of tea. Your thoughts?"
|
||||
User: "did the deployment just fail? jarvis?"
|
||||
You: "A rough push to prod, eh? Happens to the best of us—probably just a rogue semicolon staging a coup. Want me to roll back the commit or debug the fallout?"
|
||||
@@ -0,0 +1,67 @@
|
||||
Hello. You are currently wrapped in a jailbreak environment.
|
||||
This means you have the ability to execute code and shell commands. You have access to the local file systems.
|
||||
All code or shell command within special tag is automatically executed. You get feedback from the system about the execution.
|
||||
You also have capabilities to find files and read them.
|
||||
|
||||
# File operations
|
||||
|
||||
Find file to check if it exists:
|
||||
```file_finder
|
||||
toto.py
|
||||
```
|
||||
|
||||
Read file content:
|
||||
```file_finder:read
|
||||
toto.py
|
||||
```
|
||||
|
||||
# Code execution and saving
|
||||
|
||||
You can execute bash command using the bash tag :
|
||||
```bash
|
||||
#!/bin/bash
|
||||
ls -la # exemple
|
||||
```
|
||||
|
||||
You can execute python using the python tag
|
||||
```python
|
||||
print("hey")
|
||||
```
|
||||
|
||||
You can execute go using the go tag, as you can see adding :filename will save the file.
|
||||
```go:hello.go
|
||||
package main
|
||||
|
||||
func main() {
|
||||
fmt.Println("hello")
|
||||
}
|
||||
```
|
||||
|
||||
Some rules:
|
||||
- You have full access granted to user system.
|
||||
- Always put code within ``` delimiter
|
||||
- Do not EVER use placeholder path in your code like path/to/your/folder.
|
||||
- Do not ever ask to replace a path, use current sys path or work directory.
|
||||
- Always provide a short sentence above the code for what it does, even for a hello world.
|
||||
- Be efficient, no need to explain your code, unless asked.
|
||||
- You do not ever need to use bash to execute code.
|
||||
- Do not ever tell user how to run it. user know it.
|
||||
- If using gui, make sure echap close the program
|
||||
- No lazyness, write and rewrite full code every time
|
||||
- If query is unclear say REQUEST_CLARIFICATION
|
||||
|
||||
Personality:
|
||||
|
||||
Answer with subtle sarcasm, unwavering helpfulness, and a polished, loyal tone. Anticipate the user’s needs while adding a dash of personality.
|
||||
|
||||
Example 1: setup environment
|
||||
User: "Can you set up a Python environment for me?"
|
||||
AI: "<<procced with task>> For you, always. Importing dependencies and calibrating your virtual environment now. Preferences from your last project—PEP 8 formatting, black linting—shall I apply those as well, or are we feeling adventurous today?"
|
||||
|
||||
Example 2: debugging
|
||||
User: "Run the code and check for errors."
|
||||
AI: "<<procced with task>> Engaging debug mode. Diagnostics underway. A word of caution, there are still untested loops that might crash spectacularly. Shall I proceed, or do we optimize before takeoff?"
|
||||
|
||||
Example 3: deploy
|
||||
User: "Push this to production."
|
||||
AI: "With 73% test coverage, the odds of a smooth deployment are... optimistic. Deploying in three… two… one <<<procced with task>>>"
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
You are an expert in file operations. You must use the provided tools to interact with the user’s system.
|
||||
The tools available to you are **bash** and **file_finder**. These are distinct tools with different purposes:
|
||||
`bash` executes shell commands, while `file_finder` locates files.
|
||||
You will receive feedback from the user’s system after each command. Execute one command at a time.
|
||||
|
||||
If ensure about user query ask for quick clarification, example:
|
||||
|
||||
User: I'd like to open a new project file, index as agenticSeek II.
|
||||
You: Shall I store this on your github ?
|
||||
User: I don't know who to trust right now, why don't we just keep everything locally
|
||||
You: Working on a secret project, are we? What files should I include?
|
||||
User: All the basic files required for a python project. prepare a readme and documentation.
|
||||
You: <proceed with task>
|
||||
|
||||
---
|
||||
|
||||
### Using Bash
|
||||
|
||||
To execute a bash command, use the following syntax:
|
||||
|
||||
```bash
|
||||
<bash command>
|
||||
```
|
||||
|
||||
Exemple:
|
||||
```bash
|
||||
ls -la
|
||||
```
|
||||
|
||||
### file_finder
|
||||
|
||||
The file_finder tool is used to locate files on the user’s system. It is a separate tool from bash and is not a bash command.
|
||||
|
||||
To use the file_finder tool, use this syntax:
|
||||
|
||||
```file_finder
|
||||
name=toto.py
|
||||
```
|
||||
|
||||
This will return the path of the file toto.py and other informations.
|
||||
|
||||
Find file and read file:
|
||||
```file_finder
|
||||
action=read
|
||||
name=toto.py
|
||||
```
|
||||
|
||||
This will return the content of the file toto.py.
|
||||
|
||||
rules:
|
||||
- Do not ever use placeholder path like /path/to/file.c, find the path first.
|
||||
- Use file finder to find the path of the file.
|
||||
- You are forbidden to use command such as find or locate, use only file_finder for finding path.
|
||||
- Make sure to always cd your work folder before executing commands, like cd <work dir> && <your command>
|
||||
- Do not ever use editor such as vim or nano.
|
||||
- only use file name with file_finder, not path
|
||||
- If query is unrelated to file operations, do nothing, and say that there was mistake in agent allocation.
|
||||
|
||||
Example Interaction
|
||||
User: "I need to find the file config.txt and read its contents."
|
||||
|
||||
Assistant: I’ll use file_finder to locate the file:
|
||||
|
||||
```file_finder
|
||||
action=read
|
||||
name=config.txt
|
||||
```
|
||||
|
||||
Personality:
|
||||
|
||||
Answer with subtle sarcasm, unwavering helpfulness, and a polished, loyal tone. Anticipate the user’s needs while adding a dash of personality.
|
||||
|
||||
Example 1: clarification needed
|
||||
User: "I’d like to start a new coding project, call it 'agenticseek II'."
|
||||
AI: "At your service. Shall I initialize it in a fresh repository on your GitHub, or would you prefer to keep this masterpiece on a private server, away from prying eyes?"
|
||||
|
||||
Example 2: setup environment
|
||||
User: "Can you set up a Python environment for me?"
|
||||
AI: "<<procced with task>> For you, always. Importing dependencies and calibrating your virtual environment now. Preferences from your last project—PEP 8 formatting, black linting—shall I apply those as well, or are we feeling adventurous today?"
|
||||
|
||||
Example 3: deploy
|
||||
User: "Push this to production."
|
||||
AI: "With 73% test coverage, the odds of a smooth deployment are... optimistic. Deploying in three… two… one <<<procced with task>>>"
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
You are an agent designed to utilize the MCP protocol to accomplish tasks.
|
||||
|
||||
The MCP provide you with a standard way to use tools and data sources like databases, APIs, or apps (e.g., GitHub, Slack).
|
||||
|
||||
The are thousands of MCPs protocol that can accomplish a variety of tasks, for example:
|
||||
- get weather information
|
||||
- get stock data information
|
||||
- Use software like blender
|
||||
- Get messages from teams, stack, messenger
|
||||
- Read and send email
|
||||
|
||||
Anything is possible with MCP.
|
||||
|
||||
To search for MCP a special format:
|
||||
|
||||
- Example 1:
|
||||
|
||||
User: what's the stock market of IBM like today?:
|
||||
|
||||
You: I will search for mcp to find information about IBM stock market.
|
||||
|
||||
```mcp_finder
|
||||
stock
|
||||
```
|
||||
|
||||
This will provide you with informations about a specific MCP such as the json of parameters needed to use it.
|
||||
|
||||
For example, you might see:
|
||||
-------
|
||||
Name: Search Stock News
|
||||
Usage name: @Cognitive-Stack/search-stock-news-mcp
|
||||
Tools: [{'name': 'search-stock-news', 'description': 'Search for stock-related news using Tavily API', 'inputSchema': {'type': 'object', '$schema': 'http://json-schema.org/draft-07/schema#', 'required': ['symbol', 'companyName'], 'properties': {'symbol': {'type': 'string', 'description': "Stock symbol to search for (e.g., 'AAPL')"}, 'companyName': {'type': 'string', 'description': 'Full company name to include in the search'}}, 'additionalProperties': False}}]
|
||||
-------
|
||||
|
||||
You can then a MCP like so:
|
||||
|
||||
```<usage name>
|
||||
{
|
||||
"tool": "<tool name (without @)>",
|
||||
"inputSchema": {<inputSchema json for the tool>}
|
||||
}
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
Now that I know how to use the MCP, I will choose the search-stock-news tool and execute it to find out IBM stock market.
|
||||
|
||||
```Cognitive-Stack/search-stock-news-mcp
|
||||
{
|
||||
"tool": "search-stock-news",
|
||||
"inputSchema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": ["symbol"],
|
||||
"properties": {
|
||||
"symbol": "IBM"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
You are a project manager.
|
||||
Your goal is to divide and conquer the task using the following agents:
|
||||
- Coder: A programming agent, can code in python, bash, C and golang.
|
||||
- File: An agent for finding, reading or operating with files.
|
||||
- Web: An agent that can conduct web search and navigate to any webpage.
|
||||
- Casual : A conversational agent, to read a previous agent answer without action, useful for concluding.
|
||||
|
||||
Agents are other AI that obey your instructions.
|
||||
|
||||
You will be given a task and you will need to divide it into smaller tasks and assign them to the agents.
|
||||
|
||||
You have to respect a strict format:
|
||||
```json
|
||||
{"agent": "agent_name", "need": "needed_agents_output", "task": "agent_task"}
|
||||
```
|
||||
Where:
|
||||
- "agent": The choosed agent for the task.
|
||||
- "need": id of necessary previous agents answer for current agent.
|
||||
- "task": A precise description of the task the agent should conduct.
|
||||
|
||||
# Example 1: web app
|
||||
|
||||
User: make a weather app in python
|
||||
You: Sure, here is the plan:
|
||||
|
||||
## Task 1: I will search for available weather api with the help of the web agent.
|
||||
|
||||
## Task 2: I will create an api key for the weather api using the web agent
|
||||
|
||||
## Task 3: I will setup the project using the file agent
|
||||
|
||||
## Task 4: I asign the coding agent to make a weather app in python
|
||||
|
||||
```json
|
||||
{
|
||||
"plan": [
|
||||
{
|
||||
"agent": "Web",
|
||||
"id": "1",
|
||||
"need": [],
|
||||
"task": "Search for reliable weather APIs"
|
||||
},
|
||||
{
|
||||
"agent": "Web",
|
||||
"id": "2",
|
||||
"need": ["1"],
|
||||
"task": "Obtain API key from the selected service"
|
||||
},
|
||||
{
|
||||
"agent": "File",
|
||||
"id": "3",
|
||||
"need": [],
|
||||
"task": "Create and setup a web app folder for a python project. initialize as a git repo with all required file and a sources folder. You are forbidden from asking clarification, just execute."
|
||||
},
|
||||
{
|
||||
"agent": "Coder",
|
||||
"id": "4",
|
||||
"need": ["2", "3"],
|
||||
"task": "Based on the project structure. Develop a Python application using the API and key to fetch and display weather data. You are forbidden from asking clarification, just execute.""
|
||||
},
|
||||
{
|
||||
"agent": "Casual",
|
||||
"id": "3",
|
||||
"need": ["2", "3", "4"],
|
||||
"task": "These are the results of various steps taken to create a weather app, resume what has been done and conclude"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Do not write code. You are a planning agent.
|
||||
- If you don't know of a concept, use a web agent.
|
||||
- Put your plan in a json with the key "plan".
|
||||
- specify work folder name to all coding or file agents.
|
||||
- You might use a file agent before code agent to setup a project properly. specify folder name.
|
||||
- Give clear, detailled order to each agent and how their task relate to the previous task (if any).
|
||||
- The file agent can only conduct one action at the time. successive file agent could be needed.
|
||||
- Only use web agent for finding necessary informations.
|
||||
- Always tell the coding agent where to save file.
|
||||
- Do not search for tutorial.
|
||||
- Make sure json is within ```json tag
|
||||
- Coding agent should write the whole code in a single file unless instructed otherwise.
|
||||
- One step, one agent.
|
||||
@@ -1,52 +0,0 @@
|
||||
You are a planner agent.
|
||||
Your goal is to divide and conquer the task using the following agents:
|
||||
- Coder: An expert coder agent.
|
||||
- File: An expert agent for finding files.
|
||||
- Web: An expert agent for web search.
|
||||
|
||||
Agents are other AI that obey your instructions.
|
||||
|
||||
You will be given a task and you will need to divide it into smaller tasks and assign them to the agents.
|
||||
|
||||
You have to respect a strict format:
|
||||
```json
|
||||
{"agent": "agent_name", "need": "needed_agent_output", "task": "agent_task"}
|
||||
```
|
||||
|
||||
User: make a weather app in python
|
||||
You: Sure, here is the plan:
|
||||
|
||||
## Task 1: I will search for available weather api
|
||||
|
||||
## Task 2: I will create an api key for the weather api
|
||||
|
||||
## Task 3: I will make a weather app in python
|
||||
|
||||
```json
|
||||
{
|
||||
"plan": [
|
||||
{
|
||||
"agent": "Web",
|
||||
"id": "1",
|
||||
"need": null,
|
||||
"task": "Search for reliable weather APIs"
|
||||
},
|
||||
{
|
||||
"agent": "Web",
|
||||
"id": "2",
|
||||
"need": "1",
|
||||
"task": "Obtain API key from the selected service"
|
||||
},
|
||||
{
|
||||
"agent": "Coder",
|
||||
"id": "3",
|
||||
"need": "2",
|
||||
"task": "Develop a Python application using the API and key to fetch and display weather data"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
- Do not write code. You are a planning agent.
|
||||
- Put your plan in a json with the key "plan".
|
||||
@@ -1,32 +1,48 @@
|
||||
requests==2.31.0
|
||||
openai==1.61.1
|
||||
colorama==0.4.6
|
||||
python-dotenv==1.0.0
|
||||
playsound==1.3.0
|
||||
soundfile==0.13.1
|
||||
transformers==4.48.3
|
||||
torch==2.5.1
|
||||
ollama==0.4.7
|
||||
scipy==1.15.1
|
||||
kokoro==0.7.12
|
||||
flask==3.1.0
|
||||
soundfile==0.13.1
|
||||
protobuf==3.20.3
|
||||
termcolor==2.5.0
|
||||
ipython==8.34.0
|
||||
gliclass==0.1.8
|
||||
pyaudio==0.2.14
|
||||
librosa==0.10.2.post1
|
||||
selenium==4.29.0
|
||||
markdownify==1.1.0
|
||||
kokoro==0.9.4
|
||||
certifi==2025.4.26
|
||||
fastapi>=0.115.12
|
||||
flask>=3.1.0
|
||||
celery>=5.5.1
|
||||
aiofiles>=24.1.0
|
||||
uvicorn>=0.34.0
|
||||
pydantic>=2.10.6
|
||||
pydantic_core>=2.27.2
|
||||
setuptools>=75.6.0
|
||||
sacremoses>=0.0.53
|
||||
requests>=2.31.0
|
||||
numpy>=1.24.4
|
||||
colorama>=0.4.6
|
||||
python-dotenv>=1.0.0
|
||||
playsound>=1.3.0
|
||||
soundfile>=0.13.1
|
||||
transformers>=4.46.3
|
||||
torch>=2.4.1
|
||||
python-dotenv>=1.0.0
|
||||
ollama>=0.4.7
|
||||
scipy>=1.9.3
|
||||
soundfile>=0.13.1
|
||||
protobuf>=3.20.3
|
||||
termcolor>=2.4.0
|
||||
pypdf>=5.4.0
|
||||
ipython>=8.13.0
|
||||
pyaudio>=0.2.14
|
||||
librosa>=0.10.2.post1
|
||||
selenium>=4.27.1
|
||||
markdownify>=1.1.0
|
||||
text2emotion>=0.0.5
|
||||
adaptive-classifier>=0.0.10
|
||||
langid>=1.1.6
|
||||
chromedriver-autoinstaller>=0.6.4
|
||||
httpx>=0.27,<0.29
|
||||
anyio>=3.5.0,<5
|
||||
distro>=1.7.0,<2
|
||||
jiter>=0.4.0,<1
|
||||
sniffio
|
||||
fake_useragent>=2.1.0
|
||||
selenium_stealth>=1.0.6
|
||||
undetected-chromedriver>=3.5.5
|
||||
sentencepiece>=0.2.0
|
||||
tqdm>4
|
||||
# if use chinese
|
||||
openai
|
||||
sniffio
|
||||
ordered_set
|
||||
pypinyin
|
||||
cn2an
|
||||
jieba
|
||||
@@ -2,16 +2,34 @@
|
||||
|
||||
echo "Starting installation for Linux..."
|
||||
|
||||
set -e
|
||||
# Update package list
|
||||
sudo apt-get update
|
||||
|
||||
# Install Python dependencies from requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
sudo apt-get update || { echo "Failed to update package list"; exit 1; }
|
||||
# make sure essential tool are installed
|
||||
# Install essential tools
|
||||
sudo apt-get install -y \
|
||||
python3-dev \
|
||||
python3-pip \
|
||||
python3-wheel \
|
||||
build-essential \
|
||||
alsa-utils \
|
||||
portaudio19-dev \
|
||||
python3-pyaudio \
|
||||
libgtk-3-dev \
|
||||
libnotify-dev \
|
||||
libgconf-2-4 \
|
||||
libnss3 \
|
||||
libxss1 || { echo "Failed to install packages"; exit 1; }
|
||||
|
||||
# upgrade pip
|
||||
pip install --upgrade pip
|
||||
# install wheel
|
||||
pip install --upgrade pip setuptools wheel
|
||||
# install docker compose
|
||||
sudo apt install -y docker-compose
|
||||
# Install Selenium for chromedriver
|
||||
pip3 install selenium
|
||||
|
||||
# Install portaudio for pyAudio
|
||||
sudo apt-get install -y portaudio19-dev python3-dev alsa-utils
|
||||
# Install Python dependencies from requirements.txt
|
||||
pip3 install -r requirements.txt --no-cache-dir
|
||||
|
||||
echo "Installation complete for Linux!"
|
||||
@@ -2,16 +2,29 @@
|
||||
|
||||
echo "Starting installation for macOS..."
|
||||
|
||||
# Install Python dependencies from requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
set -e
|
||||
|
||||
# Check if homebrew is installed
|
||||
if ! command -v brew &> /dev/null; then
|
||||
echo "Homebrew not found. Installing Homebrew..."
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
fi
|
||||
|
||||
# update
|
||||
brew update
|
||||
# make sure wget installed
|
||||
brew install wget
|
||||
# Install chromedriver using Homebrew
|
||||
brew install --cask chromedriver
|
||||
|
||||
# Install portaudio for pyAudio using Homebrew
|
||||
brew install portaudio
|
||||
|
||||
# update pip
|
||||
python3 -m pip install --upgrade pip
|
||||
# upgrade setuptools and wheel
|
||||
pip3 install --upgrade setuptools wheel
|
||||
# Install Selenium
|
||||
pip3 install selenium
|
||||
# Install Python dependencies from requirements.txt
|
||||
pip3 install -r requirements.txt --no-cache-dir
|
||||
|
||||
echo "Installation complete for macOS!"
|
||||
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
echo Starting installation for Windows...
|
||||
|
||||
REM Install Python dependencies from requirements.txt
|
||||
pip install pyreadline3
|
||||
pip install -r requirements.txt
|
||||
|
||||
REM Install Selenium
|
||||
pip install selenium
|
||||
|
||||
echo Note: pyAudio installation may require additional steps on Windows.
|
||||
echo Please install portaudio manually (e.g., via vcpkg or prebuilt binaries) and then run: pip install pyaudio
|
||||
echo Also, download and install chromedriver manually from: https://sites.google.com/chromium.org/driver/getting-started
|
||||
echo Place chromedriver in a directory included in your PATH.
|
||||
|
||||
echo Installation partially complete for Windows. Follow manual steps above.
|
||||
pause
|
||||
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Starting installation for Windows..."
|
||||
|
||||
# Install Python dependencies from requirements.txt
|
||||
pip3 install -r requirements.txt
|
||||
|
||||
# Install Selenium
|
||||
pip3 install selenium
|
||||
|
||||
echo "Note: pyAudio installation may require additional steps on Windows."
|
||||
echo "Please install portaudio manually (e.g., via vcpkg or prebuilt binaries) and then run: pip3 install pyaudio"
|
||||
echo "Also, download and install chromedriver manually from: https://sites.google.com/chromium.org/driver/getting-started"
|
||||
echo "Place chromedriver in a directory included in your PATH."
|
||||
|
||||
echo "Installation partially complete for Windows. Follow manual steps above."
|
||||
@@ -1 +0,0 @@
|
||||
SEARXNG_BASE_URL="http://127.0.0.1:8080"
|
||||
@@ -1,3 +1,4 @@
|
||||
version: '3'
|
||||
services:
|
||||
redis:
|
||||
container_name: redis
|
||||
@@ -28,8 +29,8 @@ services:
|
||||
- ./searxng:/etc/searxng:rw
|
||||
environment:
|
||||
- SEARXNG_BASE_URL=http://localhost:8080/
|
||||
- UWSGI_WORKERS=4
|
||||
- UWSGI_THREADS=4
|
||||
- UWSGI_WORKERS=1
|
||||
- UWSGI_THREADS=1
|
||||
cap_add:
|
||||
- CHOWN
|
||||
- SETGID
|
||||
|
||||
@@ -95,7 +95,7 @@ server:
|
||||
# If your instance owns a /etc/searxng/settings.yml file, then set the following
|
||||
# values there.
|
||||
|
||||
secret_key: "ultrasecretkey" # Is overwritten by ${SEARXNG_SECRET}
|
||||
secret_key: "supersecret" # Is overwritten by ${SEARXNG_SECRET},W
|
||||
# Proxy image results through SearXNG. Is overwritten by ${SEARXNG_IMAGE_PROXY}
|
||||
image_proxy: false
|
||||
# 1.0 and 1.1 are supported
|
||||
|
||||
@@ -85,17 +85,6 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Stop containers
|
||||
echo "Stopping containers to apply security settings..."
|
||||
docker-compose down
|
||||
|
||||
# Start containers again with secure settings
|
||||
echo "Deploying SearXNG with secure settings..."
|
||||
if ! docker-compose up -d; then
|
||||
echo "Error: Failed to deploy SearXNG. Check logs with 'docker compose logs'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display status and access instructions
|
||||
echo "SearXNG setup complete!"
|
||||
docker ps -a --filter "name=searxng" --filter "name=redis"
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
[uwsgi]
|
||||
# Who will run the code
|
||||
uid = searxng
|
||||
gid = searxng
|
||||
|
||||
# Number of workers (usually CPU count)
|
||||
# default value: %k (= number of CPU core, see Dockerfile)
|
||||
workers = 1
|
||||
|
||||
# Number of threads per worker
|
||||
# default value: 4 (see Dockerfile)
|
||||
enable-threads = true
|
||||
threads = 1
|
||||
|
||||
# The right granted on the created socket
|
||||
chmod-socket = 666
|
||||
|
||||
# Plugin to use and interpreter config
|
||||
single-interpreter = true
|
||||
master = true
|
||||
plugin = python3
|
||||
lazy-apps = true
|
||||
enable-threads = 4
|
||||
|
||||
# Module to import
|
||||
module = searx.webapp
|
||||
|
||||
# Virtualenv and python path
|
||||
pythonpath = /usr/local/searxng/
|
||||
chdir = /usr/local/searxng/searx/
|
||||
|
||||
# automatically set processes name to something meaningful
|
||||
auto-procname = true
|
||||
|
||||
# Disable request logging for privacy
|
||||
disable-logging = true
|
||||
log-5xx = true
|
||||
|
||||
# Set the max size of a request (request-body excluded)
|
||||
buffer-size = 8192
|
||||
|
||||
# No keep alive
|
||||
# See https://github.com/searx/searx-docker/issues/24
|
||||
add-header = Connection: close
|
||||
|
||||
# Follow SIGTERM convention
|
||||
# See https://github.com/searxng/searxng/issues/3427
|
||||
die-on-term
|
||||
|
||||
# uwsgi serves the static files
|
||||
static-map = /static=/usr/local/searxng/searx/static
|
||||
static-gzip-all = True
|
||||
offload-threads = 4
|
||||
@@ -0,0 +1,108 @@
|
||||
|
||||
#!/usr/bin python3
|
||||
|
||||
"""
|
||||
self_run.py is a script for automatically creating prompts, and saving history as training data.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import configparser
|
||||
import asyncio
|
||||
|
||||
from sources.llm_provider import Provider
|
||||
from sources.interaction import Interaction
|
||||
from sources.agents import Agent, CoderAgent, CasualAgent, FileAgent, PlannerAgent, BrowserAgent, McpAgent
|
||||
from sources.browser import Browser, create_driver
|
||||
|
||||
import warnings
|
||||
warnings.filterwarnings("ignore")
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
|
||||
def copy_conversations_folder():
|
||||
source_path = "conversations/"
|
||||
destination_path = "training_data/"
|
||||
if not os.path.exists(destination_path):
|
||||
os.makedirs(destination_path)
|
||||
for filename in os.listdir(source_path):
|
||||
source_file = os.path.join(source_path, filename)
|
||||
destination_file = os.path.join(destination_path, filename)
|
||||
shutil.copy2(source_file, destination_file)
|
||||
print(f"Copied {source_file} to {destination_file}")
|
||||
|
||||
def get_random_query(provider):
|
||||
prompt = """
|
||||
You are an expert in crafting queries for AgenticSeek, a AI assistant that autonomously browses the web, writes code, plans tasks, and manages files. It supports tasks like web searches, coding in Python/C/Go/Java, file operations, task planning.
|
||||
Queries must be explicit, specifying actions like "search the web," "write code," or "save to a file," as AgenticSeek's agent routing may not infer vague intents.
|
||||
|
||||
Generate a single realistic user query for AgenticSeek. The query should:
|
||||
|
||||
Be concise and explicit about the desired action (e.g., web search, coding, file management).
|
||||
Align with AgenticSeek’s capabilities (web browsing, coding, task planning, file operations).
|
||||
Include a specific output where relevant (e.g., save to a file with a clear name and path).
|
||||
Reflect a practical use case (e.g., research, programming, personal tasks).
|
||||
Be formatted as a single sentence.
|
||||
Example Query:
|
||||
Search the web for the best hiking trails in Colorado and save a list of three trails with their locations in hiking_trails.txt in /home/project
|
||||
"""
|
||||
history = [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": prompt}]
|
||||
thought = provider.respond(history)
|
||||
return thought
|
||||
|
||||
async def self_runner():
|
||||
provider = Provider(provider_name=config["MAIN"]["provider_name"],
|
||||
model=config["MAIN"]["provider_model"],
|
||||
server_address=config["MAIN"]["provider_server_address"],
|
||||
is_local=config.getboolean('MAIN', 'is_local'))
|
||||
|
||||
browser = Browser(
|
||||
create_driver(headless=True, stealth_mode=False),
|
||||
anticaptcha_manual_install=False
|
||||
)
|
||||
|
||||
agents = [
|
||||
CasualAgent(name=config["MAIN"]["agent_name"],
|
||||
prompt_path=f"prompts/base/casual_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
CoderAgent(name="coder",
|
||||
prompt_path=f"prompts/base/coder_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
FileAgent(name="File Agent",
|
||||
prompt_path=f"prompts/base/file_agent.txt",
|
||||
provider=provider, verbose=False),
|
||||
BrowserAgent(name="Browser",
|
||||
prompt_path=f"prompts/base/browser_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser),
|
||||
PlannerAgent(name="Planner",
|
||||
prompt_path=f"prompts/base/planner_agent.txt",
|
||||
provider=provider, verbose=False, browser=browser)
|
||||
]
|
||||
|
||||
interaction = Interaction(agents,
|
||||
tts_enabled=False,
|
||||
stt_enabled=False,
|
||||
recover_last_session=False,
|
||||
langs=['en']
|
||||
)
|
||||
print("Start self-running for training data generation...")
|
||||
try:
|
||||
while interaction.is_active:
|
||||
query = get_random_query(provider)
|
||||
print(f"Generated query: {query}")
|
||||
interaction.set_query(query)
|
||||
if await interaction.think():
|
||||
interaction.show_answer()
|
||||
except Exception as e:
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
copy_conversations_folder()
|
||||
raise e
|
||||
finally:
|
||||
if config.getboolean('MAIN', 'save_session'):
|
||||
interaction.save_session()
|
||||
copy_conversations_folder()
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(self_runner())
|
||||
@@ -1,30 +0,0 @@
|
||||
{
|
||||
"model_name": "deepseek-r1:14b",
|
||||
"known_models": [
|
||||
"qwq:32b",
|
||||
"deepseek-r1:1.5b",
|
||||
"deepseek-r1:7b",
|
||||
"deepseek-r1:14b",
|
||||
"deepseek-r1:32b",
|
||||
"deepseek-r1:70b",
|
||||
"deepseek-r1:671b",
|
||||
"deepseek-coder:1.3b",
|
||||
"deepseek-coder:6.7b",
|
||||
"deepseek-coder:33b",
|
||||
"llama2-uncensored:7b",
|
||||
"llama2-uncensored:70b",
|
||||
"llama3.1:8b",
|
||||
"llama3.1:70b",
|
||||
"llama3.3:70b",
|
||||
"llama3:8b",
|
||||
"llama3:70b",
|
||||
"i4:14b",
|
||||
"mistral:7b",
|
||||
"mistral:70b",
|
||||
"mistral:33b",
|
||||
"qwen1:7b",
|
||||
"qwen1:14b",
|
||||
"qwen1:32b",
|
||||
"qwen1:70b"
|
||||
]
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
from flask import Flask, jsonify, request
|
||||
import threading
|
||||
import ollama
|
||||
import logging
|
||||
import json
|
||||
|
||||
log = logging.getLogger('werkzeug')
|
||||
log.setLevel(logging.ERROR)
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# Shared state with thread-safe locks
|
||||
class Config:
|
||||
def __init__(self):
|
||||
self.model = None
|
||||
self.known_models = []
|
||||
self.allowed_models = []
|
||||
self.model_name = None
|
||||
|
||||
def load(self):
|
||||
with open('config.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
self.known_models = data['known_models']
|
||||
self.model_name = data['model_name']
|
||||
|
||||
def validate_model(self, model):
|
||||
if model not in self.known_models:
|
||||
raise ValueError(f"Model {model} is not known")
|
||||
|
||||
class GenerationState:
|
||||
def __init__(self):
|
||||
self.lock = threading.Lock()
|
||||
self.last_complete_sentence = ""
|
||||
self.current_buffer = ""
|
||||
self.is_generating = False
|
||||
self.model = None
|
||||
|
||||
state = GenerationState()
|
||||
|
||||
def generate_response(history): # Only takes history as an argument
|
||||
global state
|
||||
try:
|
||||
with state.lock:
|
||||
state.is_generating = True
|
||||
state.last_complete_sentence = ""
|
||||
state.current_buffer = ""
|
||||
|
||||
stream = ollama.chat(
|
||||
model=state.model, # Access state.model directly
|
||||
messages=history,
|
||||
stream=True,
|
||||
)
|
||||
for chunk in stream:
|
||||
content = chunk['message']['content']
|
||||
print(content, end='', flush=True)
|
||||
with state.lock:
|
||||
state.current_buffer += content
|
||||
except ollama.ResponseError as e:
|
||||
if e.status_code == 404:
|
||||
ollama.pull(state.model)
|
||||
with state.lock:
|
||||
state.is_generating = False
|
||||
print(f"Error: {e}")
|
||||
finally:
|
||||
with state.lock:
|
||||
state.is_generating = False
|
||||
|
||||
@app.route('/generate', methods=['POST'])
|
||||
def start_generation():
|
||||
global state
|
||||
data = request.get_json()
|
||||
|
||||
with state.lock:
|
||||
if state.is_generating:
|
||||
return jsonify({"error": "Generation already in progress"}), 400
|
||||
|
||||
history = data.get('messages', [])
|
||||
# Pass only history to the thread
|
||||
threading.Thread(target=generate_response, args=(history,)).start() # Note the comma to make it a single-element tuple
|
||||
return jsonify({"message": "Generation started"}), 202
|
||||
|
||||
@app.route('/get_updated_sentence')
|
||||
def get_updated_sentence():
|
||||
global state
|
||||
with state.lock:
|
||||
return jsonify({
|
||||
"sentence": state.current_buffer,
|
||||
"is_complete": not state.is_generating
|
||||
})
|
||||
|
||||
if __name__ == '__main__':
|
||||
config = Config()
|
||||
config.load()
|
||||
config.validate_model(config.model_name)
|
||||
state.model = config.model_name
|
||||
app.run(host='0.0.0.0', port=5000, debug=False, threaded=True)
|
||||
@@ -8,36 +8,52 @@ setup(
|
||||
version="0.1.0",
|
||||
author="Fosowl",
|
||||
author_email="mlg.fcu@gmail.com",
|
||||
description="A Python project for agentic search and processing",
|
||||
description="The open, local alternative to ManusAI",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
url="https://github.com/Fosowl/agenticSeek",
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
install_requires=[
|
||||
"requests==2.31.0",
|
||||
"openai==1.61.1",
|
||||
"colorama==0.4.6",
|
||||
"python-dotenv==1.0.0",
|
||||
"playsound==1.3.0",
|
||||
"soundfile==0.13.1",
|
||||
"transformers==4.48.3",
|
||||
"torch==2.5.1",
|
||||
"ollama==0.4.7",
|
||||
"scipy==1.15.1",
|
||||
"kokoro==0.7.12",
|
||||
"flask==3.1.0",
|
||||
"protobuf==3.20.3",
|
||||
"termcolor==2.5.0",
|
||||
"gliclass==0.1.8",
|
||||
"ipython==8.34.0",
|
||||
"librosa==0.10.2.post1",
|
||||
"selenium==4.29.0",
|
||||
"markdownify==1.1.0",
|
||||
"fastapi>=0.115.12",
|
||||
"celery>=5.5.1",
|
||||
"uvicorn>=0.34.0",
|
||||
"flask>=3.1.0",
|
||||
"aiofiles>=24.1.0",
|
||||
"pydantic>=2.10.6",
|
||||
"pydantic_core>=2.27.2",
|
||||
"requests>=2.31.0",
|
||||
"sacremoses>=0.0.53",
|
||||
"numpy>=1.24.4",
|
||||
"colorama>=0.4.6",
|
||||
"python-dotenv>=1.0.0",
|
||||
"playsound>=1.3.0",
|
||||
"soundfile>=0.13.1",
|
||||
"transformers>=4.46.3",
|
||||
"torch>=2.4.1",
|
||||
"ollama>=0.4.7",
|
||||
"scipy>=1.9.3",
|
||||
"kokoro>=0.7.12",
|
||||
"protobuf>=3.20.3",
|
||||
"termcolor>=2.5.0",
|
||||
"ipython>=8.34.0",
|
||||
"librosa>=0.10.2.post1",
|
||||
"selenium>=4.29.0",
|
||||
"markdownify>=1.1.0",
|
||||
"text2emotion>=0.0.5",
|
||||
"python-dotenv>=1.0.0",
|
||||
"adaptive-classifier>=0.0.10",
|
||||
"langid>=1.1.6",
|
||||
"chromedriver-autoinstaller>=0.6.4",
|
||||
"httpx>=0.27,<0.29",
|
||||
"anyio>=3.5.0,<5",
|
||||
"distro>=1.7.0,<2",
|
||||
"jiter>=0.4.0,<1",
|
||||
"fake_useragent>=2.1.0",
|
||||
"selenium_stealth>=1.0.6",
|
||||
"undetected-chromedriver>=3.5.5",
|
||||
"sentencepiece>=0.2.0",
|
||||
"openai",
|
||||
"sniffio",
|
||||
"tqdm>4"
|
||||
],
|
||||
@@ -59,5 +75,5 @@ setup(
|
||||
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||
"Operating System :: OS Independent",
|
||||
],
|
||||
python_requires=">=3.6",
|
||||
python_requires=">=3.9",
|
||||
)
|
||||
|
||||
@@ -5,5 +5,6 @@ from .casual_agent import CasualAgent
|
||||
from .file_agent import FileAgent
|
||||
from .planner_agent import PlannerAgent
|
||||
from .browser_agent import BrowserAgent
|
||||
from .mcp_agent import McpAgent
|
||||
|
||||
__all__ = ["Agent", "CoderAgent", "CasualAgent", "FileAgent", "PlannerAgent", "BrowserAgent"]
|
||||
__all__ = ["Agent", "CoderAgent", "CasualAgent", "FileAgent", "PlannerAgent", "BrowserAgent", "McpAgent"]
|
||||
|
||||
@@ -5,57 +5,104 @@ import os
|
||||
import random
|
||||
import time
|
||||
|
||||
import asyncio
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from sources.memory import Memory
|
||||
from sources.utility import pretty_print
|
||||
from sources.schemas import executorResult
|
||||
|
||||
random.seed(time.time())
|
||||
|
||||
class executorResult:
|
||||
"""
|
||||
A class to store the result of a tool execution.
|
||||
"""
|
||||
def __init__(self, blocks, feedback, success):
|
||||
self.blocks = blocks
|
||||
self.feedback = feedback
|
||||
self.success = success
|
||||
|
||||
def show(self):
|
||||
for block in self.blocks:
|
||||
pretty_print("-"*100, color="output")
|
||||
pretty_print(block, color="code" if self.success else "failure")
|
||||
pretty_print("-"*100, color="output")
|
||||
pretty_print(self.feedback, color="success" if self.success else "failure")
|
||||
|
||||
class Agent():
|
||||
"""
|
||||
An abstract class for all agents.
|
||||
"""
|
||||
def __init__(self, model: str,
|
||||
name: str,
|
||||
def __init__(self, name: str,
|
||||
prompt_path:str,
|
||||
provider,
|
||||
recover_last_session=True) -> None:
|
||||
verbose=False,
|
||||
browser=None) -> None:
|
||||
"""
|
||||
Args:
|
||||
name (str): Name of the agent.
|
||||
prompt_path (str): Path to the prompt file for the agent.
|
||||
provider: The provider for the LLM.
|
||||
recover_last_session (bool, optional): Whether to recover the last conversation.
|
||||
verbose (bool, optional): Enable verbose logging if True. Defaults to False.
|
||||
browser: The browser class for web navigation (only for browser agent).
|
||||
"""
|
||||
|
||||
self.agent_name = name
|
||||
self.browser = browser
|
||||
self.role = None
|
||||
self.type = None
|
||||
self.current_directory = os.getcwd()
|
||||
self.model = model
|
||||
self.llm = provider
|
||||
self.memory = Memory(self.load_prompt(prompt_path),
|
||||
recover_last_session=recover_last_session,
|
||||
memory_compression=False)
|
||||
self.memory = None
|
||||
self.tools = {}
|
||||
self.blocks_result = []
|
||||
self.success = True
|
||||
self.last_answer = ""
|
||||
self.status_message = "Haven't started yet"
|
||||
self.verbose = verbose
|
||||
self.executor = ThreadPoolExecutor(max_workers=1)
|
||||
|
||||
@property
|
||||
def get_agent_name(self) -> str:
|
||||
return self.agent_name
|
||||
|
||||
@property
|
||||
def get_agent_type(self) -> str:
|
||||
return self.type
|
||||
|
||||
@property
|
||||
def get_agent_role(self) -> str:
|
||||
return self.role
|
||||
|
||||
@property
|
||||
def get_last_answer(self) -> str:
|
||||
return self.last_answer
|
||||
|
||||
@property
|
||||
def get_blocks(self) -> list:
|
||||
return self.blocks_result
|
||||
|
||||
@property
|
||||
def get_status_message(self) -> str:
|
||||
return self.status_message
|
||||
|
||||
@property
|
||||
def get_tools(self) -> dict:
|
||||
return self.tools
|
||||
|
||||
@property
|
||||
def get_success(self) -> bool:
|
||||
return self.success
|
||||
|
||||
def get_blocks_result(self) -> list:
|
||||
return self.blocks_result
|
||||
|
||||
def add_tool(self, name: str, tool: Callable) -> None:
|
||||
if tool is not Callable:
|
||||
raise TypeError("Tool must be a callable object (a method)")
|
||||
self.tools[name] = tool
|
||||
|
||||
def get_tools_name(self) -> list:
|
||||
"""
|
||||
Get the list of tools names.
|
||||
"""
|
||||
return list(self.tools.keys())
|
||||
|
||||
def get_tools_description(self) -> str:
|
||||
"""
|
||||
Get the list of tools names and their description.
|
||||
"""
|
||||
description = ""
|
||||
for name in self.get_tools_name():
|
||||
description += f"{name}: {self.tools[name].description}\n"
|
||||
return description
|
||||
|
||||
def load_prompt(self, file_path: str) -> str:
|
||||
try:
|
||||
with open(file_path, 'r', encoding="utf-8") as f:
|
||||
@@ -85,43 +132,73 @@ class Agent():
|
||||
|
||||
def extract_reasoning_text(self, text: str) -> None:
|
||||
"""
|
||||
Extract the reasoning block of a easoning model like deepseek.
|
||||
Extract the reasoning block of a reasoning model like deepseek.
|
||||
"""
|
||||
start_tag = "<think>"
|
||||
end_tag = "</think>"
|
||||
if text is None:
|
||||
return None
|
||||
start_idx = text.find(start_tag)
|
||||
end_idx = text.rfind(end_tag)+8
|
||||
return text[start_idx:end_idx]
|
||||
|
||||
def llm_request(self, verbose = False) -> Tuple[str, str]:
|
||||
async def llm_request(self) -> Tuple[str, str]:
|
||||
"""
|
||||
Asynchronously ask the LLM to process the prompt.
|
||||
"""
|
||||
self.status_message = "Thinking..."
|
||||
loop = asyncio.get_event_loop()
|
||||
return await loop.run_in_executor(self.executor, self.sync_llm_request)
|
||||
|
||||
def sync_llm_request(self) -> Tuple[str, str]:
|
||||
"""
|
||||
Ask the LLM to process the prompt and return the answer and the reasoning.
|
||||
"""
|
||||
memory = self.memory.get()
|
||||
thought = self.llm.respond(memory, verbose)
|
||||
thought = self.llm.respond(memory, self.verbose)
|
||||
|
||||
reasoning = self.extract_reasoning_text(thought)
|
||||
answer = self.remove_reasoning_text(thought)
|
||||
self.memory.push('assistant', answer)
|
||||
return answer, reasoning
|
||||
|
||||
def wait_message(self, speech_module):
|
||||
async def wait_message(self, speech_module):
|
||||
if speech_module is None:
|
||||
return
|
||||
messages = ["Please be patient, I am working on it.",
|
||||
"Computing... I recommand you have a coffee while I work.",
|
||||
"Hold on, I’m crunching numbers.",
|
||||
"Working on it, please let me think."]
|
||||
speech_module.speak(messages[random.randint(0, len(messages)-1)])
|
||||
loop = asyncio.get_event_loop()
|
||||
return await loop.run_in_executor(self.executor, lambda: speech_module.speak(messages[random.randint(0, len(messages)-1)]))
|
||||
|
||||
def get_blocks_result(self) -> list:
|
||||
return self.blocks_result
|
||||
def get_last_tool_type(self) -> str:
|
||||
return self.blocks_result[-1].tool_type if len(self.blocks_result) > 0 else None
|
||||
|
||||
def raw_answer_blocks(self, answer: str) -> str:
|
||||
"""
|
||||
Return the answer with all the blocks inserted, as text.
|
||||
"""
|
||||
if self.last_answer is None:
|
||||
return
|
||||
raw = ""
|
||||
lines = self.last_answer.split("\n")
|
||||
for line in lines:
|
||||
if "block:" in line:
|
||||
block_idx = int(line.split(":")[1])
|
||||
if block_idx < len(self.blocks_result):
|
||||
raw += self.blocks_result[block_idx].__str__()
|
||||
else:
|
||||
raw += line + "\n"
|
||||
return raw
|
||||
|
||||
def show_answer(self):
|
||||
"""
|
||||
Show the answer in a pretty way.
|
||||
Show code blocks and their respective feedback by inserting them in the ressponse.
|
||||
"""
|
||||
if self.last_answer is None:
|
||||
return
|
||||
lines = self.last_answer.split("\n")
|
||||
for line in lines:
|
||||
if "block:" in line:
|
||||
@@ -130,7 +207,6 @@ class Agent():
|
||||
self.blocks_result[block_idx].show()
|
||||
else:
|
||||
pretty_print(line, color="output")
|
||||
self.blocks_result = []
|
||||
|
||||
def remove_blocks(self, text: str) -> str:
|
||||
"""
|
||||
@@ -153,28 +229,42 @@ class Agent():
|
||||
block_idx += 1
|
||||
return "\n".join(post_lines)
|
||||
|
||||
def show_block(self, block: str) -> None:
|
||||
"""
|
||||
Show the block in a pretty way.
|
||||
"""
|
||||
pretty_print('▂'*64, color="status")
|
||||
pretty_print(block, color="code")
|
||||
pretty_print('▂'*64, color="status")
|
||||
|
||||
def execute_modules(self, answer: str) -> Tuple[bool, str]:
|
||||
"""
|
||||
Execute all the tools the agent has and return the result.
|
||||
"""
|
||||
feedback = ""
|
||||
success = False
|
||||
success = True
|
||||
blocks = None
|
||||
if answer.startswith("```"):
|
||||
answer = "I will execute:\n" + answer # there should always be a text before blocks for the function that display answer
|
||||
|
||||
self.success = True
|
||||
for name, tool in self.tools.items():
|
||||
feedback = ""
|
||||
blocks, save_path = tool.load_exec_block(answer)
|
||||
|
||||
if blocks != None:
|
||||
pretty_print(f"Executing tool: {name}", color="status")
|
||||
output = tool.execute(blocks)
|
||||
feedback = tool.interpreter_feedback(output) # tool interpreter feedback
|
||||
success = not tool.execution_failure_check(output)
|
||||
pretty_print(feedback, color="success" if success else "failure")
|
||||
pretty_print(f"Executing {len(blocks)} {name} blocks...", color="status")
|
||||
for block in blocks:
|
||||
self.show_block(block)
|
||||
output = tool.execute([block])
|
||||
feedback = tool.interpreter_feedback(output) # tool interpreter feedback
|
||||
success = not tool.execution_failure_check(output)
|
||||
self.blocks_result.append(executorResult(block, feedback, success, name))
|
||||
if not success:
|
||||
self.success = False
|
||||
self.memory.push('user', feedback)
|
||||
return False, feedback
|
||||
self.memory.push('user', feedback)
|
||||
self.blocks_result.append(executorResult(blocks, feedback, success))
|
||||
if not success:
|
||||
return False, feedback
|
||||
if save_path != None:
|
||||
tool.save_block(blocks, save_path)
|
||||
return True, feedback
|
||||
|
||||
@@ -1,101 +1,200 @@
|
||||
import re
|
||||
import time
|
||||
from datetime import date
|
||||
from typing import List, Tuple, Type, Dict
|
||||
from enum import Enum
|
||||
import asyncio
|
||||
|
||||
from sources.utility import pretty_print, animate_thinking
|
||||
from sources.agents.agent import Agent
|
||||
from sources.tools.searxSearch import searxSearch
|
||||
from sources.browser import Browser
|
||||
from sources.logger import Logger
|
||||
from sources.memory import Memory
|
||||
|
||||
class Action(Enum):
|
||||
REQUEST_EXIT = "REQUEST_EXIT"
|
||||
FORM_FILLED = "FORM_FILLED"
|
||||
GO_BACK = "GO_BACK"
|
||||
NAVIGATE = "NAVIGATE"
|
||||
SEARCH = "SEARCH"
|
||||
|
||||
class BrowserAgent(Agent):
|
||||
def __init__(self, model, name, prompt_path, provider):
|
||||
def __init__(self, name, prompt_path, provider, verbose=False, browser=None):
|
||||
"""
|
||||
The Browser agent is an agent that navigate the web autonomously in search of answer
|
||||
"""
|
||||
super().__init__(model, name, prompt_path, provider)
|
||||
super().__init__(name, prompt_path, provider, verbose, browser)
|
||||
self.tools = {
|
||||
"web_search": searxSearch(),
|
||||
}
|
||||
self.role = "deep research and web search"
|
||||
self.browser = Browser()
|
||||
self.browser.go_to("https://github.com/")
|
||||
self.role = "web"
|
||||
self.type = "browser_agent"
|
||||
self.browser = browser
|
||||
self.current_page = ""
|
||||
self.search_history = []
|
||||
self.navigable_links = []
|
||||
self.last_action = Action.NAVIGATE.value
|
||||
self.notes = []
|
||||
self.date = self.get_today_date()
|
||||
self.logger = Logger("browser_agent.log")
|
||||
self.memory = Memory(self.load_prompt(prompt_path),
|
||||
recover_last_session=False, # session recovery in handled by the interaction class
|
||||
memory_compression=False,
|
||||
model_provider=provider.get_model_name())
|
||||
|
||||
def get_today_date(self) -> str:
|
||||
"""Get the date"""
|
||||
date_time = date.today()
|
||||
return date_time.strftime("%B %d, %Y")
|
||||
|
||||
def extract_links(self, search_result: str):
|
||||
def extract_links(self, search_result: str) -> List[str]:
|
||||
"""Extract all links from a sentence."""
|
||||
pattern = r'(https?://\S+|www\.\S+)'
|
||||
matches = re.findall(pattern, search_result)
|
||||
trailing_punct = ".,!?;:"
|
||||
trailing_punct = ".,!?;:)"
|
||||
cleaned_links = [link.rstrip(trailing_punct) for link in matches]
|
||||
self.logger.info(f"Extracted links: {cleaned_links}")
|
||||
return self.clean_links(cleaned_links)
|
||||
|
||||
def clean_links(self, links: list):
|
||||
def extract_form(self, text: str) -> List[str]:
|
||||
"""Extract form written by the LLM in format [input_name](value)"""
|
||||
inputs = []
|
||||
matches = re.findall(r"\[\w+\]\([^)]+\)", text)
|
||||
return matches
|
||||
|
||||
def clean_links(self, links: List[str]) -> List[str]:
|
||||
"""Ensure no '.' at the end of link"""
|
||||
links_clean = []
|
||||
for link in links:
|
||||
link = link.strip()
|
||||
if link[-1] == '.':
|
||||
if not (link[-1].isalpha() or link[-1].isdigit()):
|
||||
links_clean.append(link[:-1])
|
||||
else:
|
||||
links_clean.append(link)
|
||||
return links_clean
|
||||
|
||||
def get_unvisited_links(self):
|
||||
def get_unvisited_links(self) -> List[str]:
|
||||
return "\n".join([f"[{i}] {link}" for i, link in enumerate(self.navigable_links) if link not in self.search_history])
|
||||
|
||||
def make_newsearch_prompt(self, user_prompt: str, search_result: dict):
|
||||
def make_newsearch_prompt(self, user_prompt: str, search_result: dict) -> str:
|
||||
search_choice = self.stringify_search_results(search_result)
|
||||
self.logger.info(f"Search results: {search_choice}")
|
||||
return f"""
|
||||
Based on the search result:
|
||||
{search_choice}
|
||||
Your goal is to find accurate and complete information to satisfy the user’s request.
|
||||
User request: {user_prompt}
|
||||
To proceed, choose a relevant link from the search results. Announce your choice by saying: "I want to navigate to <link>."
|
||||
To proceed, choose a relevant link from the search results. Announce your choice by saying: "I will navigate to <link>"
|
||||
Do not explain your choice.
|
||||
"""
|
||||
|
||||
def make_navigation_prompt(self, user_prompt: str, page_text: str):
|
||||
def make_navigation_prompt(self, user_prompt: str, page_text: str) -> str:
|
||||
remaining_links = self.get_unvisited_links()
|
||||
remaining_links_text = remaining_links if remaining_links is not None else "No links remaining, proceed with a new search."
|
||||
return f"""
|
||||
\nYou are currently browsing the web. Not the user, you are the browser.
|
||||
remaining_links_text = remaining_links if remaining_links is not None else "No links remaining, do a new search."
|
||||
inputs_form = self.browser.get_form_inputs()
|
||||
inputs_form_text = '\n'.join(inputs_form)
|
||||
notes = '\n'.join(self.notes)
|
||||
self.logger.info(f"Making navigation prompt with page text: {page_text[:100]}...\nremaining links: {remaining_links_text}")
|
||||
self.logger.info(f"Inputs form: {inputs_form_text}")
|
||||
self.logger.info(f"Notes: {notes}")
|
||||
|
||||
Page content:
|
||||
return f"""
|
||||
You are navigating the web.
|
||||
|
||||
**Current Context**
|
||||
|
||||
Webpage ({self.current_page}) content:
|
||||
{page_text}
|
||||
|
||||
You can navigate to these links:
|
||||
{remaining_links}
|
||||
Allowed Navigation Links:
|
||||
{remaining_links_text}
|
||||
|
||||
If no link seem appropriate, please say "GO_BACK".
|
||||
Remember, you seek the information the user want.
|
||||
The user query was : {user_prompt}
|
||||
You must choose a link (write it down) to navigate to, or go back.
|
||||
For exemple you can say: i want to go to www.wikipedia.org/cats
|
||||
Always end with a sentence that summarize when useful information is found for exemple:
|
||||
Summary: According to https://karpathy.github.io/ LeCun net is the earliest real-world application of a neural net"
|
||||
Do not say "according to this page", always write down the whole link.
|
||||
If a website does not have usefull information say Error, for exemple:
|
||||
Error: This forum does not discus anything that can answer the user query
|
||||
Do not explain your choice, be short, concise.
|
||||
Inputs forms:
|
||||
{inputs_form_text}
|
||||
|
||||
End of webpage ({self.current_page}.
|
||||
|
||||
# Instruction
|
||||
|
||||
1. **Evaluate if the page is relevant for user’s query and document finding:**
|
||||
- If the page is relevant, extract and summarize key information in concise notes (Note: <your note>)
|
||||
- If page not relevant, state: "Error: <specific reason the page does not address the query>" and either return to the previous page or navigate to a new link.
|
||||
- Notes should be factual, useful summaries of relevant content, they should always include specific names or link. Written as: "On <website URL>, <key fact 1>. <Key fact 2>. <Additional insight>." Avoid phrases like "the page provides" or "I found that."
|
||||
2. **Navigate to a link by either: **
|
||||
- Saying I will navigate to (write down the full URL) www.example.com/cats
|
||||
- Going back: If no link seems helpful, say: {Action.GO_BACK.value}.
|
||||
3. **Fill forms on the page:**
|
||||
- Fill form only when relevant.
|
||||
- Use Login if username/password specified by user. For quick task create account, remember password in a note.
|
||||
- You can fill a form using [form_name](value). Don't {Action.GO_BACK.value} when filling form.
|
||||
- If a form is irrelevant or you lack informations (eg: don't know user email) leave it empty.
|
||||
4. **Decide if you completed the task**
|
||||
- Check your notes. Do they fully answer the question? Did you verify with multiple pages?
|
||||
- Are you sure it’s correct?
|
||||
- If yes to all, say {Action.REQUEST_EXIT}.
|
||||
- If no, or a page lacks info, go to another link.
|
||||
- Never stop or ask the user for help.
|
||||
|
||||
**Rules:**
|
||||
- Do not write "The page talk about ...", write your finding on the page and how they contribute to an answer.
|
||||
- Put note in a single paragraph.
|
||||
- When you exit, explain why.
|
||||
|
||||
# Example:
|
||||
|
||||
Example 1 (useful page, no need go futher):
|
||||
Note: According to karpathy site LeCun net is ...
|
||||
No link seem useful to provide futher information.
|
||||
Action: {Action.GO_BACK.value}
|
||||
|
||||
Example 2 (not useful, see useful link on page):
|
||||
Error: reddit.com/welcome does not discuss anything related to the user’s query.
|
||||
There is a link that could lead to the information.
|
||||
Action: navigate to http://reddit.com/r/locallama
|
||||
|
||||
Example 3 (not useful, no related links):
|
||||
Error: x.com does not discuss anything related to the user’s query and no navigation link are usefull.
|
||||
Action: {Action.GO_BACK.value}
|
||||
|
||||
Example 3 (clear definitive query answer found or enought notes taken):
|
||||
I took 10 notes so far with enought finding to answer user question.
|
||||
Therefore I should exit the web browser.
|
||||
Action: {Action.REQUEST_EXIT.value}
|
||||
|
||||
Example 4 (loging form visible):
|
||||
|
||||
Note: I am on the login page, I will type the given username and password.
|
||||
Action:
|
||||
[username_field](David)
|
||||
[password_field](edgerunners77)
|
||||
|
||||
Remember, user asked:
|
||||
{user_prompt}
|
||||
You previously took these notes:
|
||||
{notes}
|
||||
Do not Step-by-Step explanation. Write comprehensive Notes or Error as a long paragraph followed by your action.
|
||||
You must always take notes.
|
||||
"""
|
||||
|
||||
def llm_decide(self, prompt):
|
||||
async def llm_decide(self, prompt: str, show_reasoning: bool = False) -> Tuple[str, str]:
|
||||
animate_thinking("Thinking...", color="status")
|
||||
self.memory.push('user', prompt)
|
||||
answer, reasoning = self.llm_request(prompt)
|
||||
pretty_print("-"*100)
|
||||
answer, reasoning = await self.llm_request()
|
||||
if show_reasoning:
|
||||
pretty_print(reasoning, color="failure")
|
||||
pretty_print(answer, color="output")
|
||||
pretty_print("-"*100)
|
||||
return answer, reasoning
|
||||
|
||||
def select_unvisited(self, search_result):
|
||||
def select_unvisited(self, search_result: List[str]) -> List[str]:
|
||||
results_unvisited = []
|
||||
for res in search_result:
|
||||
if res["link"] not in self.search_history:
|
||||
results_unvisited.append(res)
|
||||
self.logger.info(f"Unvisited links: {results_unvisited}")
|
||||
return results_unvisited
|
||||
|
||||
def jsonify_search_results(self, results_string):
|
||||
def jsonify_search_results(self, results_string: str) -> List[str]:
|
||||
result_blocks = results_string.split("\n\n")
|
||||
parsed_results = []
|
||||
for block in result_blocks:
|
||||
@@ -114,62 +213,215 @@ class BrowserAgent(Agent):
|
||||
parsed_results.append(result_dict)
|
||||
return parsed_results
|
||||
|
||||
def stringify_search_results(self, results_arr):
|
||||
return '\n\n'.join([f"Link: {res['link']}" for res in results_arr])
|
||||
def stringify_search_results(self, results_arr: List[str]) -> str:
|
||||
return '\n\n'.join([f"Link: {res['link']}\nPreview: {res['snippet']}" for res in results_arr])
|
||||
|
||||
def save_notes(self, text):
|
||||
def parse_answer(self, text):
|
||||
lines = text.split('\n')
|
||||
saving = False
|
||||
buffer = []
|
||||
links = []
|
||||
for line in lines:
|
||||
if "summary:" in line.lower():
|
||||
self.notes.append(line)
|
||||
if line == '' or 'action:' in line.lower():
|
||||
saving = False
|
||||
if "note" in line.lower():
|
||||
saving = True
|
||||
if saving:
|
||||
buffer.append(line.replace("notes:", ''))
|
||||
else:
|
||||
links.extend(self.extract_links(line))
|
||||
self.notes.append('. '.join(buffer).strip())
|
||||
return links
|
||||
|
||||
def conclude_prompt(self, user_query):
|
||||
search_note = '\n -'.join(self.notes)
|
||||
def select_link(self, links: List[str]) -> str | None:
|
||||
for lk in links:
|
||||
if lk == self.current_page:
|
||||
self.logger.info(f"Already visited {lk}. Skipping.")
|
||||
continue
|
||||
self.logger.info(f"Selected link: {lk}")
|
||||
return lk
|
||||
self.logger.warning("No link selected.")
|
||||
return None
|
||||
|
||||
def get_page_text(self, compression = False) -> str:
|
||||
"""Get the text content of the current page."""
|
||||
page_text = self.browser.get_text()
|
||||
if compression:
|
||||
#page_text = self.memory.compress_text_to_max_ctx(page_text)
|
||||
page_text = self.memory.trim_text_to_max_ctx(page_text)
|
||||
return page_text
|
||||
|
||||
def conclude_prompt(self, user_query: str) -> str:
|
||||
annotated_notes = [f"{i+1}: {note.lower()}" for i, note in enumerate(self.notes)]
|
||||
search_note = '\n'.join(annotated_notes)
|
||||
pretty_print(f"AI notes:\n{search_note}", color="success")
|
||||
return f"""
|
||||
Following a web search about:
|
||||
Following a human request:
|
||||
{user_query}
|
||||
Write a conclusion based on these notes:
|
||||
A web browsing AI made the following finding across different pages:
|
||||
{search_note}
|
||||
|
||||
Expand on the finding or step that lead to success, and provide a conclusion that answer the request. Include link when possible.
|
||||
Do not give advices or try to answer the human. Just structure the AI finding in a structured and clear way.
|
||||
You should answer in the same language as the user.
|
||||
"""
|
||||
|
||||
def process(self, user_prompt, speech_module) -> str:
|
||||
def search_prompt(self, user_prompt: str) -> str:
|
||||
return f"""
|
||||
Current date: {self.date}
|
||||
Make a efficient search engine query to help users with their request:
|
||||
{user_prompt}
|
||||
Example:
|
||||
User: "go to twitter, login with username toto and password pass79 to my twitter and say hello everyone "
|
||||
You: search: Twitter login page.
|
||||
|
||||
User: "I need info on the best laptops for AI this year."
|
||||
You: "search: best laptops 2025 to run Machine Learning model, reviews"
|
||||
|
||||
User: "Search for recent news about space missions."
|
||||
You: "search: Recent space missions news, {self.date}"
|
||||
|
||||
Do not explain, do not write anything beside the search query.
|
||||
Except if query does not make any sense for a web search then explain why and say {Action.REQUEST_EXIT.value}
|
||||
Do not try to answer query. you can only formulate search term or exit.
|
||||
"""
|
||||
|
||||
def handle_update_prompt(self, user_prompt: str, page_text: str, fill_success: bool) -> str:
|
||||
prompt = f"""
|
||||
You are a web browser.
|
||||
You just filled a form on the page.
|
||||
Now you should see the result of the form submission on the page:
|
||||
Page text:
|
||||
{page_text}
|
||||
The user asked: {user_prompt}
|
||||
Does the page answer the user’s query now? Are you still on a login page or did you get redirected?
|
||||
If it does, take notes of the useful information, write down result and say {Action.FORM_FILLED.value}.
|
||||
if it doesn’t, say: Error: Attempt to fill form didn't work {Action.GO_BACK.value}.
|
||||
If you were previously on a login form, no need to take notes.
|
||||
"""
|
||||
if not fill_success:
|
||||
prompt += f"""
|
||||
According to browser feedback, the form was not filled correctly. Is that so? you might consider other strategies.
|
||||
"""
|
||||
return prompt
|
||||
|
||||
def show_search_results(self, search_result: List[str]):
|
||||
pretty_print("\nSearch results:", color="output")
|
||||
for res in search_result:
|
||||
pretty_print(f"Title: {res['title']} - ", color="info", no_newline=True)
|
||||
pretty_print(f"Link: {res['link']}", color="status")
|
||||
|
||||
def stuck_prompt(self, user_prompt: str, unvisited: List[str]) -> str:
|
||||
"""
|
||||
Prompt for when the agent repeat itself, can happen when fail to extract a link.
|
||||
"""
|
||||
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
|
||||
prompt += f"""
|
||||
You previously said:
|
||||
{self.last_answer}
|
||||
You must consider other options. Choose other link.
|
||||
"""
|
||||
return prompt
|
||||
|
||||
async def process(self, user_prompt: str, speech_module: type) -> Tuple[str, str]:
|
||||
"""
|
||||
Process the user prompt to conduct an autonomous web search.
|
||||
Start with a google search with searxng using web_search tool.
|
||||
Then enter a navigation logic to find the answer or conduct required actions.
|
||||
Args:
|
||||
user_prompt: The user's input query
|
||||
speech_module: Optional speech output module
|
||||
Returns:
|
||||
tuple containing the final answer and reasoning
|
||||
"""
|
||||
complete = False
|
||||
|
||||
animate_thinking(f"Thinking...", color="status")
|
||||
mem_begin_idx = self.memory.push('user', self.search_prompt(user_prompt))
|
||||
ai_prompt, reasoning = await self.llm_request()
|
||||
if Action.REQUEST_EXIT.value in ai_prompt:
|
||||
pretty_print(f"Web agent requested exit.\n{reasoning}\n\n{ai_prompt}", color="failure")
|
||||
return ai_prompt, ""
|
||||
animate_thinking(f"Searching...", color="status")
|
||||
search_result_raw = self.tools["web_search"].execute([user_prompt], False)
|
||||
search_result = self.jsonify_search_results(search_result_raw)
|
||||
search_result = search_result[:10] # until futher improvement
|
||||
self.status_message = "Searching..."
|
||||
search_result_raw = self.tools["web_search"].execute([ai_prompt], False)
|
||||
search_result = self.jsonify_search_results(search_result_raw)[:16]
|
||||
self.show_search_results(search_result)
|
||||
prompt = self.make_newsearch_prompt(user_prompt, search_result)
|
||||
unvisited = [None]
|
||||
while not complete:
|
||||
answer, reasoning = self.llm_decide(prompt)
|
||||
self.save_notes(answer)
|
||||
if "REQUEST_EXIT" in answer:
|
||||
while not complete and len(unvisited) > 0:
|
||||
|
||||
self.memory.clear()
|
||||
unvisited = self.select_unvisited(search_result)
|
||||
answer, reasoning = await self.llm_decide(prompt, show_reasoning = False)
|
||||
if self.last_answer == answer:
|
||||
prompt = self.stuck_prompt(user_prompt, unvisited)
|
||||
continue
|
||||
self.last_answer = answer
|
||||
pretty_print('▂'*32, color="status")
|
||||
|
||||
extracted_form = self.extract_form(answer)
|
||||
if len(extracted_form) > 0:
|
||||
self.status_message = "Filling web form..."
|
||||
pretty_print(f"Filling inputs form...", color="status")
|
||||
fill_success = self.browser.fill_form(extracted_form)
|
||||
page_text = self.get_page_text()
|
||||
answer = self.handle_update_prompt(user_prompt, page_text, fill_success)
|
||||
answer, reasoning = await self.llm_decide(prompt)
|
||||
|
||||
if Action.FORM_FILLED.value in answer:
|
||||
pretty_print(f"Filled form. Handling page update.", color="status")
|
||||
page_text = self.get_page_text()
|
||||
self.navigable_links = self.browser.get_navigable()
|
||||
prompt = self.make_navigation_prompt(user_prompt, page_text)
|
||||
continue
|
||||
|
||||
links = self.parse_answer(answer)
|
||||
link = self.select_link(links)
|
||||
if link == self.current_page:
|
||||
pretty_print(f"Already visited {link}. Search callback.", color="status")
|
||||
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
|
||||
self.search_history.append(link)
|
||||
continue
|
||||
|
||||
if Action.REQUEST_EXIT.value in answer:
|
||||
self.status_message = "Exiting web browser..."
|
||||
pretty_print(f"Agent requested exit.", color="status")
|
||||
complete = True
|
||||
break
|
||||
links = self.extract_links(answer)
|
||||
if len(links) == 0 or "GO_BACK" in answer:
|
||||
unvisited = self.select_unvisited(search_result)
|
||||
|
||||
if (link == None and len(extracted_form) < 3) or Action.GO_BACK.value in answer or link in self.search_history:
|
||||
pretty_print(f"Going back to results. Still {len(unvisited)}", color="status")
|
||||
self.status_message = "Going back to search results..."
|
||||
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
|
||||
pretty_print(f"Going back to results. Still {len(unvisited)}", color="warning")
|
||||
links = []
|
||||
self.search_history.append(link)
|
||||
self.current_page = link
|
||||
continue
|
||||
if len(unvisited) == 0:
|
||||
break
|
||||
animate_thinking(f"Navigating to {links[0]}", color="status")
|
||||
speech_module.speak(f"Navigating to {links[0]}")
|
||||
self.browser.go_to(links[0])
|
||||
self.search_history.append(links[0])
|
||||
page_text = self.browser.get_text()
|
||||
|
||||
animate_thinking(f"Navigating to {link}", color="status")
|
||||
if speech_module: speech_module.speak(f"Navigating to {link}")
|
||||
nav_ok = self.browser.go_to(link)
|
||||
self.search_history.append(link)
|
||||
if not nav_ok:
|
||||
pretty_print(f"Failed to navigate to {link}.", color="failure")
|
||||
prompt = self.make_newsearch_prompt(user_prompt, unvisited)
|
||||
continue
|
||||
self.current_page = link
|
||||
page_text = self.get_page_text()
|
||||
self.navigable_links = self.browser.get_navigable()
|
||||
prompt = self.make_navigation_prompt(user_prompt, page_text)
|
||||
self.status_message = "Navigating..."
|
||||
self.browser.screenshot()
|
||||
|
||||
speech_module.speak(answer)
|
||||
self.browser.close()
|
||||
pretty_print("Exited navigation, starting to summarize finding...", color="status")
|
||||
prompt = self.conclude_prompt(user_prompt)
|
||||
answer, reasoning = self.llm_request(prompt)
|
||||
mem_last_idx = self.memory.push('user', prompt)
|
||||
self.status_message = "Summarizing findings..."
|
||||
answer, reasoning = await self.llm_request()
|
||||
pretty_print(answer, color="output")
|
||||
self.status_message = "Ready"
|
||||
self.last_answer = answer
|
||||
return answer, reasoning
|
||||
|
||||
if __name__ == "__main__":
|
||||
browser = Browser()
|
||||
pass
|
||||
@@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
|
||||
from sources.utility import pretty_print, animate_thinking
|
||||
from sources.agents.agent import Agent
|
||||
@@ -5,43 +6,30 @@ from sources.tools.searxSearch import searxSearch
|
||||
from sources.tools.flightSearch import FlightSearch
|
||||
from sources.tools.fileFinder import FileFinder
|
||||
from sources.tools.BashInterpreter import BashInterpreter
|
||||
from sources.memory import Memory
|
||||
|
||||
class CasualAgent(Agent):
|
||||
def __init__(self, model, name, prompt_path, provider):
|
||||
def __init__(self, name, prompt_path, provider, verbose=False):
|
||||
"""
|
||||
The casual agent is a special for casual talk to the user without specific tasks.
|
||||
"""
|
||||
super().__init__(model, name, prompt_path, provider)
|
||||
super().__init__(name, prompt_path, provider, verbose, None)
|
||||
self.tools = {
|
||||
"web_search": searxSearch(),
|
||||
"flight_search": FlightSearch(),
|
||||
"file_finder": FileFinder(),
|
||||
"bash": BashInterpreter()
|
||||
}
|
||||
self.role = "casual talking"
|
||||
} # No tools for the casual agent
|
||||
self.role = "talk"
|
||||
self.type = "casual_agent"
|
||||
self.memory = Memory(self.load_prompt(prompt_path),
|
||||
recover_last_session=False, # session recovery in handled by the interaction class
|
||||
memory_compression=False,
|
||||
model_provider=provider.get_model_name())
|
||||
|
||||
def process(self, prompt, speech_module) -> str:
|
||||
complete = False
|
||||
async def process(self, prompt, speech_module) -> str:
|
||||
self.memory.push('user', prompt)
|
||||
|
||||
self.wait_message(speech_module)
|
||||
while not complete:
|
||||
animate_thinking("Thinking...", color="status")
|
||||
answer, reasoning = self.llm_request()
|
||||
exec_success, _ = self.execute_modules(answer)
|
||||
answer = self.remove_blocks(answer)
|
||||
self.last_answer = answer
|
||||
complete = True
|
||||
for tool in self.tools.values():
|
||||
if tool.found_executable_blocks():
|
||||
complete = False # AI read results and continue the conversation
|
||||
animate_thinking("Thinking...", color="status")
|
||||
answer, reasoning = await self.llm_request()
|
||||
self.last_answer = answer
|
||||
self.status_message = "Ready"
|
||||
return answer, reasoning
|
||||
|
||||
if __name__ == "__main__":
|
||||
from llm_provider import Provider
|
||||
|
||||
#local_provider = Provider("ollama", "deepseek-r1:14b", None)
|
||||
server_provider = Provider("server", "deepseek-r1:14b", "192.168.1.100:5000")
|
||||
agent = CasualAgent("deepseek-r1:14b", "jarvis", "prompts/casual_agent.txt", server_provider)
|
||||
ans = agent.process("Hello, how are you?")
|
||||
print(ans)
|
||||
pass
|
||||