npcsh 1.0.26__py3-none-any.whl → 1.0.28__py3-none-any.whl
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/_state.py +115 -111
- npcsh/alicanto.py +88 -88
- npcsh/corca.py +423 -95
- npcsh/guac.py +110 -107
- npcsh/mcp_helpers.py +45 -45
- npcsh/mcp_server.py +16 -17
- npcsh/npc.py +16 -17
- npcsh/npc_team/jinxs/bash_executer.jinx +1 -1
- npcsh/npc_team/jinxs/edit_file.jinx +6 -6
- npcsh/npc_team/jinxs/image_generation.jinx +5 -5
- npcsh/npc_team/jinxs/screen_cap.jinx +2 -2
- npcsh/npcsh.py +15 -6
- npcsh/plonk.py +8 -8
- npcsh/routes.py +77 -77
- npcsh/spool.py +13 -13
- npcsh/wander.py +37 -37
- npcsh/yap.py +72 -72
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/bash_executer.jinx +1 -1
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/edit_file.jinx +6 -6
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/image_generation.jinx +5 -5
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/screen_cap.jinx +2 -2
- {npcsh-1.0.26.dist-info → npcsh-1.0.28.dist-info}/METADATA +1 -1
- npcsh-1.0.28.dist-info/RECORD +73 -0
- npcsh-1.0.26.dist-info/RECORD +0 -73
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/foreman.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/internet_search.jinx +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/python_executor.jinx +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.0.26.data → npcsh-1.0.28.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.0.26.dist-info → npcsh-1.0.28.dist-info}/WHEEL +0 -0
- {npcsh-1.0.26.dist-info → npcsh-1.0.28.dist-info}/entry_points.txt +0 -0
- {npcsh-1.0.26.dist-info → npcsh-1.0.28.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.0.26.dist-info → npcsh-1.0.28.dist-info}/top_level.txt +0 -0
npcsh/plonk.py
CHANGED
|
@@ -8,7 +8,7 @@ import matplotlib.pyplot as plt
|
|
|
8
8
|
import matplotlib.patches as patches
|
|
9
9
|
from PIL import Image
|
|
10
10
|
import numpy as np
|
|
11
|
-
import imagehash
|
|
11
|
+
import imagehash
|
|
12
12
|
from npcsh._state import NPCSH_VISION_MODEL, NPCSH_VISION_PROVIDER
|
|
13
13
|
import argparse
|
|
14
14
|
from npcpy.npc_compiler import NPC
|
|
@@ -40,7 +40,7 @@ def format_plonk_summary(synthesized_summary: list) -> str:
|
|
|
40
40
|
def get_image_hash(image_path):
|
|
41
41
|
"""Generate a perceptual hash of the image to detect screen changes intelligently."""
|
|
42
42
|
try:
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
return imagehash.phash(Image.open(image_path))
|
|
45
45
|
except Exception as e:
|
|
46
46
|
print(f"Could not generate image hash: {e}")
|
|
@@ -59,7 +59,7 @@ def add_click_vector_trail(image_path, click_history, output_path):
|
|
|
59
59
|
font_size = max(12, min(width, height) // 80)
|
|
60
60
|
colors = plt.cm.viridis(np.linspace(0.3, 1.0, len(click_history)))
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
if len(click_history) > 1:
|
|
64
64
|
for i in range(len(click_history) - 1):
|
|
65
65
|
x1, y1 = (click_history[i]['x'] * width / 100, click_history[i]['y'] * height / 100)
|
|
@@ -68,7 +68,7 @@ def add_click_vector_trail(image_path, click_history, output_path):
|
|
|
68
68
|
arrowprops=dict(arrowstyle='->,head_width=0.6,head_length=0.8',
|
|
69
69
|
lw=3, color='cyan', alpha=0.9, shrinkA=25, shrinkB=25))
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
for i, click in enumerate(click_history):
|
|
73
73
|
x_pixel = int(click['x'] * width / 100)
|
|
74
74
|
y_pixel = int(click['y'] * height / 100)
|
|
@@ -79,15 +79,15 @@ def add_click_vector_trail(image_path, click_history, output_path):
|
|
|
79
79
|
facecolor=colors[i], alpha=0.9)
|
|
80
80
|
ax.add_patch(circle)
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
ax.text(x_pixel, y_pixel, str(i+1),
|
|
84
84
|
fontsize=font_size + 4,
|
|
85
85
|
color='white', weight='bold', ha='center', va='center')
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
coord_text = f"({click['x']}, {click['y']})"
|
|
89
|
-
ax.text(x_pixel + radius + 5,
|
|
90
|
-
y_pixel,
|
|
89
|
+
ax.text(x_pixel + radius + 5,
|
|
90
|
+
y_pixel,
|
|
91
91
|
coord_text,
|
|
92
92
|
fontsize=font_size,
|
|
93
93
|
color='white',
|
npcsh/routes.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
|
|
3
3
|
from typing import Callable, Dict, Any, List, Optional, Union
|
|
4
4
|
import functools
|
|
@@ -192,15 +192,15 @@ def safe_get(kwargs, key, default=None):
|
|
|
192
192
|
|
|
193
193
|
@router.route("breathe", "Condense context on a regular cadence")
|
|
194
194
|
def breathe_handler(command: str, **kwargs):
|
|
195
|
-
|
|
195
|
+
|
|
196
196
|
result = breathe(**kwargs)
|
|
197
197
|
if isinstance(result, dict):
|
|
198
198
|
return result
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
204
|
|
|
205
205
|
@router.route("compile", "Compile NPC profiles")
|
|
206
206
|
def compile_handler(command: str, **kwargs):
|
|
@@ -308,7 +308,7 @@ def help_handler(command: str, **kwargs):
|
|
|
308
308
|
parts = shlex.split(command)
|
|
309
309
|
if len(parts) < 2:
|
|
310
310
|
return {"output": get_help_text(), "messages": messages}
|
|
311
|
-
target = parts[1].lstrip('/')
|
|
311
|
+
target = parts[1].lstrip('/')
|
|
312
312
|
output = ""
|
|
313
313
|
|
|
314
314
|
|
|
@@ -330,7 +330,7 @@ def help_handler(command: str, **kwargs):
|
|
|
330
330
|
output += f"- **Associated Jinxs**: {jinx_names}\n"
|
|
331
331
|
return {"output": output, "messages": messages}
|
|
332
332
|
|
|
333
|
-
|
|
333
|
+
|
|
334
334
|
npc = safe_get(kwargs, 'npc')
|
|
335
335
|
jinx_obj = None
|
|
336
336
|
source = ""
|
|
@@ -363,10 +363,10 @@ def init_handler(command: str, **kwargs):
|
|
|
363
363
|
directory = "."
|
|
364
364
|
templates = None
|
|
365
365
|
context = None
|
|
366
|
-
|
|
366
|
+
|
|
367
367
|
if len(parts) > 1 and not parts[1].startswith("-"):
|
|
368
368
|
directory = parts[1]
|
|
369
|
-
|
|
369
|
+
|
|
370
370
|
|
|
371
371
|
initialize_npc_project(
|
|
372
372
|
directory=directory,
|
|
@@ -400,10 +400,10 @@ def ensure_repo():
|
|
|
400
400
|
|
|
401
401
|
def install_dependencies():
|
|
402
402
|
"""Install npm and pip dependencies."""
|
|
403
|
-
|
|
403
|
+
|
|
404
404
|
subprocess.check_call(["npm", "install"], cwd=NPC_STUDIO_DIR)
|
|
405
405
|
|
|
406
|
-
|
|
406
|
+
|
|
407
407
|
req_file = NPC_STUDIO_DIR / "requirements.txt"
|
|
408
408
|
if req_file.exists():
|
|
409
409
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "-r", str(req_file)])
|
|
@@ -415,21 +415,21 @@ def launch_npc_studio(path_to_open: str = None):
|
|
|
415
415
|
ensure_repo()
|
|
416
416
|
install_dependencies()
|
|
417
417
|
|
|
418
|
-
|
|
418
|
+
|
|
419
419
|
backend = subprocess.Popen(
|
|
420
420
|
[sys.executable, "npc_studio_serve.py"],
|
|
421
421
|
cwd=NPC_STUDIO_DIR,
|
|
422
422
|
shell = False
|
|
423
423
|
)
|
|
424
424
|
|
|
425
|
-
|
|
425
|
+
|
|
426
426
|
dev_server = subprocess.Popen(
|
|
427
427
|
["npm", "run", "dev"],
|
|
428
428
|
cwd=NPC_STUDIO_DIR,
|
|
429
429
|
shell=False
|
|
430
430
|
)
|
|
431
431
|
|
|
432
|
-
|
|
432
|
+
|
|
433
433
|
frontend = subprocess.Popen(
|
|
434
434
|
["npm", "start"],
|
|
435
435
|
cwd=NPC_STUDIO_DIR,
|
|
@@ -437,7 +437,7 @@ def launch_npc_studio(path_to_open: str = None):
|
|
|
437
437
|
)
|
|
438
438
|
|
|
439
439
|
return backend, dev_server, frontend
|
|
440
|
-
|
|
440
|
+
|
|
441
441
|
@router.route("npc-studio", "Start npc studio")
|
|
442
442
|
def npc_studio_handler(command: str, **kwargs):
|
|
443
443
|
messages = kwargs.get("messages", [])
|
|
@@ -529,13 +529,13 @@ def plan_handler(command: str, **kwargs):
|
|
|
529
529
|
user_command = " ".join(command.split()[1:])
|
|
530
530
|
if not user_command:
|
|
531
531
|
return {"output": "Usage: /plan <description_of_plan>", "messages": messages}
|
|
532
|
-
|
|
532
|
+
|
|
533
533
|
return execute_plan_command(command=user_command, **kwargs)
|
|
534
534
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
539
|
|
|
540
540
|
@router.route("pti", "Enter Pardon-The-Interruption mode for human-in-the-loop reasoning.")
|
|
541
541
|
def pti_handler(command: str, **kwargs):
|
|
@@ -545,8 +545,8 @@ def pti_handler(command: str, **kwargs):
|
|
|
545
545
|
def plonk_handler(command: str, **kwargs):
|
|
546
546
|
messages = safe_get(kwargs, "messages", [])
|
|
547
547
|
|
|
548
|
-
|
|
549
|
-
|
|
548
|
+
|
|
549
|
+
|
|
550
550
|
positional_args = safe_get(kwargs, 'positional_args', [])
|
|
551
551
|
request_str = " ".join(positional_args)
|
|
552
552
|
|
|
@@ -556,14 +556,14 @@ def plonk_handler(command: str, **kwargs):
|
|
|
556
556
|
try:
|
|
557
557
|
plonk_context = safe_get(kwargs, 'plonk_context')
|
|
558
558
|
|
|
559
|
-
|
|
559
|
+
|
|
560
560
|
summary_data = execute_plonk_command(
|
|
561
561
|
request=request_str,
|
|
562
562
|
model=safe_get(kwargs, 'vmodel', NPCSH_VISION_MODEL),
|
|
563
563
|
provider=safe_get(kwargs, 'vprovider', NPCSH_VISION_PROVIDER),
|
|
564
564
|
npc=safe_get(kwargs, 'npc'),
|
|
565
565
|
plonk_context=plonk_context,
|
|
566
|
-
debug=True
|
|
566
|
+
debug=True
|
|
567
567
|
)
|
|
568
568
|
|
|
569
569
|
if summary_data and isinstance(summary_data, list):
|
|
@@ -586,11 +586,11 @@ def brainblast_handler(command: str, **kwargs):
|
|
|
586
586
|
if not search_query:
|
|
587
587
|
return {"output": "Usage: /brainblast <search_terms>", "messages": messages}
|
|
588
588
|
|
|
589
|
-
|
|
589
|
+
|
|
590
590
|
command_history = kwargs.get('command_history')
|
|
591
591
|
if not command_history:
|
|
592
|
-
|
|
593
|
-
|
|
592
|
+
|
|
593
|
+
|
|
594
594
|
db_path = safe_get(kwargs, "history_db_path", os.path.expanduser('~/npcsh_history.db'))
|
|
595
595
|
try:
|
|
596
596
|
command_history = CommandHistory(db_path)
|
|
@@ -599,11 +599,11 @@ def brainblast_handler(command: str, **kwargs):
|
|
|
599
599
|
return {"output": f"Error connecting to command history: {e}", "messages": messages}
|
|
600
600
|
|
|
601
601
|
try:
|
|
602
|
-
|
|
602
|
+
|
|
603
603
|
if 'messages' in kwargs:
|
|
604
604
|
del kwargs['messages']
|
|
605
605
|
|
|
606
|
-
|
|
606
|
+
|
|
607
607
|
return execute_brainblast_command(
|
|
608
608
|
command=search_query,
|
|
609
609
|
**kwargs)
|
|
@@ -617,17 +617,17 @@ def rag_handler(command: str, **kwargs):
|
|
|
617
617
|
user_command = []
|
|
618
618
|
file_paths = []
|
|
619
619
|
|
|
620
|
-
i = 1
|
|
620
|
+
i = 1
|
|
621
621
|
while i < len(parts):
|
|
622
622
|
if parts[i] == "-f" or parts[i] == "--file":
|
|
623
|
-
|
|
623
|
+
|
|
624
624
|
if i + 1 < len(parts):
|
|
625
625
|
file_paths.append(parts[i + 1])
|
|
626
|
-
i += 2
|
|
626
|
+
i += 2
|
|
627
627
|
else:
|
|
628
628
|
return {"output": "Error: -f/--file flag needs a file path", "messages": messages}
|
|
629
629
|
else:
|
|
630
|
-
|
|
630
|
+
|
|
631
631
|
user_command.append(parts[i])
|
|
632
632
|
i += 1
|
|
633
633
|
|
|
@@ -641,7 +641,7 @@ def rag_handler(command: str, **kwargs):
|
|
|
641
641
|
return {"output": "Usage: /rag [-f file_path] <query>", "messages": kwargs.get('messages', [])}
|
|
642
642
|
|
|
643
643
|
try:
|
|
644
|
-
|
|
644
|
+
|
|
645
645
|
file_contents = []
|
|
646
646
|
for file_path in file_paths:
|
|
647
647
|
try:
|
|
@@ -718,7 +718,7 @@ def sample_handler(command: str, **kwargs):
|
|
|
718
718
|
"npc":kwargs.get("npc"),
|
|
719
719
|
}
|
|
720
720
|
else:
|
|
721
|
-
|
|
721
|
+
|
|
722
722
|
return {"output": str(result), "messages": messages}
|
|
723
723
|
|
|
724
724
|
except Exception as e:
|
|
@@ -728,16 +728,16 @@ def sample_handler(command: str, **kwargs):
|
|
|
728
728
|
def search_handler(command: str, **kwargs):
|
|
729
729
|
"""
|
|
730
730
|
Executes a search command.
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
737
|
"""
|
|
738
738
|
messages = safe_get(kwargs, "messages", [])
|
|
739
739
|
|
|
740
|
-
|
|
740
|
+
|
|
741
741
|
positional_args = safe_get(kwargs, 'positional_args', [])
|
|
742
742
|
query = " ".join(positional_args)
|
|
743
743
|
|
|
@@ -764,11 +764,11 @@ def search_handler(command: str, **kwargs):
|
|
|
764
764
|
|
|
765
765
|
@router.route("serve", "Serve an NPC Team")
|
|
766
766
|
def serve_handler(command: str, **kwargs):
|
|
767
|
-
|
|
768
|
-
|
|
767
|
+
|
|
768
|
+
|
|
769
769
|
|
|
770
770
|
port = safe_get(kwargs, "port", 5337)
|
|
771
|
-
|
|
771
|
+
|
|
772
772
|
messages = safe_get(kwargs, "messages", [])
|
|
773
773
|
cors = safe_get(kwargs, "cors", None)
|
|
774
774
|
if cors:
|
|
@@ -821,13 +821,13 @@ def sleep_handler(command: str, **kwargs):
|
|
|
821
821
|
if operations_str and isinstance(operations_str, str):
|
|
822
822
|
operations_config = [op.strip() for op in operations_str.split(',')]
|
|
823
823
|
|
|
824
|
-
|
|
824
|
+
|
|
825
825
|
team_name = team.name if team else "__none__"
|
|
826
826
|
npc_name = npc.name if isinstance(npc, NPC) else "__none__"
|
|
827
827
|
current_path = os.getcwd()
|
|
828
828
|
scope_str = f"Team: '{team_name}', NPC: '{npc_name}', Path: '{current_path}'"
|
|
829
829
|
|
|
830
|
-
|
|
830
|
+
|
|
831
831
|
render_markdown(f"- Checking knowledge graph for scope: {scope_str}")
|
|
832
832
|
|
|
833
833
|
try:
|
|
@@ -840,20 +840,20 @@ def sleep_handler(command: str, **kwargs):
|
|
|
840
840
|
try:
|
|
841
841
|
current_kg = load_kg_from_db(engine, team_name, npc_name, current_path)
|
|
842
842
|
|
|
843
|
-
|
|
843
|
+
|
|
844
844
|
if not current_kg or not current_kg.get('facts'):
|
|
845
845
|
output_msg = f"Knowledge graph for the current scope is empty. Nothing to process.\n"
|
|
846
846
|
output_msg += f" - Scope Checked: {scope_str}\n\n"
|
|
847
847
|
output_msg += "**Hint:** Have a conversation or run some commands first to build up knowledge in this specific context. The KG is unique to each combination of Team, NPC, and directory."
|
|
848
848
|
return {"output": output_msg, "messages": messages}
|
|
849
849
|
|
|
850
|
-
|
|
850
|
+
|
|
851
851
|
original_facts = len(current_kg.get('facts', []))
|
|
852
852
|
original_concepts = len(current_kg.get('concepts', []))
|
|
853
853
|
|
|
854
|
-
|
|
854
|
+
|
|
855
855
|
|
|
856
|
-
|
|
856
|
+
|
|
857
857
|
process_type = "Sleep"
|
|
858
858
|
ops_display = f"with operations: {operations_config}" if operations_config else "with random operations"
|
|
859
859
|
render_markdown(f"- Initiating sleep process {ops_display}")
|
|
@@ -866,7 +866,7 @@ def sleep_handler(command: str, **kwargs):
|
|
|
866
866
|
operations_config=operations_config
|
|
867
867
|
)
|
|
868
868
|
|
|
869
|
-
|
|
869
|
+
|
|
870
870
|
if is_dreaming:
|
|
871
871
|
process_type += " & Dream"
|
|
872
872
|
render_markdown(f"- Initiating dream process on the evolved KG...")
|
|
@@ -877,10 +877,10 @@ def sleep_handler(command: str, **kwargs):
|
|
|
877
877
|
npc=npc
|
|
878
878
|
)
|
|
879
879
|
|
|
880
|
-
|
|
880
|
+
|
|
881
881
|
save_kg_to_db(conn, evolved_kg, team_name, npc_name, current_path)
|
|
882
882
|
|
|
883
|
-
|
|
883
|
+
|
|
884
884
|
new_facts = len(evolved_kg.get('facts', []))
|
|
885
885
|
new_concepts = len(evolved_kg.get('concepts', []))
|
|
886
886
|
|
|
@@ -978,7 +978,7 @@ def vixynt_handler(command: str, **kwargs):
|
|
|
978
978
|
width = safe_get(kwargs, 'width', 1024)
|
|
979
979
|
output_file_base = safe_get(kwargs, 'output_file')
|
|
980
980
|
attachments = safe_get(kwargs, 'attachments')
|
|
981
|
-
n_images = safe_get(kwargs, 'n_images', 1)
|
|
981
|
+
n_images = safe_get(kwargs, 'n_images', 1)
|
|
982
982
|
if isinstance(attachments, str):
|
|
983
983
|
attachments = attachments.split(',')
|
|
984
984
|
|
|
@@ -990,7 +990,7 @@ def vixynt_handler(command: str, **kwargs):
|
|
|
990
990
|
return {"output": "Usage: /vixynt <prompt> [--output_file path] [--attachments path] [--n_images num]", "messages": messages}
|
|
991
991
|
|
|
992
992
|
try:
|
|
993
|
-
|
|
993
|
+
|
|
994
994
|
images_list = gen_image(
|
|
995
995
|
prompt=user_prompt,
|
|
996
996
|
model=model,
|
|
@@ -998,7 +998,7 @@ def vixynt_handler(command: str, **kwargs):
|
|
|
998
998
|
npc=npc,
|
|
999
999
|
height=height,
|
|
1000
1000
|
width=width,
|
|
1001
|
-
n_images=n_images,
|
|
1001
|
+
n_images=n_images,
|
|
1002
1002
|
input_images=attachments
|
|
1003
1003
|
)
|
|
1004
1004
|
|
|
@@ -1048,33 +1048,33 @@ def vixynt_handler(command: str, **kwargs):
|
|
|
1048
1048
|
def wander_handler(command: str, **kwargs):
|
|
1049
1049
|
messages = safe_get(kwargs, "messages", [])
|
|
1050
1050
|
|
|
1051
|
-
|
|
1051
|
+
|
|
1052
1052
|
try:
|
|
1053
1053
|
parts = shlex.split(command)
|
|
1054
1054
|
problem_parts = []
|
|
1055
1055
|
wander_params = {}
|
|
1056
1056
|
|
|
1057
|
-
i = 1
|
|
1057
|
+
i = 1
|
|
1058
1058
|
while i < len(parts):
|
|
1059
1059
|
part = parts[i]
|
|
1060
1060
|
|
|
1061
1061
|
if '=' in part:
|
|
1062
|
-
|
|
1062
|
+
|
|
1063
1063
|
key, initial_value = part.split('=', 1)
|
|
1064
1064
|
|
|
1065
|
-
|
|
1065
|
+
|
|
1066
1066
|
value_parts = [initial_value]
|
|
1067
1067
|
j = i + 1
|
|
1068
1068
|
while j < len(parts) and '=' not in parts[j]:
|
|
1069
1069
|
value_parts.append(parts[j])
|
|
1070
1070
|
j += 1
|
|
1071
1071
|
|
|
1072
|
-
|
|
1072
|
+
|
|
1073
1073
|
wander_params[key] = " ".join(value_parts)
|
|
1074
|
-
|
|
1074
|
+
|
|
1075
1075
|
i = j
|
|
1076
1076
|
else:
|
|
1077
|
-
|
|
1077
|
+
|
|
1078
1078
|
problem_parts.append(part)
|
|
1079
1079
|
i += 1
|
|
1080
1080
|
|
|
@@ -1086,13 +1086,13 @@ def wander_handler(command: str, **kwargs):
|
|
|
1086
1086
|
return {"output": "Usage: /wander <problem> [key=value...]", "messages": messages}
|
|
1087
1087
|
|
|
1088
1088
|
try:
|
|
1089
|
-
|
|
1089
|
+
|
|
1090
1090
|
mode_args = {
|
|
1091
1091
|
'problem': problem,
|
|
1092
1092
|
'npc': safe_get(kwargs, 'npc'),
|
|
1093
1093
|
'model': safe_get(kwargs, 'model'),
|
|
1094
1094
|
'provider': safe_get(kwargs, 'provider'),
|
|
1095
|
-
|
|
1095
|
+
|
|
1096
1096
|
'environment': wander_params.get('environment'),
|
|
1097
1097
|
'low_temp': float(wander_params.get('low-temp', 0.5)),
|
|
1098
1098
|
'high_temp': float(wander_params.get('high-temp', 1.9)),
|
|
@@ -1131,10 +1131,10 @@ def yap_handler(command: str, **kwargs):
|
|
|
1131
1131
|
def alicanto_handler(command: str, **kwargs):
|
|
1132
1132
|
messages = safe_get(kwargs, "messages", [])
|
|
1133
1133
|
|
|
1134
|
-
|
|
1134
|
+
|
|
1135
1135
|
parts = shlex.split(command)
|
|
1136
1136
|
|
|
1137
|
-
|
|
1137
|
+
|
|
1138
1138
|
query = ""
|
|
1139
1139
|
num_npcs = safe_get(kwargs, 'num_npcs', 5)
|
|
1140
1140
|
depth = safe_get(kwargs, 'depth', 3)
|
|
@@ -1142,11 +1142,11 @@ def alicanto_handler(command: str, **kwargs):
|
|
|
1142
1142
|
creativity_factor = safe_get(kwargs, 'creativity', 0.5)
|
|
1143
1143
|
output_format = safe_get(kwargs, 'format', 'report')
|
|
1144
1144
|
|
|
1145
|
-
|
|
1146
|
-
i = 1
|
|
1145
|
+
|
|
1146
|
+
i = 1
|
|
1147
1147
|
while i < len(parts):
|
|
1148
1148
|
if parts[i].startswith('--'):
|
|
1149
|
-
option = parts[i][2:]
|
|
1149
|
+
option = parts[i][2:]
|
|
1150
1150
|
if option in ['num-npcs', 'npcs']:
|
|
1151
1151
|
if i + 1 < len(parts) and parts[i + 1].isdigit():
|
|
1152
1152
|
num_npcs = int(parts[i + 1])
|
|
@@ -1178,16 +1178,16 @@ def alicanto_handler(command: str, **kwargs):
|
|
|
1178
1178
|
else:
|
|
1179
1179
|
i += 1
|
|
1180
1180
|
else:
|
|
1181
|
-
|
|
1181
|
+
|
|
1182
1182
|
i += 1
|
|
1183
1183
|
else:
|
|
1184
|
-
|
|
1184
|
+
|
|
1185
1185
|
query += parts[i] + " "
|
|
1186
1186
|
i += 1
|
|
1187
1187
|
|
|
1188
1188
|
query = query.strip()
|
|
1189
1189
|
|
|
1190
|
-
|
|
1190
|
+
|
|
1191
1191
|
if 'num_npcs' in kwargs:
|
|
1192
1192
|
try:
|
|
1193
1193
|
num_npcs = int(kwargs['num_npcs'])
|
|
@@ -1230,7 +1230,7 @@ def alicanto_handler(command: str, **kwargs):
|
|
|
1230
1230
|
output_format=output_format
|
|
1231
1231
|
)
|
|
1232
1232
|
|
|
1233
|
-
|
|
1233
|
+
|
|
1234
1234
|
if isinstance(result, dict):
|
|
1235
1235
|
if "integration" in result:
|
|
1236
1236
|
output = result["integration"]
|
npcsh/spool.py
CHANGED
|
@@ -51,10 +51,10 @@ def enter_spool_mode(
|
|
|
51
51
|
**kwargs,
|
|
52
52
|
) -> Dict:
|
|
53
53
|
print_spool_ascii()
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
command_history, state_team, default_npc = setup_shell()
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
spool_state = ShellState(
|
|
59
59
|
npc=npc or default_npc,
|
|
60
60
|
team=team or state_team,
|
|
@@ -65,7 +65,7 @@ def enter_spool_mode(
|
|
|
65
65
|
attachments=None,
|
|
66
66
|
)
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
|
|
69
69
|
if model:
|
|
70
70
|
spool_state.chat_model = model
|
|
71
71
|
if provider:
|
|
@@ -79,7 +79,7 @@ def enter_spool_mode(
|
|
|
79
79
|
print(f"🧵 Entering spool mode{npc_info}. Type '/sq' to exit spool mode.")
|
|
80
80
|
print("💡 Tip: Press Ctrl+C during streaming to interrupt and continue with a new message.")
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
loaded_chunks = {}
|
|
84
84
|
if attachments:
|
|
85
85
|
if isinstance(attachments, str):
|
|
@@ -97,14 +97,14 @@ def enter_spool_mode(
|
|
|
97
97
|
except Exception as e:
|
|
98
98
|
print(colored(f"Error loading {file_path}: {str(e)}", "red"))
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
|
|
101
101
|
if not spool_state.messages or spool_state.messages[0].get("role") != "system":
|
|
102
102
|
system_message = get_system_message(spool_state.npc) if spool_state.npc else "You are a helpful assistant."
|
|
103
103
|
spool_state.messages.insert(0, {"role": "system", "content": system_message})
|
|
104
104
|
|
|
105
105
|
while True:
|
|
106
106
|
try:
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
npc_name = spool_state.npc.name if spool_state.npc else "chat"
|
|
109
109
|
display_model = spool_state.npc.model if spool_state.npc and spool_state.npc.model else spool_state.chat_model
|
|
110
110
|
|
|
@@ -123,7 +123,7 @@ def enter_spool_mode(
|
|
|
123
123
|
spool_state.messages = enter_yap_mode(spool_state.messages, spool_state.npc)
|
|
124
124
|
continue
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
if user_input.startswith("/ots"):
|
|
128
128
|
command_parts = user_input.split()
|
|
129
129
|
image_paths = []
|
|
@@ -146,7 +146,7 @@ def enter_spool_mode(
|
|
|
146
146
|
|
|
147
147
|
vision_prompt = input("Prompt for image(s) (or press Enter): ").strip() or "Describe these images."
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
|
|
150
150
|
response = get_llm_response(
|
|
151
151
|
vision_prompt,
|
|
152
152
|
model=spool_state.vision_model,
|
|
@@ -162,11 +162,11 @@ def enter_spool_mode(
|
|
|
162
162
|
spool_state.messages = response.get('messages', spool_state.messages)
|
|
163
163
|
output = response.get('response')
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
|
|
166
166
|
process_result(vision_prompt, spool_state, {'output': output}, command_history)
|
|
167
167
|
continue
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
|
|
170
170
|
current_prompt = user_input
|
|
171
171
|
if loaded_chunks:
|
|
172
172
|
context_content = ""
|
|
@@ -183,7 +183,7 @@ def enter_spool_mode(
|
|
|
183
183
|
if context_content:
|
|
184
184
|
current_prompt += f"\n\n--- Relevant context from loaded files ---\n{context_content}"
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
|
|
187
187
|
response = get_llm_response(
|
|
188
188
|
current_prompt,
|
|
189
189
|
model=spool_state.npc.model if spool_state.npc and spool_state.npc.model else spool_state.chat_model,
|
|
@@ -197,7 +197,7 @@ def enter_spool_mode(
|
|
|
197
197
|
spool_state.messages = response.get('messages', spool_state.messages)
|
|
198
198
|
output = response.get('response')
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
|
|
201
201
|
process_result(current_prompt, spool_state, {'output': output}, command_history)
|
|
202
202
|
|
|
203
203
|
except (EOFError,):
|
|
@@ -221,7 +221,7 @@ def main():
|
|
|
221
221
|
|
|
222
222
|
args = parser.parse_args()
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
|
|
225
225
|
command_history, team, default_npc = setup_shell()
|
|
226
226
|
|
|
227
227
|
npc = None
|