npcsh 1.1.20__py3-none-any.whl → 1.1.21__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 +5 -71
- npcsh/diff_viewer.py +3 -3
- npcsh/npc_team/jinxs/lib/core/compress.jinx +373 -85
- npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +17 -6
- npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +17 -6
- npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +19 -8
- npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +52 -14
- npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
- npcsh/npc_team/jinxs/{bin → lib/utils}/jinxs.jinx +12 -12
- npcsh/npc_team/jinxs/{bin → lib/utils}/models.jinx +7 -7
- npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +6 -6
- npcsh/npc_team/jinxs/modes/alicanto.jinx +1573 -296
- npcsh/npc_team/jinxs/modes/arxiv.jinx +5 -5
- npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
- npcsh/npc_team/jinxs/modes/corca.jinx +3 -3
- npcsh/npc_team/jinxs/modes/git.jinx +795 -0
- {npcsh-1.1.20.data/data/npcsh/npc_team → npcsh/npc_team/jinxs/modes}/kg.jinx +13 -13
- npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
- npcsh/npc_team/jinxs/{bin → modes}/nql.jinx +10 -21
- npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
- npcsh/npc_team/jinxs/modes/plonk.jinx +490 -304
- npcsh/npc_team/jinxs/modes/reattach.jinx +3 -3
- npcsh/npc_team/jinxs/modes/spool.jinx +3 -3
- npcsh/npc_team/jinxs/{bin → modes}/team.jinx +12 -12
- npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
- npcsh/npc_team/jinxs/modes/wander.jinx +454 -181
- npcsh/npc_team/jinxs/modes/yap.jinx +10 -3
- npcsh/npcsh.py +112 -47
- npcsh/routes.py +4 -1
- npcsh/salmon_simulation.py +0 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/alicanto.jinx +1633 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/arxiv.jinx +5 -5
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/benchmark.jinx +2 -2
- npcsh-1.1.21.data/data/npcsh/npc_team/compress.jinx +428 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/config_tui.jinx +300 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/db_search.jinx +17 -6
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/file_search.jinx +17 -6
- npcsh-1.1.21.data/data/npcsh/npc_team/git.jinx +795 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/jinxs.jinx +12 -12
- {npcsh/npc_team/jinxs/bin → npcsh-1.1.21.data/data/npcsh/npc_team}/kg.jinx +13 -13
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kg_search.jinx +19 -8
- npcsh-1.1.21.data/data/npcsh/npc_team/memories.jinx +414 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/models.jinx +7 -7
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/nql.jinx +10 -21
- npcsh-1.1.21.data/data/npcsh/npc_team/papers.jinx +578 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/plonk.jinx +565 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/reattach.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/setup.jinx +6 -6
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.jinx +3 -3
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/team.jinx +12 -12
- npcsh-1.1.21.data/data/npcsh/npc_team/vixynt.jinx +388 -0
- npcsh-1.1.21.data/data/npcsh/npc_team/wander.jinx +728 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/web_search.jinx +52 -14
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.jinx +10 -3
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/METADATA +2 -2
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/RECORD +145 -150
- npcsh-1.1.21.dist-info/entry_points.txt +11 -0
- npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -300
- npcsh/npc_team/jinxs/bin/memories.jinx +0 -317
- npcsh/npc_team/jinxs/bin/vixynt.jinx +0 -122
- npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +0 -73
- npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +0 -388
- npcsh/npc_team/jinxs/lib/research/paper_search.jinx +0 -412
- npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +0 -386
- npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.20.data/data/npcsh/npc_team/alicanto.jinx +0 -356
- npcsh-1.1.20.data/data/npcsh/npc_team/compress.jinx +0 -140
- npcsh-1.1.20.data/data/npcsh/npc_team/config_tui.jinx +0 -300
- npcsh-1.1.20.data/data/npcsh/npc_team/mem_review.jinx +0 -73
- npcsh-1.1.20.data/data/npcsh/npc_team/mem_search.jinx +0 -388
- npcsh-1.1.20.data/data/npcsh/npc_team/memories.jinx +0 -317
- npcsh-1.1.20.data/data/npcsh/npc_team/paper_search.jinx +0 -412
- npcsh-1.1.20.data/data/npcsh/npc_team/plonk.jinx +0 -379
- npcsh-1.1.20.data/data/npcsh/npc_team/plonkjr.npc +0 -23
- npcsh-1.1.20.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
- npcsh-1.1.20.data/data/npcsh/npc_team/vixynt.jinx +0 -122
- npcsh-1.1.20.data/data/npcsh/npc_team/wander.jinx +0 -455
- npcsh-1.1.20.dist-info/entry_points.txt +0 -25
- /npcsh/npc_team/jinxs/lib/{orchestration → core}/convene.jinx +0 -0
- /npcsh/npc_team/jinxs/lib/{orchestration → core}/delegate.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → lib/core}/sample.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → lib/utils}/sync.jinx +0 -0
- /npcsh/npc_team/jinxs/{bin → modes}/roll.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/build.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/chat.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/click.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/cmd.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/compile.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/confirm.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/convene.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca_example.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/delegate.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic4.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/help.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/incognide.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/init.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/key_press.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/load_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/navigate.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/notify.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/ots.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/paste.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonkjr.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/pti.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/python.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/roll.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sample.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/search.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/send_message.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/serve.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/set.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sh.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/shh.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.npc +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sleep.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sql.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switches.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sync.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/trigger.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/type_text.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/usage.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/verbose.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/wait.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/write_file.jinx +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.png +0 -0
- {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/WHEEL +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/licenses/LICENSE +0 -0
- {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/top_level.txt +0 -0
|
@@ -417,7 +417,7 @@ steps:
|
|
|
417
417
|
header = " ARXIV: '" + query + "' (" + str(len(papers)) + " papers) [sort:" + sort_key + "] "
|
|
418
418
|
else:
|
|
419
419
|
header = " " + papers[selected]['title'][:width-4] + " "
|
|
420
|
-
sys.stdout.write('\033[
|
|
420
|
+
sys.stdout.write('\033[7;1m' + header.ljust(width) + '\033[0m\n')
|
|
421
421
|
|
|
422
422
|
if mode == 'list':
|
|
423
423
|
# Column headers
|
|
@@ -456,7 +456,7 @@ steps:
|
|
|
456
456
|
sys.stdout.write(' ' + line)
|
|
457
457
|
|
|
458
458
|
sys.stdout.write('\033[' + str(height-1) + ';1H\033[K\033[90m' + ("─" * width) + '\033[0m')
|
|
459
|
-
sys.stdout.write('\033[' + str(height) + ';1H\033[K\033[
|
|
459
|
+
sys.stdout.write('\033[' + str(height) + ';1H\033[K\033[7m j/k:Nav Enter:View o/i/p:Open d:Download 1-3:Sort y/a:Filter c:Clear q:Quit [' + str(selected+1) + '/' + str(len(papers)) + '] \033[0m')
|
|
460
460
|
|
|
461
461
|
elif mode == 'detail':
|
|
462
462
|
sys.stdout.write('\033[90m' + ("─" * width) + '\033[0m\n')
|
|
@@ -489,13 +489,13 @@ steps:
|
|
|
489
489
|
sys.stdout.write(' ' + lines[idx][:width-4])
|
|
490
490
|
|
|
491
491
|
sys.stdout.write('\033[' + str(height-1) + ';1H\033[K\033[90m' + ("─" * width) + '\033[0m')
|
|
492
|
-
sys.stdout.write('\033[' + str(height) + ';1H\033[K\033[
|
|
492
|
+
sys.stdout.write('\033[' + str(height) + ';1H\033[K\033[7m j/k:Scroll b:Back o:Browser i:Incognide p:PDF d:Download v:TermView q:Quit \033[0m')
|
|
493
493
|
|
|
494
494
|
elif mode == 'pdfview':
|
|
495
495
|
# PDF terminal view mode
|
|
496
496
|
p = papers[selected]
|
|
497
497
|
header = " PDF VIEW: " + p['aid'] + " "
|
|
498
|
-
sys.stdout.write('\033[
|
|
498
|
+
sys.stdout.write('\033[7;1m' + header.ljust(width) + '\033[0m\n')
|
|
499
499
|
sys.stdout.write('\033[90m' + ("─" * width) + '\033[0m\n')
|
|
500
500
|
|
|
501
501
|
view_height = height - 4
|
|
@@ -510,7 +510,7 @@ steps:
|
|
|
510
510
|
|
|
511
511
|
sys.stdout.write('\033[' + str(height-1) + ';1H\033[K\033[90m' + ("─" * width) + '\033[0m')
|
|
512
512
|
pct = int((pdf_scroll / max(1, len(pdf_lines) - view_height)) * 100) if len(pdf_lines) > view_height else 100
|
|
513
|
-
sys.stdout.write('\033[' + str(height) + ';1H\033[K\033[
|
|
513
|
+
sys.stdout.write('\033[' + str(height) + ';1H\033[K\033[7m j/k/PgDn/PgUp:Scroll b:Back d:Download q:Quit [' + str(pct) + '%] \033[0m')
|
|
514
514
|
|
|
515
515
|
sys.stdout.flush()
|
|
516
516
|
|
|
@@ -23,7 +23,7 @@ steps:
|
|
|
23
23
|
if not model:
|
|
24
24
|
model = npc.model if npc and npc.model else ""
|
|
25
25
|
if not provider:
|
|
26
|
-
provider = npc.provider if npc and npc.provider else "
|
|
26
|
+
provider = npc.provider if npc and npc.provider else ""
|
|
27
27
|
|
|
28
28
|
try:
|
|
29
29
|
from npcsh.benchmark import BenchmarkRunner, run_benchmark
|
|
@@ -56,7 +56,7 @@ steps:
|
|
|
56
56
|
output += "\n### Usage:\n"
|
|
57
57
|
output += "```\n"
|
|
58
58
|
output += "/benchmark action=quick\n"
|
|
59
|
-
output += "/benchmark action=run model
|
|
59
|
+
output += "/benchmark action=run model=<model> provider=<provider>\n"
|
|
60
60
|
output += "/benchmark action=list\n"
|
|
61
61
|
output += "```\n"
|
|
62
62
|
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
jinx_name: "compress"
|
|
2
|
+
description: "Manages conversation and knowledge context - compress, flush, sleep, dream"
|
|
3
|
+
interactive: true
|
|
4
|
+
inputs:
|
|
5
|
+
- flush: ""
|
|
6
|
+
- sleep: False
|
|
7
|
+
- dream: False
|
|
8
|
+
- ops: ""
|
|
9
|
+
- model: ""
|
|
10
|
+
- provider: ""
|
|
11
|
+
steps:
|
|
12
|
+
- name: "manage_context_and_memory"
|
|
13
|
+
engine: "python"
|
|
14
|
+
code: |
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
import traceback
|
|
18
|
+
from npcpy.llm_funcs import breathe
|
|
19
|
+
from npcpy.memory.command_history import CommandHistory, load_kg_from_db, save_kg_to_db
|
|
20
|
+
from npcpy.memory.knowledge_graph import kg_sleep_process, kg_dream_process
|
|
21
|
+
|
|
22
|
+
# --- Get all inputs from context ---
|
|
23
|
+
flush_n_str = context.get('flush')
|
|
24
|
+
is_sleeping = context.get('sleep')
|
|
25
|
+
is_dreaming = context.get('dream')
|
|
26
|
+
operations_str = context.get('ops')
|
|
27
|
+
llm_model = context.get('model')
|
|
28
|
+
llm_provider = context.get('provider')
|
|
29
|
+
output_messages = context.get('messages', [])
|
|
30
|
+
|
|
31
|
+
# --- Detect if called with explicit flags ---
|
|
32
|
+
is_flushing = flush_n_str is not None and str(flush_n_str).strip() != ''
|
|
33
|
+
has_explicit_args = is_flushing or is_sleeping or is_dreaming
|
|
34
|
+
|
|
35
|
+
# ========== Execution Functions ==========
|
|
36
|
+
def do_compress():
|
|
37
|
+
"""Compact conversation context via breathe()"""
|
|
38
|
+
try:
|
|
39
|
+
result = breathe(**context)
|
|
40
|
+
if isinstance(result, dict):
|
|
41
|
+
return result.get('output', 'Context compressed.')
|
|
42
|
+
return "Context compression process initiated."
|
|
43
|
+
except Exception as e:
|
|
44
|
+
traceback.print_exc()
|
|
45
|
+
return "Error during context compression: " + str(e)
|
|
46
|
+
|
|
47
|
+
def do_flush(n):
|
|
48
|
+
"""Remove last N messages from context"""
|
|
49
|
+
messages_list = list(output_messages)
|
|
50
|
+
original_len = len(messages_list)
|
|
51
|
+
if messages_list and messages_list[0].get("role") == "system":
|
|
52
|
+
system_message = messages_list.pop(0)
|
|
53
|
+
num_to_remove = min(n, len(messages_list))
|
|
54
|
+
final_messages = [system_message] + messages_list[:-num_to_remove] if num_to_remove < len(messages_list) else [system_message]
|
|
55
|
+
else:
|
|
56
|
+
num_to_remove = min(n, original_len)
|
|
57
|
+
final_messages = messages_list[:-num_to_remove] if num_to_remove < original_len else []
|
|
58
|
+
removed_count = original_len - len(final_messages)
|
|
59
|
+
context['messages'] = final_messages
|
|
60
|
+
return "Flushed " + str(removed_count) + " message(s). Context is now " + str(len(final_messages)) + " messages."
|
|
61
|
+
|
|
62
|
+
def do_sleep(model, provider, ops_str, dream=False):
|
|
63
|
+
"""Evolve knowledge graph via sleep/dream"""
|
|
64
|
+
current_npc = context.get('npc')
|
|
65
|
+
current_team = context.get('team')
|
|
66
|
+
operations_config = [op.strip() for op in ops_str.split(',')] if ops_str else None
|
|
67
|
+
if not model and current_npc: model = current_npc.model
|
|
68
|
+
if not provider and current_npc: provider = current_npc.provider
|
|
69
|
+
if not model: model = state.chat_model if state else "llama3.2"
|
|
70
|
+
if not provider: provider = state.chat_provider if state else "ollama"
|
|
71
|
+
team_name = current_team.name if current_team else "__none__"
|
|
72
|
+
npc_name = current_npc.name if current_npc else "__none__"
|
|
73
|
+
current_path = os.getcwd()
|
|
74
|
+
scope_str = "Team: '" + team_name + "', NPC: '" + npc_name + "', Path: '" + current_path + "'"
|
|
75
|
+
command_history = None
|
|
76
|
+
try:
|
|
77
|
+
db_path = os.getenv("NPCSH_DB_PATH", os.path.expanduser("~/npcsh_history.db"))
|
|
78
|
+
command_history = CommandHistory(db_path)
|
|
79
|
+
engine = command_history.engine
|
|
80
|
+
current_kg = load_kg_from_db(engine, team_name, npc_name, current_path)
|
|
81
|
+
if not current_kg or not current_kg.get('facts'):
|
|
82
|
+
return "Knowledge graph for the current scope is empty. Nothing to process.\n- Scope: " + scope_str
|
|
83
|
+
original_facts = len(current_kg.get('facts', []))
|
|
84
|
+
original_concepts = len(current_kg.get('concepts', []))
|
|
85
|
+
evolved_kg, _ = kg_sleep_process(existing_kg=current_kg, model=model, provider=provider, npc=current_npc, operations_config=operations_config)
|
|
86
|
+
process_type = "Sleep"
|
|
87
|
+
if dream:
|
|
88
|
+
evolved_kg, _ = kg_dream_process(existing_kg=evolved_kg, model=model, provider=provider, npc=current_npc)
|
|
89
|
+
process_type += " & Dream"
|
|
90
|
+
save_kg_to_db(engine, evolved_kg, team_name, npc_name, current_path)
|
|
91
|
+
new_facts = len(evolved_kg.get('facts', []))
|
|
92
|
+
new_concepts = len(evolved_kg.get('concepts', []))
|
|
93
|
+
return (process_type + " process complete.\n"
|
|
94
|
+
"- Facts: " + str(original_facts) + " -> " + str(new_facts) + " (" + str(new_facts - original_facts) + ")\n"
|
|
95
|
+
"- Concepts: " + str(original_concepts) + " -> " + str(new_concepts) + " (" + str(new_concepts - original_concepts) + ")")
|
|
96
|
+
except Exception as e:
|
|
97
|
+
traceback.print_exc()
|
|
98
|
+
return "Error during KG evolution: " + str(e)
|
|
99
|
+
finally:
|
|
100
|
+
if command_history: command_history.close()
|
|
101
|
+
|
|
102
|
+
# ========== Direct execution (flags provided) ==========
|
|
103
|
+
if has_explicit_args:
|
|
104
|
+
if is_sleeping and is_flushing:
|
|
105
|
+
context['output'] = "Error: --sleep and --flush are mutually exclusive."
|
|
106
|
+
context['messages'] = output_messages
|
|
107
|
+
elif is_sleeping:
|
|
108
|
+
context['output'] = do_sleep(llm_model, llm_provider, operations_str, dream=bool(is_dreaming))
|
|
109
|
+
context['messages'] = output_messages
|
|
110
|
+
elif is_flushing:
|
|
111
|
+
try:
|
|
112
|
+
n = int(flush_n_str)
|
|
113
|
+
if n <= 0:
|
|
114
|
+
context['output'] = "Error: Number of messages to flush must be positive."
|
|
115
|
+
else:
|
|
116
|
+
context['output'] = do_flush(n)
|
|
117
|
+
except ValueError:
|
|
118
|
+
context['output'] = "Error: Invalid number '" + str(flush_n_str) + "'."
|
|
119
|
+
|
|
120
|
+
# ========== Interactive TUI (no flags) ==========
|
|
121
|
+
elif sys.stdin.isatty():
|
|
122
|
+
import tty
|
|
123
|
+
import termios
|
|
124
|
+
import select as _sel
|
|
125
|
+
|
|
126
|
+
class CompressState:
|
|
127
|
+
def __init__(self):
|
|
128
|
+
self.actions = [
|
|
129
|
+
{'name': 'Compress', 'desc': 'Compact conversation context (breathe)', 'key': 'compress'},
|
|
130
|
+
{'name': 'Flush', 'desc': 'Remove last N messages from context', 'key': 'flush'},
|
|
131
|
+
{'name': 'Sleep', 'desc': 'Evolve knowledge graph', 'key': 'sleep'},
|
|
132
|
+
{'name': 'Sleep + Dream', 'desc': 'Evolve KG with creative synthesis', 'key': 'dream'},
|
|
133
|
+
]
|
|
134
|
+
self.sel = 0
|
|
135
|
+
self.mode = 'menu' # menu, params, editing, running
|
|
136
|
+
# Params for each action
|
|
137
|
+
self.flush_n = "5"
|
|
138
|
+
self.sleep_model = ""
|
|
139
|
+
self.sleep_provider = ""
|
|
140
|
+
self.sleep_ops = ""
|
|
141
|
+
self.status = "Select an action"
|
|
142
|
+
self.msg_count = len(output_messages)
|
|
143
|
+
# Param editing
|
|
144
|
+
self.param_sel = 0
|
|
145
|
+
self.edit_buf = ""
|
|
146
|
+
self.edit_cursor = 0
|
|
147
|
+
|
|
148
|
+
def get_params(self):
|
|
149
|
+
"""Return list of (label, value) for current action"""
|
|
150
|
+
key = self.actions[self.sel]['key']
|
|
151
|
+
if key == 'compress':
|
|
152
|
+
return [('Messages in context', str(self.msg_count), False)]
|
|
153
|
+
elif key == 'flush':
|
|
154
|
+
return [
|
|
155
|
+
('Messages to flush', self.flush_n, True),
|
|
156
|
+
('Messages in context', str(self.msg_count), False),
|
|
157
|
+
]
|
|
158
|
+
elif key == 'sleep':
|
|
159
|
+
return [
|
|
160
|
+
('Model', self.sleep_model or '(default)', True),
|
|
161
|
+
('Provider', self.sleep_provider or '(default)', True),
|
|
162
|
+
('Operations', self.sleep_ops or '(all)', True),
|
|
163
|
+
]
|
|
164
|
+
elif key == 'dream':
|
|
165
|
+
return [
|
|
166
|
+
('Model', self.sleep_model or '(default)', True),
|
|
167
|
+
('Provider', self.sleep_provider or '(default)', True),
|
|
168
|
+
('Operations', self.sleep_ops or '(all)', True),
|
|
169
|
+
]
|
|
170
|
+
return []
|
|
171
|
+
|
|
172
|
+
def set_param(self, idx, val):
|
|
173
|
+
key = self.actions[self.sel]['key']
|
|
174
|
+
if key == 'flush':
|
|
175
|
+
if idx == 0: self.flush_n = val
|
|
176
|
+
elif key in ('sleep', 'dream'):
|
|
177
|
+
if idx == 0: self.sleep_model = val
|
|
178
|
+
elif idx == 1: self.sleep_provider = val
|
|
179
|
+
elif idx == 2: self.sleep_ops = val
|
|
180
|
+
|
|
181
|
+
st = CompressState()
|
|
182
|
+
|
|
183
|
+
def get_size():
|
|
184
|
+
try:
|
|
185
|
+
s = os.get_terminal_size()
|
|
186
|
+
return s.columns, s.lines
|
|
187
|
+
except:
|
|
188
|
+
return 80, 24
|
|
189
|
+
|
|
190
|
+
def render():
|
|
191
|
+
width, height = get_size()
|
|
192
|
+
out = []
|
|
193
|
+
out.append("\033[H")
|
|
194
|
+
|
|
195
|
+
# Header
|
|
196
|
+
header = " COMPRESS - Context & Memory Manager "
|
|
197
|
+
out.append("\033[1;1H\033[7;1m" + header.ljust(width) + "\033[0m")
|
|
198
|
+
|
|
199
|
+
if st.mode == 'menu':
|
|
200
|
+
out.append("\033[3;1H\033[36;1m Actions \033[90m" + ("-" * (width - 11)) + "\033[0m")
|
|
201
|
+
for i, act in enumerate(st.actions):
|
|
202
|
+
row = 4 + i
|
|
203
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
204
|
+
line = " " + act['name'].ljust(18) + "\033[90m" + act['desc'][:width-24] + "\033[0m"
|
|
205
|
+
if i == st.sel:
|
|
206
|
+
out.append("\033[7m>" + line + "\033[0m")
|
|
207
|
+
else:
|
|
208
|
+
out.append(" " + line)
|
|
209
|
+
|
|
210
|
+
# Show params preview below
|
|
211
|
+
params = st.get_params()
|
|
212
|
+
param_start = 4 + len(st.actions) + 1
|
|
213
|
+
out.append("\033[" + str(param_start) + ";1H\033[33;1m Parameters \033[90m" + ("-" * (width - 14)) + "\033[0m")
|
|
214
|
+
for j, (label, val, editable) in enumerate(params):
|
|
215
|
+
row = param_start + 1 + j
|
|
216
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
217
|
+
marker = "[e]" if editable else " "
|
|
218
|
+
out.append(" " + label.ljust(22) + val[:width-30] + " \033[90m" + marker + "\033[0m")
|
|
219
|
+
|
|
220
|
+
# Clear remaining lines
|
|
221
|
+
clear_start = param_start + 1 + len(params)
|
|
222
|
+
for r in range(clear_start, height - 2):
|
|
223
|
+
out.append("\033[" + str(r) + ";1H\033[K")
|
|
224
|
+
|
|
225
|
+
elif st.mode == 'params':
|
|
226
|
+
params = st.get_params()
|
|
227
|
+
act = st.actions[st.sel]
|
|
228
|
+
out.append("\033[3;1H\033[36;1m " + act['name'] + " Parameters \033[90m" + ("-" * (width - len(act['name']) - 16)) + "\033[0m")
|
|
229
|
+
for j, (label, val, editable) in enumerate(params):
|
|
230
|
+
row = 4 + j
|
|
231
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
232
|
+
if st.mode == 'editing' and j == st.param_sel:
|
|
233
|
+
line = " " + label.ljust(22) + "\033[7m " + st.edit_buf + " \033[0m"
|
|
234
|
+
else:
|
|
235
|
+
marker = " [e]" if editable else ""
|
|
236
|
+
line = " " + label.ljust(22) + val[:width-30] + "\033[90m" + marker + "\033[0m"
|
|
237
|
+
if j == st.param_sel:
|
|
238
|
+
out.append("\033[7m>" + line + "\033[0m")
|
|
239
|
+
else:
|
|
240
|
+
out.append(" " + line)
|
|
241
|
+
|
|
242
|
+
clear_start = 4 + len(params)
|
|
243
|
+
for r in range(clear_start, height - 2):
|
|
244
|
+
out.append("\033[" + str(r) + ";1H\033[K")
|
|
245
|
+
|
|
246
|
+
elif st.mode == 'editing':
|
|
247
|
+
# Same as params but with edit field
|
|
248
|
+
params = st.get_params()
|
|
249
|
+
act = st.actions[st.sel]
|
|
250
|
+
out.append("\033[3;1H\033[36;1m " + act['name'] + " Parameters \033[90m" + ("-" * (width - len(act['name']) - 16)) + "\033[0m")
|
|
251
|
+
for j, (label, val, editable) in enumerate(params):
|
|
252
|
+
row = 4 + j
|
|
253
|
+
out.append("\033[" + str(row) + ";1H\033[K")
|
|
254
|
+
if j == st.param_sel:
|
|
255
|
+
line = " " + label.ljust(22) + "\033[7m " + st.edit_buf + " \033[0m"
|
|
256
|
+
out.append(">" + line)
|
|
257
|
+
else:
|
|
258
|
+
marker = " [e]" if editable else ""
|
|
259
|
+
line = " " + label.ljust(22) + val[:width-30] + "\033[90m" + marker + "\033[0m"
|
|
260
|
+
out.append(" " + line)
|
|
261
|
+
|
|
262
|
+
clear_start = 4 + len(params)
|
|
263
|
+
for r in range(clear_start, height - 2):
|
|
264
|
+
out.append("\033[" + str(r) + ";1H\033[K")
|
|
265
|
+
|
|
266
|
+
elif st.mode == 'running':
|
|
267
|
+
out.append("\033[3;1H\033[K")
|
|
268
|
+
out.append("\033[4;1H\033[K Running " + st.actions[st.sel]['name'] + "...")
|
|
269
|
+
for r in range(5, height - 2):
|
|
270
|
+
out.append("\033[" + str(r) + ";1H\033[K")
|
|
271
|
+
|
|
272
|
+
# Status + footer
|
|
273
|
+
out.append("\033[" + str(height-2) + ";1H\033[K\033[90m" + ("-" * width) + "\033[0m")
|
|
274
|
+
out.append("\033[" + str(height-1) + ";1H\033[K " + st.status[:width-2])
|
|
275
|
+
|
|
276
|
+
if st.mode == 'menu':
|
|
277
|
+
footer = " j/k:Nav Enter:Configure G:Run Now q:Quit "
|
|
278
|
+
elif st.mode == 'params':
|
|
279
|
+
footer = " j/k:Nav e:Edit Enter:Execute b:Back q:Quit "
|
|
280
|
+
elif st.mode == 'editing':
|
|
281
|
+
footer = " Type value Enter:Confirm Esc:Cancel "
|
|
282
|
+
else:
|
|
283
|
+
footer = " Running... "
|
|
284
|
+
out.append("\033[" + str(height) + ";1H\033[K\033[7m" + footer.ljust(width) + "\033[0m")
|
|
285
|
+
|
|
286
|
+
sys.stdout.write(''.join(out))
|
|
287
|
+
sys.stdout.flush()
|
|
288
|
+
|
|
289
|
+
def execute_action():
|
|
290
|
+
"""Run the selected action and return result text"""
|
|
291
|
+
key = st.actions[st.sel]['key']
|
|
292
|
+
st.mode = 'running'
|
|
293
|
+
render()
|
|
294
|
+
|
|
295
|
+
if key == 'compress':
|
|
296
|
+
return do_compress()
|
|
297
|
+
elif key == 'flush':
|
|
298
|
+
try:
|
|
299
|
+
n = int(st.flush_n)
|
|
300
|
+
if n <= 0:
|
|
301
|
+
return "Error: Number must be positive."
|
|
302
|
+
return do_flush(n)
|
|
303
|
+
except ValueError:
|
|
304
|
+
return "Error: Invalid number '" + st.flush_n + "'."
|
|
305
|
+
elif key == 'sleep':
|
|
306
|
+
return do_sleep(st.sleep_model or None, st.sleep_provider or None, st.sleep_ops or None, dream=False)
|
|
307
|
+
elif key == 'dream':
|
|
308
|
+
return do_sleep(st.sleep_model or None, st.sleep_provider or None, st.sleep_ops or None, dream=True)
|
|
309
|
+
return "Unknown action."
|
|
310
|
+
|
|
311
|
+
fd = sys.stdin.fileno()
|
|
312
|
+
old_settings = termios.tcgetattr(fd)
|
|
313
|
+
result_text = None
|
|
314
|
+
|
|
315
|
+
try:
|
|
316
|
+
tty.setcbreak(fd)
|
|
317
|
+
sys.stdout.write('\033[?25l')
|
|
318
|
+
sys.stdout.write('\033[2J')
|
|
319
|
+
render()
|
|
320
|
+
|
|
321
|
+
running = True
|
|
322
|
+
while running:
|
|
323
|
+
c = os.read(fd, 1).decode('latin-1')
|
|
324
|
+
|
|
325
|
+
if st.mode == 'editing':
|
|
326
|
+
if c == '\x1b':
|
|
327
|
+
if _sel.select([fd], [], [], 0.05)[0]:
|
|
328
|
+
os.read(fd, 2)
|
|
329
|
+
st.mode = 'params'
|
|
330
|
+
elif c in ('\r', '\n'):
|
|
331
|
+
st.set_param(st.param_sel, st.edit_buf)
|
|
332
|
+
st.mode = 'params'
|
|
333
|
+
st.status = "Parameter updated."
|
|
334
|
+
elif c == '\x7f' or c == '\x08':
|
|
335
|
+
if st.edit_cursor > 0:
|
|
336
|
+
st.edit_buf = st.edit_buf[:st.edit_cursor-1] + st.edit_buf[st.edit_cursor:]
|
|
337
|
+
st.edit_cursor -= 1
|
|
338
|
+
elif c >= ' ' and c <= '~':
|
|
339
|
+
st.edit_buf = st.edit_buf[:st.edit_cursor] + c + st.edit_buf[st.edit_cursor:]
|
|
340
|
+
st.edit_cursor += 1
|
|
341
|
+
render()
|
|
342
|
+
continue
|
|
343
|
+
|
|
344
|
+
if c == '\x1b':
|
|
345
|
+
if _sel.select([fd], [], [], 0.05)[0]:
|
|
346
|
+
c2 = os.read(fd, 1).decode('latin-1')
|
|
347
|
+
if c2 == '[':
|
|
348
|
+
c3 = os.read(fd, 1).decode('latin-1')
|
|
349
|
+
if c3 == 'A': # Up
|
|
350
|
+
if st.mode == 'menu':
|
|
351
|
+
st.sel = max(0, st.sel - 1)
|
|
352
|
+
elif st.mode == 'params':
|
|
353
|
+
st.param_sel = max(0, st.param_sel - 1)
|
|
354
|
+
elif c3 == 'B': # Down
|
|
355
|
+
if st.mode == 'menu':
|
|
356
|
+
st.sel = min(len(st.actions) - 1, st.sel + 1)
|
|
357
|
+
elif st.mode == 'params':
|
|
358
|
+
params = st.get_params()
|
|
359
|
+
st.param_sel = min(len(params) - 1, st.param_sel + 1)
|
|
360
|
+
else:
|
|
361
|
+
if st.mode == 'params':
|
|
362
|
+
st.mode = 'menu'
|
|
363
|
+
st.status = "Select an action"
|
|
364
|
+
else:
|
|
365
|
+
result_text = "Cancelled."
|
|
366
|
+
running = False
|
|
367
|
+
render()
|
|
368
|
+
continue
|
|
369
|
+
|
|
370
|
+
if c == 'q' or c == '\x03':
|
|
371
|
+
result_text = "Cancelled."
|
|
372
|
+
running = False
|
|
373
|
+
elif st.mode == 'menu':
|
|
374
|
+
if c == 'j':
|
|
375
|
+
st.sel = min(len(st.actions) - 1, st.sel + 1)
|
|
376
|
+
elif c == 'k':
|
|
377
|
+
st.sel = max(0, st.sel - 1)
|
|
378
|
+
elif c in ('\r', '\n'):
|
|
379
|
+
params = st.get_params()
|
|
380
|
+
editable = [p for p in params if p[2]]
|
|
381
|
+
if editable:
|
|
382
|
+
st.mode = 'params'
|
|
383
|
+
st.param_sel = 0
|
|
384
|
+
st.status = "Configure parameters, then Enter to execute"
|
|
385
|
+
else:
|
|
386
|
+
result_text = execute_action()
|
|
387
|
+
running = False
|
|
388
|
+
elif c == 'G':
|
|
389
|
+
result_text = execute_action()
|
|
390
|
+
running = False
|
|
391
|
+
elif st.mode == 'params':
|
|
392
|
+
if c == 'j':
|
|
393
|
+
params = st.get_params()
|
|
394
|
+
st.param_sel = min(len(params) - 1, st.param_sel + 1)
|
|
395
|
+
elif c == 'k':
|
|
396
|
+
st.param_sel = max(0, st.param_sel - 1)
|
|
397
|
+
elif c == 'e':
|
|
398
|
+
params = st.get_params()
|
|
399
|
+
if st.param_sel < len(params) and params[st.param_sel][2]:
|
|
400
|
+
st.mode = 'editing'
|
|
401
|
+
val = params[st.param_sel][1]
|
|
402
|
+
st.edit_buf = "" if val.startswith('(') else val
|
|
403
|
+
st.edit_cursor = len(st.edit_buf)
|
|
404
|
+
elif c == 'b':
|
|
405
|
+
st.mode = 'menu'
|
|
406
|
+
st.status = "Select an action"
|
|
407
|
+
elif c in ('\r', '\n'):
|
|
408
|
+
result_text = execute_action()
|
|
409
|
+
running = False
|
|
410
|
+
|
|
411
|
+
render()
|
|
412
|
+
|
|
413
|
+
finally:
|
|
414
|
+
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
|
|
415
|
+
sys.stdout.write('\033[?25h')
|
|
416
|
+
sys.stdout.write('\033[2J\033[H')
|
|
417
|
+
sys.stdout.flush()
|
|
418
|
+
|
|
419
|
+
context['output'] = result_text or "Cancelled."
|
|
420
|
+
if 'messages' not in context:
|
|
421
|
+
context['messages'] = output_messages
|
|
422
|
+
|
|
423
|
+
# ========== Non-interactive fallback ==========
|
|
424
|
+
else:
|
|
425
|
+
result = do_compress()
|
|
426
|
+
context['output'] = result
|
|
427
|
+
if 'messages' not in context:
|
|
428
|
+
context['messages'] = output_messages
|