npcsh 0.3.28__tar.gz → 0.3.30__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {npcsh-0.3.28/npcsh.egg-info → npcsh-0.3.30}/PKG-INFO +43 -3
- {npcsh-0.3.28 → npcsh-0.3.30}/README.md +42 -2
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/llm_funcs.py +32 -23
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_compiler.py +23 -4
- npcsh-0.3.30/npcsh/npc_team/tools/bash_executer.tool +32 -0
- npcsh-0.3.30/npcsh/npc_team/tools/code_executor.tool +16 -0
- npcsh-0.3.30/npcsh/npc_team/tools/npcsh_executor.tool +9 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/tools/sql_executor.tool +2 -2
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/shell.py +19 -17
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/shell_helpers.py +576 -49
- {npcsh-0.3.28 → npcsh-0.3.30/npcsh.egg-info}/PKG-INFO +43 -3
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh.egg-info/SOURCES.txt +3 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/setup.py +1 -1
- {npcsh-0.3.28 → npcsh-0.3.30}/LICENSE +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/MANIFEST.in +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/__init__.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/audio.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/cli.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/command_history.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/conversation.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/data_models.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/dataframes.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/embeddings.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/helpers.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/image.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/image_gen.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/knowledge_graph.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/load_data.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/main.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/model_runner.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_sysenv.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/assembly_lines/test_pipeline.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/corca.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/foreman.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/analytics/celona.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/hr_support/raone.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/humanities/eriane.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/it_support/lineru.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/marketing/slean.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/philosophy/maurawa.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/sales/turnic.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/templates/software/welxor.npc +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/tools/calculator.tool +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/tools/generic_search.tool +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/tools/image_generation.tool +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/tools/local_search.tool +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/npc_team/tools/screen_cap.tool +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/plonk.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/response.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/search.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/serve.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/stream.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh/video.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh.egg-info/dependency_links.txt +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh.egg-info/entry_points.txt +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh.egg-info/requires.txt +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/npcsh.egg-info/top_level.txt +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/setup.cfg +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_chromadb.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_embedding_check.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_embedding_methods.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_helpers.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_knowledge_graph_rag.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_llm_funcs.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_networkx_vis.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_npc_compiler.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_npcsh.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_npcteam.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_shell_helpers.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_tars.py +0 -0
- {npcsh-0.3.28 → npcsh-0.3.30}/tests/test_tool_use.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: npcsh
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.30
|
|
4
4
|
Summary: npcsh is a command line tool for integrating LLMs into everyday workflows and for orchestrating teams of NPCs.
|
|
5
5
|
Home-page: https://github.com/cagostino/npcsh
|
|
6
6
|
Author: Christopher Agostino
|
|
@@ -469,6 +469,7 @@ if __name__ == "__main__":
|
|
|
469
469
|
### Linux install
|
|
470
470
|
```bash
|
|
471
471
|
|
|
472
|
+
# for audio primarily
|
|
472
473
|
sudo apt-get install espeak
|
|
473
474
|
sudo apt-get install portaudio19-dev python3-pyaudio
|
|
474
475
|
sudo apt-get install alsa-base alsa-utils
|
|
@@ -476,6 +477,10 @@ sudo apt-get install libcairo2-dev
|
|
|
476
477
|
sudo apt-get install libgirepository1.0-dev
|
|
477
478
|
sudo apt-get install ffmpeg
|
|
478
479
|
|
|
480
|
+
# for triggers
|
|
481
|
+
sudo apt install inotify-tools
|
|
482
|
+
|
|
483
|
+
|
|
479
484
|
#And if you don't have ollama installed, use this:
|
|
480
485
|
curl -fsSL https://ollama.com/install.sh | sh
|
|
481
486
|
|
|
@@ -498,11 +503,17 @@ pip install npcsh[all]
|
|
|
498
503
|
|
|
499
504
|
### Mac install
|
|
500
505
|
```bash
|
|
506
|
+
#mainly for audio
|
|
501
507
|
brew install portaudio
|
|
502
508
|
brew install ffmpeg
|
|
509
|
+
brew install pygobject3
|
|
510
|
+
|
|
511
|
+
# for triggers
|
|
512
|
+
brew install ...
|
|
513
|
+
|
|
514
|
+
|
|
503
515
|
brew install ollama
|
|
504
516
|
brew services start ollama
|
|
505
|
-
brew install pygobject3
|
|
506
517
|
ollama pull llama3.2
|
|
507
518
|
ollama pull llava:7b
|
|
508
519
|
ollama pull nomic-embed-text
|
|
@@ -1076,13 +1087,30 @@ npc ots -f test_data/catfight.PNG
|
|
|
1076
1087
|
### Plan : Schedule tasks to be run at regular intervals (under construction)
|
|
1077
1088
|
Use the /plan macro to schedule tasks to be run at regular intervals.
|
|
1078
1089
|
```npcsh
|
|
1079
|
-
npcsh> /plan run a rag search on the files in the current directory every 5 minutes
|
|
1090
|
+
npcsh> /plan run a rag search for 'moonbeam' on the files in the current directory every 5 minutes
|
|
1080
1091
|
```
|
|
1081
1092
|
|
|
1093
|
+
```npcsh
|
|
1094
|
+
npcsh> /plan record the cpu usage every 5 minutes
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
```npcsh
|
|
1098
|
+
npcsh> /plan record the apps that are using the most ram every 5 minutes
|
|
1099
|
+
```
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1082
1104
|
```bash
|
|
1083
1105
|
npc plan -f 30m -t 'task'
|
|
1084
1106
|
```
|
|
1085
1107
|
|
|
1108
|
+
Plan will use platform-specific scheduling tools. In particular, it uses crontab on Linux and launchd on macOS and Schedule Tasks on Windows.
|
|
1109
|
+
|
|
1110
|
+
Implementations have been provided for Mac and Windows but only has been tested as of 3/23/2025 on Linux.
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1086
1114
|
### Plonk : Computer Control
|
|
1087
1115
|
Use the /plonk macro to allow the LLM to control your computer.
|
|
1088
1116
|
```npcsh
|
|
@@ -1368,6 +1396,18 @@ npcsh> /spool model=llama3.3
|
|
|
1368
1396
|
npc spool -n npc.npc
|
|
1369
1397
|
```
|
|
1370
1398
|
|
|
1399
|
+
### Trigger
|
|
1400
|
+
Use the /trigger macro to execute specific actionss based on certain conditions.
|
|
1401
|
+
|
|
1402
|
+
```npcsh
|
|
1403
|
+
npcsh> /trigger watch for new PDF downloads in the ~/Downloads directory and move them
|
|
1404
|
+
to the ~/Documents/PDFs directory . Ensure that the directory exists or create it if it does not.
|
|
1405
|
+
```
|
|
1406
|
+
|
|
1407
|
+
On Linux, trigger makes use of inotify-tools to watch for file system events. On macOS, it uses fswatch, and on Windows, it uses Watch-Command.
|
|
1408
|
+
|
|
1409
|
+
|
|
1410
|
+
|
|
1371
1411
|
|
|
1372
1412
|
|
|
1373
1413
|
### Vixynt: Image Generation
|
|
@@ -385,6 +385,7 @@ if __name__ == "__main__":
|
|
|
385
385
|
### Linux install
|
|
386
386
|
```bash
|
|
387
387
|
|
|
388
|
+
# for audio primarily
|
|
388
389
|
sudo apt-get install espeak
|
|
389
390
|
sudo apt-get install portaudio19-dev python3-pyaudio
|
|
390
391
|
sudo apt-get install alsa-base alsa-utils
|
|
@@ -392,6 +393,10 @@ sudo apt-get install libcairo2-dev
|
|
|
392
393
|
sudo apt-get install libgirepository1.0-dev
|
|
393
394
|
sudo apt-get install ffmpeg
|
|
394
395
|
|
|
396
|
+
# for triggers
|
|
397
|
+
sudo apt install inotify-tools
|
|
398
|
+
|
|
399
|
+
|
|
395
400
|
#And if you don't have ollama installed, use this:
|
|
396
401
|
curl -fsSL https://ollama.com/install.sh | sh
|
|
397
402
|
|
|
@@ -414,11 +419,17 @@ pip install npcsh[all]
|
|
|
414
419
|
|
|
415
420
|
### Mac install
|
|
416
421
|
```bash
|
|
422
|
+
#mainly for audio
|
|
417
423
|
brew install portaudio
|
|
418
424
|
brew install ffmpeg
|
|
425
|
+
brew install pygobject3
|
|
426
|
+
|
|
427
|
+
# for triggers
|
|
428
|
+
brew install ...
|
|
429
|
+
|
|
430
|
+
|
|
419
431
|
brew install ollama
|
|
420
432
|
brew services start ollama
|
|
421
|
-
brew install pygobject3
|
|
422
433
|
ollama pull llama3.2
|
|
423
434
|
ollama pull llava:7b
|
|
424
435
|
ollama pull nomic-embed-text
|
|
@@ -992,13 +1003,30 @@ npc ots -f test_data/catfight.PNG
|
|
|
992
1003
|
### Plan : Schedule tasks to be run at regular intervals (under construction)
|
|
993
1004
|
Use the /plan macro to schedule tasks to be run at regular intervals.
|
|
994
1005
|
```npcsh
|
|
995
|
-
npcsh> /plan run a rag search on the files in the current directory every 5 minutes
|
|
1006
|
+
npcsh> /plan run a rag search for 'moonbeam' on the files in the current directory every 5 minutes
|
|
996
1007
|
```
|
|
997
1008
|
|
|
1009
|
+
```npcsh
|
|
1010
|
+
npcsh> /plan record the cpu usage every 5 minutes
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
```npcsh
|
|
1014
|
+
npcsh> /plan record the apps that are using the most ram every 5 minutes
|
|
1015
|
+
```
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
|
|
998
1020
|
```bash
|
|
999
1021
|
npc plan -f 30m -t 'task'
|
|
1000
1022
|
```
|
|
1001
1023
|
|
|
1024
|
+
Plan will use platform-specific scheduling tools. In particular, it uses crontab on Linux and launchd on macOS and Schedule Tasks on Windows.
|
|
1025
|
+
|
|
1026
|
+
Implementations have been provided for Mac and Windows but only has been tested as of 3/23/2025 on Linux.
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
|
|
1002
1030
|
### Plonk : Computer Control
|
|
1003
1031
|
Use the /plonk macro to allow the LLM to control your computer.
|
|
1004
1032
|
```npcsh
|
|
@@ -1284,6 +1312,18 @@ npcsh> /spool model=llama3.3
|
|
|
1284
1312
|
npc spool -n npc.npc
|
|
1285
1313
|
```
|
|
1286
1314
|
|
|
1315
|
+
### Trigger
|
|
1316
|
+
Use the /trigger macro to execute specific actionss based on certain conditions.
|
|
1317
|
+
|
|
1318
|
+
```npcsh
|
|
1319
|
+
npcsh> /trigger watch for new PDF downloads in the ~/Downloads directory and move them
|
|
1320
|
+
to the ~/Documents/PDFs directory . Ensure that the directory exists or create it if it does not.
|
|
1321
|
+
```
|
|
1322
|
+
|
|
1323
|
+
On Linux, trigger makes use of inotify-tools to watch for file system events. On macOS, it uses fswatch, and on Windows, it uses Watch-Command.
|
|
1324
|
+
|
|
1325
|
+
|
|
1326
|
+
|
|
1287
1327
|
|
|
1288
1328
|
|
|
1289
1329
|
### Vixynt: Image Generation
|
|
@@ -802,15 +802,20 @@ ReAct choices then will enter reasoning flow
|
|
|
802
802
|
|
|
803
803
|
prompt = f"""
|
|
804
804
|
A user submitted this query: {command}
|
|
805
|
+
|
|
805
806
|
Determine the nature of the user's request:
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
807
|
+
|
|
808
|
+
1. Should a tool be invoked to fulfill the request?
|
|
809
|
+
|
|
810
|
+
2. Is it a general question that requires an informative answer or a highly specific question that
|
|
809
811
|
requires inforrmation on the web?
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
812
|
+
|
|
813
|
+
3. Would this question be best answered by an alternative NPC?
|
|
814
|
+
|
|
815
|
+
4. Is it a complex request that actually requires more than one
|
|
816
|
+
tool to be called, perhaps in a sequence?
|
|
817
|
+
|
|
818
|
+
5. is there a need for the user to provide additional input to fulfill the request?
|
|
814
819
|
|
|
815
820
|
|
|
816
821
|
|
|
@@ -877,8 +882,12 @@ ReAct choices then will enter reasoning flow
|
|
|
877
882
|
|
|
878
883
|
prompt += f"""
|
|
879
884
|
In considering how to answer this, consider:
|
|
880
|
-
|
|
881
|
-
- Whether more context from the user is required to adequately answer the question.
|
|
885
|
+
|
|
886
|
+
- Whether more context from the user is required to adequately answer the question.
|
|
887
|
+
e.g. if a user asks for a joke about their favorite city but they don't include the city ,
|
|
888
|
+
it would be helpful to ask for that information. Similarly, if a user asks to open a browser
|
|
889
|
+
and to check the weather in a city, it would be helpful to ask for the city and which website
|
|
890
|
+
or source to use.
|
|
882
891
|
- Whether a tool should be used.
|
|
883
892
|
|
|
884
893
|
|
|
@@ -887,14 +896,17 @@ ReAct choices then will enter reasoning flow
|
|
|
887
896
|
extra tools or agent passes.
|
|
888
897
|
Only use tools or pass to other NPCs
|
|
889
898
|
when it is obvious that the answer needs to be as up-to-date as possible. For example,
|
|
890
|
-
|
|
899
|
+
a question about where mount everest is does not necessarily need to be answered by a tool call or an agent pass.
|
|
891
900
|
Similarly, if a user asks to explain the plot of the aeneid, this can be answered without a tool call or agent pass.
|
|
892
|
-
|
|
901
|
+
|
|
902
|
+
If a user were to ask for the current weather in tokyo or the current price of bitcoin or who the mayor of a city is,
|
|
903
|
+
then a tool call or agent pass may be appropriate.
|
|
904
|
+
|
|
893
905
|
Tools are valuable but their use should be limited and purposeful to
|
|
894
906
|
ensure the best user experience.
|
|
895
907
|
|
|
896
908
|
Respond with a JSON object containing:
|
|
897
|
-
- "action": one of ["
|
|
909
|
+
- "action": one of ["invoke_tool", "answer_question", "pass_to_npc", "execute_sequence", "request_input"]
|
|
898
910
|
- "tool_name": : if action is "invoke_tool": the name of the tool to use.
|
|
899
911
|
else if action is "execute_sequence", a list of tool names to use.
|
|
900
912
|
- "explanation": a brief explanation of why you chose this action.
|
|
@@ -907,7 +919,7 @@ ReAct choices then will enter reasoning flow
|
|
|
907
919
|
|
|
908
920
|
The format of the JSON object is:
|
|
909
921
|
{{
|
|
910
|
-
"action": "
|
|
922
|
+
"action": "invoke_tool" | "answer_question" | "pass_to_npc" | "execute_sequence" | "request_input",
|
|
911
923
|
"tool_name": "<tool_name(s)_if_applicable>",
|
|
912
924
|
"explanation": "<your_explanation>",
|
|
913
925
|
"npc_name": "<npc_name(s)_if_applicable>"
|
|
@@ -915,7 +927,9 @@ ReAct choices then will enter reasoning flow
|
|
|
915
927
|
|
|
916
928
|
If you execute a sequence, ensure that you have a specified NPC for each tool use.
|
|
917
929
|
|
|
918
|
-
Remember, do not include ANY ADDITIONAL MARKDOWN FORMATTING.
|
|
930
|
+
Remember, do not include ANY ADDITIONAL MARKDOWN FORMATTING.
|
|
931
|
+
There should be no leading ```json.
|
|
932
|
+
|
|
919
933
|
"""
|
|
920
934
|
|
|
921
935
|
if docs_context:
|
|
@@ -932,11 +946,6 @@ ReAct choices then will enter reasoning flow
|
|
|
932
946
|
{context}
|
|
933
947
|
|
|
934
948
|
"""
|
|
935
|
-
|
|
936
|
-
# print(prompt)
|
|
937
|
-
|
|
938
|
-
# For action determination, we don't need to pass the conversation messages to avoid confusion
|
|
939
|
-
# print(npc, model, provider)
|
|
940
949
|
action_response = get_llm_response(
|
|
941
950
|
prompt,
|
|
942
951
|
model=model,
|
|
@@ -965,12 +974,11 @@ ReAct choices then will enter reasoning flow
|
|
|
965
974
|
else:
|
|
966
975
|
response_content_parsed = response_content
|
|
967
976
|
|
|
968
|
-
# Proceed according to the action specified
|
|
969
977
|
action = response_content_parsed.get("action")
|
|
970
978
|
explanation = response_content["explanation"]
|
|
971
|
-
# Include the user's command in the conversation messages
|
|
972
979
|
print(f"action chosen: {action}")
|
|
973
980
|
print(f"explanation given: {explanation}")
|
|
981
|
+
|
|
974
982
|
if response_content_parsed.get("tool_name"):
|
|
975
983
|
print(f"tool name: {response_content_parsed.get('tool_name')}")
|
|
976
984
|
|
|
@@ -1316,8 +1324,9 @@ def handle_tool_call(
|
|
|
1316
1324
|
stream=stream,
|
|
1317
1325
|
messages=messages,
|
|
1318
1326
|
)
|
|
1319
|
-
if
|
|
1320
|
-
|
|
1327
|
+
if not stream:
|
|
1328
|
+
if "Error" in tool_output:
|
|
1329
|
+
raise Exception(tool_output)
|
|
1321
1330
|
except Exception as e:
|
|
1322
1331
|
# diagnose_problem = get_llm_response(
|
|
1323
1332
|
## f"""a problem has occurred.
|
|
@@ -551,6 +551,7 @@ class Tool:
|
|
|
551
551
|
|
|
552
552
|
# Process Steps
|
|
553
553
|
for i, step in enumerate(self.steps):
|
|
554
|
+
|
|
554
555
|
context = self.execute_step(
|
|
555
556
|
step,
|
|
556
557
|
context,
|
|
@@ -564,6 +565,7 @@ class Tool:
|
|
|
564
565
|
# if i is the last step and the user has reuqested a streaming output
|
|
565
566
|
# then we should return the stream
|
|
566
567
|
if i == len(self.steps) - 1 and stream: # this was causing the big issue X:
|
|
568
|
+
print("tool successful, passing output to stream")
|
|
567
569
|
return context
|
|
568
570
|
# Return the final output
|
|
569
571
|
if context.get("output") is not None:
|
|
@@ -592,8 +594,14 @@ class Tool:
|
|
|
592
594
|
except Exception as e:
|
|
593
595
|
print(f"Error rendering template: {e}")
|
|
594
596
|
rendered_code = code
|
|
595
|
-
|
|
596
|
-
|
|
597
|
+
# render engine if necessary
|
|
598
|
+
try:
|
|
599
|
+
template = jinja_env.from_string(engine)
|
|
600
|
+
rendered_engine = template.render(**context)
|
|
601
|
+
except:
|
|
602
|
+
print("error rendering engine")
|
|
603
|
+
rendered_engine = engine
|
|
604
|
+
if rendered_engine == "natural":
|
|
597
605
|
if len(rendered_code.strip()) > 0:
|
|
598
606
|
# print(f"Executing natural language step: {rendered_code}")
|
|
599
607
|
if stream:
|
|
@@ -610,7 +618,7 @@ class Tool:
|
|
|
610
618
|
context["llm_response"] = response_text
|
|
611
619
|
context["results"] = response_text
|
|
612
620
|
|
|
613
|
-
elif
|
|
621
|
+
elif rendered_engine == "python":
|
|
614
622
|
exec_globals = {
|
|
615
623
|
"__builtins__": __builtins__,
|
|
616
624
|
"npc": npc,
|
|
@@ -639,12 +647,23 @@ class Tool:
|
|
|
639
647
|
exec_env = context.copy()
|
|
640
648
|
try:
|
|
641
649
|
exec(rendered_code, exec_globals, new_locals)
|
|
650
|
+
exec_env.update(new_locals)
|
|
651
|
+
|
|
652
|
+
context.update(exec_env)
|
|
653
|
+
|
|
642
654
|
exec_env.update(new_locals)
|
|
643
655
|
context.update(exec_env)
|
|
644
|
-
|
|
656
|
+
|
|
657
|
+
# Add this line to explicitly copy the output
|
|
658
|
+
if "output" in new_locals:
|
|
659
|
+
context["output"] = new_locals["output"]
|
|
660
|
+
|
|
661
|
+
# Then your existing code
|
|
645
662
|
if "output" in exec_env:
|
|
646
663
|
if exec_env["output"] is not None:
|
|
647
664
|
context["results"] = exec_env["output"]
|
|
665
|
+
print("result from code execution: ", exec_env["output"])
|
|
666
|
+
|
|
648
667
|
except NameError as e:
|
|
649
668
|
tb_lines = traceback.format_exc().splitlines()
|
|
650
669
|
limited_tb = (
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
tool_name: bash_executor
|
|
2
|
+
description: Execute bash queries.
|
|
3
|
+
inputs:
|
|
4
|
+
- bash_command
|
|
5
|
+
- user_request
|
|
6
|
+
steps:
|
|
7
|
+
- engine: python
|
|
8
|
+
code: |
|
|
9
|
+
import subprocess
|
|
10
|
+
import os
|
|
11
|
+
cmd = '{{bash_command}}' # Properly quote the command input
|
|
12
|
+
def run_command(cmd):
|
|
13
|
+
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
14
|
+
stdout, stderr = process.communicate()
|
|
15
|
+
if stderr:
|
|
16
|
+
print(f"Error: {stderr.decode('utf-8')}")
|
|
17
|
+
return stderr
|
|
18
|
+
return stdout
|
|
19
|
+
result = run_command(cmd)
|
|
20
|
+
output = result.decode('utf-8')
|
|
21
|
+
|
|
22
|
+
- engine: natural
|
|
23
|
+
code: |
|
|
24
|
+
|
|
25
|
+
Here is the result of the bash command:
|
|
26
|
+
```
|
|
27
|
+
{{ output }}
|
|
28
|
+
```
|
|
29
|
+
This was the original user request: {{ user_request }}
|
|
30
|
+
|
|
31
|
+
Please provide a response accordingly.
|
|
32
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
tool_name: code_executor
|
|
2
|
+
description: Execute scripts with a specified language. choose from python, bash, R, or javascript. Set the ultimate result as the "output" variable. It must be a string. Do not add unnecessary print statements.
|
|
3
|
+
inputs:
|
|
4
|
+
- code
|
|
5
|
+
- language
|
|
6
|
+
steps:
|
|
7
|
+
- engine: '{{ language }}'
|
|
8
|
+
code: |
|
|
9
|
+
{{code}}
|
|
10
|
+
- engine: natural
|
|
11
|
+
code: |
|
|
12
|
+
Here is the result of the code execution that an agent ran.
|
|
13
|
+
```
|
|
14
|
+
{{ output }}
|
|
15
|
+
```
|
|
16
|
+
please provide a response accordingly.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
tool_name:
|
|
2
|
-
description: Execute
|
|
1
|
+
tool_name: data_pull
|
|
2
|
+
description: Execute queries on the ~/npcsh_history.db to pull data. The database contains only information about conversations and other user-provided data. It does not store any information about individual files.
|
|
3
3
|
inputs:
|
|
4
4
|
- sql_query
|
|
5
5
|
- interpret: false # Note that this is not a boolean, but a string
|
|
@@ -378,6 +378,7 @@ def main() -> None:
|
|
|
378
378
|
|
|
379
379
|
current_npc = result["current_npc"]
|
|
380
380
|
output = result.get("output")
|
|
381
|
+
|
|
381
382
|
conversation_id = result.get("conversation_id")
|
|
382
383
|
model = result.get("model")
|
|
383
384
|
provider = result.get("provider")
|
|
@@ -404,17 +405,16 @@ def main() -> None:
|
|
|
404
405
|
npc=npc_name,
|
|
405
406
|
attachments=attachments,
|
|
406
407
|
)
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
str_output = ""
|
|
408
|
+
|
|
409
|
+
str_output = ""
|
|
410
|
+
if NPCSH_STREAM_OUTPUT and hasattr(output, "__iter__"):
|
|
411
|
+
|
|
412
412
|
buffer = ""
|
|
413
413
|
in_code = False
|
|
414
414
|
code_buffer = ""
|
|
415
415
|
|
|
416
416
|
for chunk in output:
|
|
417
|
-
|
|
417
|
+
|
|
418
418
|
if provider == "anthropic":
|
|
419
419
|
chunk_content = (
|
|
420
420
|
chunk.delta.text
|
|
@@ -434,7 +434,7 @@ def main() -> None:
|
|
|
434
434
|
continue
|
|
435
435
|
|
|
436
436
|
str_output += chunk_content
|
|
437
|
-
|
|
437
|
+
# print(str_output, "str_output")
|
|
438
438
|
# Process the content character by character
|
|
439
439
|
for char in chunk_content:
|
|
440
440
|
buffer += char
|
|
@@ -490,16 +490,18 @@ def main() -> None:
|
|
|
490
490
|
if str_output:
|
|
491
491
|
output = str_output
|
|
492
492
|
print("\n")
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
493
|
+
|
|
494
|
+
if isinstance(output, str):
|
|
495
|
+
save_conversation_message(
|
|
496
|
+
command_history,
|
|
497
|
+
conversation_id,
|
|
498
|
+
"assistant",
|
|
499
|
+
output,
|
|
500
|
+
wd=current_path,
|
|
501
|
+
model=model,
|
|
502
|
+
provider=provider,
|
|
503
|
+
npc=npc_name,
|
|
504
|
+
)
|
|
503
505
|
|
|
504
506
|
# if there are attachments in most recent user sent message, save them
|
|
505
507
|
# save_attachment_to_message(command_history, message_id, # file_path, attachment_name, attachment_type)
|