npcsh 1.0.13__py3-none-any.whl → 1.0.16__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 +23 -41
- npcsh/npc.py +124 -98
- npcsh/npcsh.py +124 -77
- npcsh/routes.py +16 -28
- npcsh/yap.py +115 -106
- {npcsh-1.0.13.dist-info → npcsh-1.0.16.dist-info}/METADATA +108 -58
- {npcsh-1.0.13.dist-info → npcsh-1.0.16.dist-info}/RECORD +11 -11
- {npcsh-1.0.13.dist-info → npcsh-1.0.16.dist-info}/WHEEL +0 -0
- {npcsh-1.0.13.dist-info → npcsh-1.0.16.dist-info}/entry_points.txt +0 -0
- {npcsh-1.0.13.dist-info → npcsh-1.0.16.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.0.13.dist-info → npcsh-1.0.16.dist-info}/top_level.txt +0 -0
npcsh/npcsh.py
CHANGED
|
@@ -35,6 +35,7 @@ from npcsh._state import (
|
|
|
35
35
|
ShellState,
|
|
36
36
|
interactive_commands,
|
|
37
37
|
BASH_COMMANDS,
|
|
38
|
+
|
|
38
39
|
start_interactive_session,
|
|
39
40
|
validate_bash_command,
|
|
40
41
|
normalize_and_expand_flags,
|
|
@@ -663,11 +664,12 @@ def should_skip_kg_processing(user_input: str, assistant_output: str) -> bool:
|
|
|
663
664
|
return False
|
|
664
665
|
|
|
665
666
|
|
|
666
|
-
|
|
667
667
|
def execute_slash_command(command: str, stdin_input: Optional[str], state: ShellState, stream: bool) -> Tuple[ShellState, Any]:
|
|
668
668
|
"""Executes slash commands using the router or checking NPC/Team jinxs."""
|
|
669
669
|
all_command_parts = shlex.split(command)
|
|
670
670
|
command_name = all_command_parts[0].lstrip('/')
|
|
671
|
+
|
|
672
|
+
# Handle NPC switching commands
|
|
671
673
|
if command_name in ['n', 'npc']:
|
|
672
674
|
npc_to_switch_to = all_command_parts[1] if len(all_command_parts) > 1 else None
|
|
673
675
|
if npc_to_switch_to and state.team and npc_to_switch_to in state.team.npcs:
|
|
@@ -676,10 +678,11 @@ def execute_slash_command(command: str, stdin_input: Optional[str], state: Shell
|
|
|
676
678
|
else:
|
|
677
679
|
available_npcs = list(state.team.npcs.keys()) if state.team else []
|
|
678
680
|
return state, colored(f"NPC '{npc_to_switch_to}' not found. Available NPCs: {', '.join(available_npcs)}", "red")
|
|
681
|
+
|
|
682
|
+
# Check router commands first
|
|
679
683
|
handler = router.get_route(command_name)
|
|
680
684
|
if handler:
|
|
681
685
|
parsed_flags, positional_args = parse_generic_command_flags(all_command_parts[1:])
|
|
682
|
-
|
|
683
686
|
normalized_flags = normalize_and_expand_flags(parsed_flags)
|
|
684
687
|
|
|
685
688
|
handler_kwargs = {
|
|
@@ -704,38 +707,37 @@ def execute_slash_command(command: str, stdin_input: Optional[str], state: Shell
|
|
|
704
707
|
'igmodel': state.image_gen_model,
|
|
705
708
|
'igprovider': state.image_gen_provider,
|
|
706
709
|
'vgmodel': state.video_gen_model,
|
|
707
|
-
'vgprovider':state.video_gen_provider,
|
|
710
|
+
'vgprovider': state.video_gen_provider,
|
|
708
711
|
'vmodel': state.vision_model,
|
|
709
712
|
'vprovider': state.vision_provider,
|
|
710
713
|
'rmodel': state.reasoning_model,
|
|
711
714
|
'rprovider': state.reasoning_provider,
|
|
712
715
|
}
|
|
713
716
|
|
|
714
|
-
if len(normalized_flags)>0:
|
|
717
|
+
if len(normalized_flags) > 0:
|
|
715
718
|
kwarg_part = 'with kwargs: \n -' + '\n -'.join(f'{key}={item}' for key, item in normalized_flags.items())
|
|
716
719
|
else:
|
|
717
720
|
kwarg_part = ''
|
|
718
721
|
|
|
719
|
-
# 4. Merge the clean, normalized flags. This will correctly overwrite defaults.
|
|
720
722
|
render_markdown(f'- Calling {command_name} handler {kwarg_part} ')
|
|
723
|
+
|
|
724
|
+
# Handle model/provider inference
|
|
721
725
|
if 'model' in normalized_flags and 'provider' not in normalized_flags:
|
|
722
|
-
# Call your existing, centralized lookup_provider function
|
|
723
726
|
inferred_provider = lookup_provider(normalized_flags['model'])
|
|
724
727
|
if inferred_provider:
|
|
725
|
-
# Update the provider that will be used for this command.
|
|
726
728
|
handler_kwargs['provider'] = inferred_provider
|
|
727
729
|
print(colored(f"Info: Inferred provider '{inferred_provider}' for model '{normalized_flags['model']}'.", "cyan"))
|
|
730
|
+
|
|
728
731
|
if 'provider' in normalized_flags and 'model' not in normalized_flags:
|
|
729
|
-
# loop up mhandler_kwargs model's provider
|
|
730
732
|
current_provider = lookup_provider(handler_kwargs['model'])
|
|
731
733
|
if current_provider != normalized_flags['provider']:
|
|
732
|
-
|
|
733
|
-
|
|
734
|
+
prov = normalized_flags['provider']
|
|
735
|
+
print(f'Please specify a model for the provider: {prov}')
|
|
734
736
|
|
|
737
|
+
handler_kwargs.update(normalized_flags)
|
|
735
738
|
|
|
736
739
|
try:
|
|
737
740
|
result_dict = handler(command=command, **handler_kwargs)
|
|
738
|
-
# add the output model and provider for the print_and_process_stream downstream processing
|
|
739
741
|
if isinstance(result_dict, dict):
|
|
740
742
|
state.messages = result_dict.get("messages", state.messages)
|
|
741
743
|
return state, result_dict
|
|
@@ -746,39 +748,64 @@ def execute_slash_command(command: str, stdin_input: Optional[str], state: Shell
|
|
|
746
748
|
print(f"Error executing slash command '{command_name}':", file=sys.stderr)
|
|
747
749
|
traceback.print_exc()
|
|
748
750
|
return state, colored(f"Error executing slash command '{command_name}': {e}", "red")
|
|
751
|
+
|
|
752
|
+
# Check for jinxs in active NPC
|
|
749
753
|
active_npc = state.npc if isinstance(state.npc, NPC) else None
|
|
750
754
|
jinx_to_execute = None
|
|
751
755
|
executor = None
|
|
752
|
-
|
|
756
|
+
|
|
757
|
+
if active_npc and hasattr(active_npc, 'jinxs_dict') and command_name in active_npc.jinxs_dict:
|
|
753
758
|
jinx_to_execute = active_npc.jinxs_dict[command_name]
|
|
754
759
|
executor = active_npc
|
|
755
|
-
elif state.team and command_name in state.team.jinxs_dict:
|
|
760
|
+
elif state.team and hasattr(state.team, 'jinxs_dict') and command_name in state.team.jinxs_dict:
|
|
756
761
|
jinx_to_execute = state.team.jinxs_dict[command_name]
|
|
757
762
|
executor = state.team
|
|
758
|
-
|
|
759
763
|
if jinx_to_execute:
|
|
760
|
-
args =
|
|
764
|
+
args = all_command_parts[1:] # Fix: use all_command_parts instead of command_parts
|
|
761
765
|
try:
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
766
|
+
# Create input dictionary from args based on jinx inputs
|
|
767
|
+
input_values = {}
|
|
768
|
+
if hasattr(jinx_to_execute, 'inputs') and jinx_to_execute.inputs:
|
|
769
|
+
for i, input_name in enumerate(jinx_to_execute.inputs):
|
|
770
|
+
if i < len(args):
|
|
771
|
+
input_values[input_name] = args[i]
|
|
772
|
+
|
|
773
|
+
# Execute the jinx with proper parameters
|
|
774
|
+
if isinstance(executor, NPC):
|
|
775
|
+
jinx_output = jinx_to_execute.execute(
|
|
776
|
+
input_values=input_values,
|
|
777
|
+
jinxs_dict=executor.jinxs_dict if hasattr(executor, 'jinxs_dict') else {},
|
|
778
|
+
npc=executor,
|
|
779
|
+
messages=state.messages
|
|
780
|
+
)
|
|
781
|
+
else: # Team executor
|
|
782
|
+
jinx_output = jinx_to_execute.execute(
|
|
783
|
+
input_values=input_values,
|
|
784
|
+
jinxs_dict=executor.jinxs_dict if hasattr(executor, 'jinxs_dict') else {},
|
|
785
|
+
npc=active_npc or state.npc,
|
|
786
|
+
messages=state.messages
|
|
787
|
+
)
|
|
788
|
+
if isinstance(jinx_output, dict) and 'messages' in jinx_output:
|
|
789
|
+
state.messages = jinx_output['messages']
|
|
790
|
+
return state, str(jinx_output.get('output', jinx_output))
|
|
791
|
+
elif isinstance(jinx_output, dict):
|
|
792
|
+
return state, str(jinx_output.get('output', jinx_output))
|
|
793
|
+
else:
|
|
794
|
+
return state, jinx_output
|
|
795
|
+
|
|
769
796
|
except Exception as e:
|
|
770
797
|
import traceback
|
|
771
798
|
print(f"Error executing jinx '{command_name}':", file=sys.stderr)
|
|
772
799
|
traceback.print_exc()
|
|
773
800
|
return state, colored(f"Error executing jinx '{command_name}': {e}", "red")
|
|
774
801
|
|
|
802
|
+
# Check if it's an NPC name for switching
|
|
775
803
|
if state.team and command_name in state.team.npcs:
|
|
776
804
|
new_npc = state.team.npcs[command_name]
|
|
777
|
-
state.npc = new_npc
|
|
805
|
+
state.npc = new_npc
|
|
778
806
|
return state, f"Switched to NPC: {new_npc.name}"
|
|
779
807
|
|
|
780
|
-
return state, colored(f"Unknown slash command or
|
|
781
|
-
|
|
808
|
+
return state, colored(f"Unknown slash command, jinx, or NPC: {command_name}", "red")
|
|
782
809
|
|
|
783
810
|
def process_pipeline_command(
|
|
784
811
|
cmd_segment: str,
|
|
@@ -892,9 +919,14 @@ def execute_command(
|
|
|
892
919
|
active_provider = npc_provider or state.chat_provider
|
|
893
920
|
|
|
894
921
|
if state.current_mode == 'agent':
|
|
922
|
+
print('# of parsed commands: ', len(commands))
|
|
923
|
+
print('Commands:' '\n'.join(commands))
|
|
895
924
|
for i, cmd_segment in enumerate(commands):
|
|
925
|
+
|
|
926
|
+
render_markdown(f'- executing command {i+1}/{len(commands)}')
|
|
896
927
|
is_last_command = (i == len(commands) - 1)
|
|
897
|
-
|
|
928
|
+
|
|
929
|
+
stream_this_segment = state.stream_output and not is_last_command
|
|
898
930
|
|
|
899
931
|
try:
|
|
900
932
|
current_state, output = process_pipeline_command(
|
|
@@ -905,17 +937,18 @@ def execute_command(
|
|
|
905
937
|
)
|
|
906
938
|
|
|
907
939
|
if is_last_command:
|
|
908
|
-
|
|
940
|
+
return current_state, output
|
|
909
941
|
if isinstance(output, str):
|
|
910
942
|
stdin_for_next = output
|
|
911
943
|
elif not isinstance(output, str):
|
|
912
944
|
try:
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
945
|
+
if stream_this_segment:
|
|
946
|
+
full_stream_output = print_and_process_stream_with_markdown(output,
|
|
947
|
+
state.npc.model,
|
|
948
|
+
state.npc.provider)
|
|
949
|
+
stdin_for_next = full_stream_output
|
|
950
|
+
if is_last_command:
|
|
951
|
+
final_output = full_stream_output
|
|
919
952
|
except:
|
|
920
953
|
if output is not None: # Try converting other types to string
|
|
921
954
|
try:
|
|
@@ -964,7 +997,7 @@ def execute_command(
|
|
|
964
997
|
else:
|
|
965
998
|
try:
|
|
966
999
|
bash_state, bash_output = handle_bash_command(cmd_parts, command, None, state)
|
|
967
|
-
return
|
|
1000
|
+
return state, bash_output
|
|
968
1001
|
except Exception as bash_err:
|
|
969
1002
|
return state, colored(f"Bash execution failed: {bash_err}", "red")
|
|
970
1003
|
except Exception:
|
|
@@ -1064,6 +1097,13 @@ def setup_shell() -> Tuple[CommandHistory, Team, Optional[NPC]]:
|
|
|
1064
1097
|
command_history = CommandHistory(db_path)
|
|
1065
1098
|
|
|
1066
1099
|
|
|
1100
|
+
if not is_npcsh_initialized():
|
|
1101
|
+
print("Initializing NPCSH...")
|
|
1102
|
+
initialize_base_npcs_if_needed(db_path)
|
|
1103
|
+
print("NPCSH initialization complete. Restart or source ~/.npcshrc.")
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1067
1107
|
try:
|
|
1068
1108
|
history_file = setup_readline()
|
|
1069
1109
|
atexit.register(save_readline_history)
|
|
@@ -1157,7 +1197,8 @@ def setup_shell() -> Tuple[CommandHistory, Team, Optional[NPC]]:
|
|
|
1157
1197
|
|
|
1158
1198
|
if os.path.exists(forenpc_path):
|
|
1159
1199
|
forenpc_obj = NPC(file = forenpc_path,
|
|
1160
|
-
jinxs=jinxs_list
|
|
1200
|
+
jinxs=jinxs_list,
|
|
1201
|
+
db_conn=command_history.engine)
|
|
1161
1202
|
if forenpc_obj.model is None:
|
|
1162
1203
|
forenpc_obj.model= team_ctx.get("model", initial_state.chat_model)
|
|
1163
1204
|
if forenpc_obj.provider is None:
|
|
@@ -1200,9 +1241,7 @@ def process_result(
|
|
|
1200
1241
|
output: Any,
|
|
1201
1242
|
command_history: CommandHistory
|
|
1202
1243
|
):
|
|
1203
|
-
# --- Part 1: Save Conversation & Determine Output ---
|
|
1204
1244
|
|
|
1205
|
-
# Define team and NPC names early for consistent logging
|
|
1206
1245
|
team_name = result_state.team.name if result_state.team else "__none__"
|
|
1207
1246
|
npc_name = result_state.npc.name if isinstance(result_state.npc, NPC) else "__none__"
|
|
1208
1247
|
|
|
@@ -1210,9 +1249,8 @@ def process_result(
|
|
|
1210
1249
|
active_npc = result_state.npc if isinstance(result_state.npc, NPC) else NPC(
|
|
1211
1250
|
name="default",
|
|
1212
1251
|
model=result_state.chat_model,
|
|
1213
|
-
provider=result_state.chat_provider
|
|
1214
|
-
|
|
1215
|
-
|
|
1252
|
+
provider=result_state.chat_provider,
|
|
1253
|
+
db_conn=command_history.engine)
|
|
1216
1254
|
save_conversation_message(
|
|
1217
1255
|
command_history,
|
|
1218
1256
|
result_state.conversation_id,
|
|
@@ -1260,39 +1298,42 @@ def process_result(
|
|
|
1260
1298
|
)
|
|
1261
1299
|
|
|
1262
1300
|
conversation_turn_text = f"User: {user_input}\nAssistant: {final_output_str}"
|
|
1263
|
-
|
|
1301
|
+
engine = command_history.engine
|
|
1264
1302
|
|
|
1265
|
-
try:
|
|
1266
|
-
if not should_skip_kg_processing(user_input, final_output_str):
|
|
1267
|
-
|
|
1268
|
-
npc_kg = load_kg_from_db(conn, team_name, npc_name, result_state.current_path)
|
|
1269
|
-
evolved_npc_kg, _ = kg_evolve_incremental(
|
|
1270
|
-
existing_kg=npc_kg,
|
|
1271
|
-
new_content_text=conversation_turn_text,
|
|
1272
|
-
model=active_npc.model,
|
|
1273
|
-
provider=active_npc.provider,
|
|
1274
|
-
get_concepts=True,
|
|
1275
|
-
link_concepts_facts = False,
|
|
1276
|
-
link_concepts_concepts = False,
|
|
1277
|
-
link_facts_facts = False,
|
|
1278
1303
|
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1304
|
+
if result_state.build_kg:
|
|
1305
|
+
try:
|
|
1306
|
+
if not should_skip_kg_processing(user_input, final_output_str):
|
|
1307
|
+
|
|
1308
|
+
npc_kg = load_kg_from_db(engine, team_name, npc_name, result_state.current_path)
|
|
1309
|
+
evolved_npc_kg, _ = kg_evolve_incremental(
|
|
1310
|
+
existing_kg=npc_kg,
|
|
1311
|
+
new_content_text=conversation_turn_text,
|
|
1312
|
+
model=active_npc.model,
|
|
1313
|
+
provider=active_npc.provider,
|
|
1314
|
+
get_concepts=True,
|
|
1315
|
+
link_concepts_facts = False,
|
|
1316
|
+
link_concepts_concepts = False,
|
|
1317
|
+
link_facts_facts = False,
|
|
1318
|
+
|
|
1319
|
+
|
|
1320
|
+
)
|
|
1321
|
+
save_kg_to_db(engine,
|
|
1322
|
+
evolved_npc_kg,
|
|
1323
|
+
team_name,
|
|
1324
|
+
npc_name,
|
|
1325
|
+
result_state.current_path)
|
|
1326
|
+
except Exception as e:
|
|
1327
|
+
print(colored(f"Error during real-time KG evolution: {e}", "red"))
|
|
1288
1328
|
|
|
1289
1329
|
# --- Part 3: Periodic Team Context Suggestions ---
|
|
1290
1330
|
result_state.turn_count += 1
|
|
1331
|
+
|
|
1291
1332
|
if result_state.turn_count > 0 and result_state.turn_count % 10 == 0:
|
|
1292
1333
|
print(colored("\nChecking for potential team improvements...", "cyan"))
|
|
1293
1334
|
try:
|
|
1294
1335
|
summary = breathe(messages=result_state.messages[-20:],
|
|
1295
|
-
|
|
1336
|
+
npc=active_npc)
|
|
1296
1337
|
characterization = summary.get('output')
|
|
1297
1338
|
|
|
1298
1339
|
if characterization and result_state.team:
|
|
@@ -1300,7 +1341,7 @@ def process_result(
|
|
|
1300
1341
|
ctx_data = {}
|
|
1301
1342
|
if os.path.exists(team_ctx_path):
|
|
1302
1343
|
with open(team_ctx_path, 'r') as f:
|
|
1303
|
-
|
|
1344
|
+
ctx_data = yaml.safe_load(f) or {}
|
|
1304
1345
|
current_context = ctx_data.get('context', '')
|
|
1305
1346
|
|
|
1306
1347
|
prompt = f"""Based on this characterization: {characterization},
|
|
@@ -1317,7 +1358,7 @@ def process_result(
|
|
|
1317
1358
|
|
|
1318
1359
|
if suggestion:
|
|
1319
1360
|
new_context = (current_context + " " + suggestion).strip()
|
|
1320
|
-
print(colored("
|
|
1361
|
+
print(colored(f"{result_state.npc.name} suggests updating team context:", "yellow"))
|
|
1321
1362
|
print(f" - OLD: {current_context}\n + NEW: {new_context}")
|
|
1322
1363
|
if input("Apply? [y/N]: ").strip().lower() == 'y':
|
|
1323
1364
|
ctx_data['context'] = new_context
|
|
@@ -1360,15 +1401,14 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
|
|
|
1360
1401
|
print("\nGoodbye!")
|
|
1361
1402
|
print(colored("Processing and archiving all session knowledge...", "cyan"))
|
|
1362
1403
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1404
|
+
engine = command_history.engine
|
|
1405
|
+
|
|
1365
1406
|
|
|
1366
|
-
# Process each unique scope that was active during the session
|
|
1367
1407
|
for team_name, npc_name, path in session_scopes:
|
|
1368
1408
|
try:
|
|
1369
1409
|
print(f" -> Archiving knowledge for: T='{team_name}', N='{npc_name}', P='{path}'")
|
|
1370
1410
|
|
|
1371
|
-
|
|
1411
|
+
|
|
1372
1412
|
convo_id = current_state.conversation_id
|
|
1373
1413
|
all_messages = command_history.get_conversations_by_id(convo_id)
|
|
1374
1414
|
|
|
@@ -1383,15 +1423,16 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
|
|
|
1383
1423
|
print(" ...No content for this scope, skipping.")
|
|
1384
1424
|
continue
|
|
1385
1425
|
|
|
1386
|
-
|
|
1387
|
-
current_kg = load_kg_from_db(
|
|
1426
|
+
|
|
1427
|
+
current_kg = load_kg_from_db(engine, team_name, npc_name, path)
|
|
1388
1428
|
|
|
1389
|
-
|
|
1429
|
+
|
|
1390
1430
|
evolved_kg, _ = kg_evolve_incremental(
|
|
1391
1431
|
existing_kg=current_kg,
|
|
1392
1432
|
new_content_text=full_text,
|
|
1393
|
-
model=
|
|
1394
|
-
provider=
|
|
1433
|
+
model=current_state.npc.model,
|
|
1434
|
+
provider=current_state.npc.provider,
|
|
1435
|
+
npc= current_state.npc,
|
|
1395
1436
|
get_concepts=True,
|
|
1396
1437
|
link_concepts_facts = True,
|
|
1397
1438
|
link_concepts_concepts = True,
|
|
@@ -1400,7 +1441,11 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
|
|
|
1400
1441
|
)
|
|
1401
1442
|
|
|
1402
1443
|
# Save the updated KG back to the database under the same exact scope
|
|
1403
|
-
save_kg_to_db(
|
|
1444
|
+
save_kg_to_db(engine,
|
|
1445
|
+
evolved_kg,
|
|
1446
|
+
team_name,
|
|
1447
|
+
npc_name,
|
|
1448
|
+
path)
|
|
1404
1449
|
|
|
1405
1450
|
except Exception as e:
|
|
1406
1451
|
import traceback
|
|
@@ -1458,7 +1503,8 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
|
|
|
1458
1503
|
session_scopes.add((team_name, npc_name, state.current_path))
|
|
1459
1504
|
|
|
1460
1505
|
state, output = execute_command(user_input, state)
|
|
1461
|
-
process_result(user_input,
|
|
1506
|
+
process_result(user_input,
|
|
1507
|
+
state,
|
|
1462
1508
|
output,
|
|
1463
1509
|
command_history)
|
|
1464
1510
|
|
|
@@ -1488,6 +1534,7 @@ def main() -> None:
|
|
|
1488
1534
|
initial_state.npc = default_npc
|
|
1489
1535
|
initial_state.team = team
|
|
1490
1536
|
|
|
1537
|
+
|
|
1491
1538
|
# add a -g global command to indicate if to use the global or project, otherwise go thru normal flow
|
|
1492
1539
|
|
|
1493
1540
|
if args.command:
|
npcsh/routes.py
CHANGED
|
@@ -18,7 +18,6 @@ from npcpy.llm_funcs import (
|
|
|
18
18
|
gen_video,
|
|
19
19
|
breathe,
|
|
20
20
|
)
|
|
21
|
-
from npcpy.npc_compiler import NPC, Team, Jinx
|
|
22
21
|
from npcpy.npc_compiler import initialize_npc_project
|
|
23
22
|
from npcpy.npc_sysenv import render_markdown
|
|
24
23
|
from npcpy.work.plan import execute_plan_command
|
|
@@ -29,8 +28,7 @@ from npcpy.memory.command_history import CommandHistory, load_kg_from_db, save_k
|
|
|
29
28
|
from npcpy.serve import start_flask_server
|
|
30
29
|
from npcpy.mix.debate import run_debate
|
|
31
30
|
from npcpy.data.image import capture_screenshot
|
|
32
|
-
from npcpy.npc_compiler import NPC, Team, Jinx
|
|
33
|
-
from npcpy.npc_compiler import initialize_npc_project
|
|
31
|
+
from npcpy.npc_compiler import NPC, Team, Jinx,initialize_npc_project
|
|
34
32
|
from npcpy.data.web import search_web
|
|
35
33
|
from npcpy.memory.knowledge_graph import kg_sleep_process, kg_dream_process
|
|
36
34
|
|
|
@@ -446,13 +444,13 @@ def plan_handler(command: str, **kwargs):
|
|
|
446
444
|
user_command = " ".join(command.split()[1:])
|
|
447
445
|
if not user_command:
|
|
448
446
|
return {"output": "Usage: /plan <description_of_plan>", "messages": messages}
|
|
449
|
-
try:
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
except Exception as e:
|
|
454
|
-
|
|
455
|
-
|
|
447
|
+
#try:
|
|
448
|
+
return execute_plan_command(command=user_command, **kwargs)
|
|
449
|
+
|
|
450
|
+
#return {"output": "Plan function (execute_plan_command) not available.", "messages": messages}
|
|
451
|
+
#except Exception as e:
|
|
452
|
+
# traceback.print_exc()
|
|
453
|
+
# return {"output": f"Error executing plan: {e}", "messages": messages}
|
|
456
454
|
|
|
457
455
|
@router.route("pti", "Use pardon-the-interruption mode to interact with the LLM")
|
|
458
456
|
def pti_handler(command: str, **kwargs):
|
|
@@ -500,17 +498,18 @@ def brainblast_handler(command: str, **kwargs):
|
|
|
500
498
|
parts = shlex.split(command)
|
|
501
499
|
search_query = " ".join(parts[1:]) if len(parts) > 1 else ""
|
|
502
500
|
|
|
503
|
-
|
|
504
501
|
if not search_query:
|
|
505
502
|
return {"output": "Usage: /brainblast <search_terms>", "messages": messages}
|
|
506
503
|
|
|
507
504
|
# Get the command history instance
|
|
508
505
|
command_history = kwargs.get('command_history')
|
|
509
506
|
if not command_history:
|
|
507
|
+
#print('no command history provided to brainblast')
|
|
510
508
|
# Create a new one if not provided
|
|
511
509
|
db_path = safe_get(kwargs, "history_db_path", os.path.expanduser('~/npcsh_history.db'))
|
|
512
510
|
try:
|
|
513
511
|
command_history = CommandHistory(db_path)
|
|
512
|
+
kwargs['command_history'] = command_history
|
|
514
513
|
except Exception as e:
|
|
515
514
|
return {"output": f"Error connecting to command history: {e}", "messages": messages}
|
|
516
515
|
|
|
@@ -521,13 +520,8 @@ def brainblast_handler(command: str, **kwargs):
|
|
|
521
520
|
|
|
522
521
|
# Execute the brainblast command
|
|
523
522
|
return execute_brainblast_command(
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
messages=messages,
|
|
527
|
-
top_k=safe_get(kwargs, 'top_k', 5),
|
|
528
|
-
**kwargs
|
|
529
|
-
)
|
|
530
|
-
|
|
523
|
+
command=search_query,
|
|
524
|
+
**kwargs)
|
|
531
525
|
except Exception as e:
|
|
532
526
|
traceback.print_exc()
|
|
533
527
|
return {"output": f"Error executing brainblast command: {e}", "messages": messages}
|
|
@@ -757,12 +751,12 @@ def sleep_handler(command: str, **kwargs):
|
|
|
757
751
|
try:
|
|
758
752
|
db_path = os.getenv("NPCSH_DB_PATH", os.path.expanduser("~/npcsh_history.db"))
|
|
759
753
|
command_history = CommandHistory(db_path)
|
|
760
|
-
|
|
754
|
+
engine = command_history.engine
|
|
761
755
|
except Exception as e:
|
|
762
756
|
return {"output": f"Error connecting to history database for KG access: {e}", "messages": messages}
|
|
763
757
|
|
|
764
758
|
try:
|
|
765
|
-
current_kg = load_kg_from_db(
|
|
759
|
+
current_kg = load_kg_from_db(engine, team_name, npc_name, current_path)
|
|
766
760
|
|
|
767
761
|
# FIXED: Provide a detailed and helpful message when the KG is empty
|
|
768
762
|
if not current_kg or not current_kg.get('facts'):
|
|
@@ -1031,16 +1025,10 @@ def wander_handler(command: str, **kwargs):
|
|
|
1031
1025
|
return {"output": f"Error during wander mode: {e}", "messages": messages}
|
|
1032
1026
|
|
|
1033
1027
|
@router.route("yap", "Enter voice chat (yap) mode")
|
|
1034
|
-
def
|
|
1028
|
+
def yap_handler(command: str, **kwargs):
|
|
1035
1029
|
try:
|
|
1036
1030
|
return enter_yap_mode(
|
|
1037
|
-
|
|
1038
|
-
npc=safe_get(kwargs, 'npc'),
|
|
1039
|
-
model=safe_get(kwargs, 'model', NPCSH_CHAT_MODEL),
|
|
1040
|
-
provider=safe_get(kwargs, 'provider', NPCSH_CHAT_PROVIDER),
|
|
1041
|
-
team=safe_get(kwargs, 'team'),
|
|
1042
|
-
stream=safe_get(kwargs, 'stream', NPCSH_STREAM_OUTPUT),
|
|
1043
|
-
conversation_id=safe_get(kwargs, 'conversation_id')
|
|
1031
|
+
** kwargs
|
|
1044
1032
|
)
|
|
1045
1033
|
except Exception as e:
|
|
1046
1034
|
traceback.print_exc()
|