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.
Files changed (166) hide show
  1. npcsh/_state.py +5 -71
  2. npcsh/diff_viewer.py +3 -3
  3. npcsh/npc_team/jinxs/lib/core/compress.jinx +373 -85
  4. npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +17 -6
  5. npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +17 -6
  6. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +19 -8
  7. npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +52 -14
  8. npcsh/npc_team/jinxs/{bin → lib/utils}/benchmark.jinx +2 -2
  9. npcsh/npc_team/jinxs/{bin → lib/utils}/jinxs.jinx +12 -12
  10. npcsh/npc_team/jinxs/{bin → lib/utils}/models.jinx +7 -7
  11. npcsh/npc_team/jinxs/{bin → lib/utils}/setup.jinx +6 -6
  12. npcsh/npc_team/jinxs/modes/alicanto.jinx +1573 -296
  13. npcsh/npc_team/jinxs/modes/arxiv.jinx +5 -5
  14. npcsh/npc_team/jinxs/modes/config_tui.jinx +300 -0
  15. npcsh/npc_team/jinxs/modes/corca.jinx +3 -3
  16. npcsh/npc_team/jinxs/modes/git.jinx +795 -0
  17. {npcsh-1.1.20.data/data/npcsh/npc_team → npcsh/npc_team/jinxs/modes}/kg.jinx +13 -13
  18. npcsh/npc_team/jinxs/modes/memories.jinx +414 -0
  19. npcsh/npc_team/jinxs/{bin → modes}/nql.jinx +10 -21
  20. npcsh/npc_team/jinxs/modes/papers.jinx +578 -0
  21. npcsh/npc_team/jinxs/modes/plonk.jinx +490 -304
  22. npcsh/npc_team/jinxs/modes/reattach.jinx +3 -3
  23. npcsh/npc_team/jinxs/modes/spool.jinx +3 -3
  24. npcsh/npc_team/jinxs/{bin → modes}/team.jinx +12 -12
  25. npcsh/npc_team/jinxs/modes/vixynt.jinx +388 -0
  26. npcsh/npc_team/jinxs/modes/wander.jinx +454 -181
  27. npcsh/npc_team/jinxs/modes/yap.jinx +10 -3
  28. npcsh/npcsh.py +112 -47
  29. npcsh/routes.py +4 -1
  30. npcsh/salmon_simulation.py +0 -0
  31. npcsh-1.1.21.data/data/npcsh/npc_team/alicanto.jinx +1633 -0
  32. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/arxiv.jinx +5 -5
  33. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/benchmark.jinx +2 -2
  34. npcsh-1.1.21.data/data/npcsh/npc_team/compress.jinx +428 -0
  35. npcsh-1.1.21.data/data/npcsh/npc_team/config_tui.jinx +300 -0
  36. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.jinx +3 -3
  37. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/db_search.jinx +17 -6
  38. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/file_search.jinx +17 -6
  39. npcsh-1.1.21.data/data/npcsh/npc_team/git.jinx +795 -0
  40. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/jinxs.jinx +12 -12
  41. {npcsh/npc_team/jinxs/bin → npcsh-1.1.21.data/data/npcsh/npc_team}/kg.jinx +13 -13
  42. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kg_search.jinx +19 -8
  43. npcsh-1.1.21.data/data/npcsh/npc_team/memories.jinx +414 -0
  44. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/models.jinx +7 -7
  45. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/nql.jinx +10 -21
  46. npcsh-1.1.21.data/data/npcsh/npc_team/papers.jinx +578 -0
  47. npcsh-1.1.21.data/data/npcsh/npc_team/plonk.jinx +565 -0
  48. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/reattach.jinx +3 -3
  49. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/setup.jinx +6 -6
  50. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.jinx +3 -3
  51. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/team.jinx +12 -12
  52. npcsh-1.1.21.data/data/npcsh/npc_team/vixynt.jinx +388 -0
  53. npcsh-1.1.21.data/data/npcsh/npc_team/wander.jinx +728 -0
  54. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/web_search.jinx +52 -14
  55. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.jinx +10 -3
  56. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/METADATA +2 -2
  57. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/RECORD +145 -150
  58. npcsh-1.1.21.dist-info/entry_points.txt +11 -0
  59. npcsh/npc_team/jinxs/bin/config_tui.jinx +0 -300
  60. npcsh/npc_team/jinxs/bin/memories.jinx +0 -317
  61. npcsh/npc_team/jinxs/bin/vixynt.jinx +0 -122
  62. npcsh/npc_team/jinxs/lib/core/search/mem_review.jinx +0 -73
  63. npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +0 -388
  64. npcsh/npc_team/jinxs/lib/research/paper_search.jinx +0 -412
  65. npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +0 -386
  66. npcsh/npc_team/plonkjr.npc +0 -23
  67. npcsh-1.1.20.data/data/npcsh/npc_team/alicanto.jinx +0 -356
  68. npcsh-1.1.20.data/data/npcsh/npc_team/compress.jinx +0 -140
  69. npcsh-1.1.20.data/data/npcsh/npc_team/config_tui.jinx +0 -300
  70. npcsh-1.1.20.data/data/npcsh/npc_team/mem_review.jinx +0 -73
  71. npcsh-1.1.20.data/data/npcsh/npc_team/mem_search.jinx +0 -388
  72. npcsh-1.1.20.data/data/npcsh/npc_team/memories.jinx +0 -317
  73. npcsh-1.1.20.data/data/npcsh/npc_team/paper_search.jinx +0 -412
  74. npcsh-1.1.20.data/data/npcsh/npc_team/plonk.jinx +0 -379
  75. npcsh-1.1.20.data/data/npcsh/npc_team/plonkjr.npc +0 -23
  76. npcsh-1.1.20.data/data/npcsh/npc_team/semantic_scholar.jinx +0 -386
  77. npcsh-1.1.20.data/data/npcsh/npc_team/vixynt.jinx +0 -122
  78. npcsh-1.1.20.data/data/npcsh/npc_team/wander.jinx +0 -455
  79. npcsh-1.1.20.dist-info/entry_points.txt +0 -25
  80. /npcsh/npc_team/jinxs/lib/{orchestration → core}/convene.jinx +0 -0
  81. /npcsh/npc_team/jinxs/lib/{orchestration → core}/delegate.jinx +0 -0
  82. /npcsh/npc_team/jinxs/{bin → lib/core}/sample.jinx +0 -0
  83. /npcsh/npc_team/jinxs/{bin → lib/utils}/sync.jinx +0 -0
  84. /npcsh/npc_team/jinxs/{bin → modes}/roll.jinx +0 -0
  85. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
  86. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.npc +0 -0
  87. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/alicanto.png +0 -0
  88. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
  89. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
  90. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/build.jinx +0 -0
  91. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/chat.jinx +0 -0
  92. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/click.jinx +0 -0
  93. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  94. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
  95. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
  96. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/cmd.jinx +0 -0
  97. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/compile.jinx +0 -0
  98. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/confirm.jinx +0 -0
  99. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/convene.jinx +0 -0
  100. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.npc +0 -0
  101. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca.png +0 -0
  102. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/corca_example.png +0 -0
  103. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/delegate.jinx +0 -0
  104. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/edit_file.jinx +0 -0
  105. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
  106. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic.npc +0 -0
  107. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/frederic4.png +0 -0
  108. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.jinx +0 -0
  109. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.npc +0 -0
  110. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/guac.png +0 -0
  111. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/help.jinx +0 -0
  112. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/incognide.jinx +0 -0
  113. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/init.jinx +0 -0
  114. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
  115. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  116. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/key_press.jinx +0 -0
  117. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
  118. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
  119. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  120. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/navigate.jinx +0 -0
  121. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/notify.jinx +0 -0
  122. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
  123. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  124. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
  125. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
  126. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/ots.jinx +0 -0
  127. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/paste.jinx +0 -0
  128. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.npc +0 -0
  129. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonk.png +0 -0
  130. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  131. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/pti.jinx +0 -0
  132. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/python.jinx +0 -0
  133. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
  134. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/roll.jinx +0 -0
  135. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
  136. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sample.jinx +0 -0
  137. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
  138. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/search.jinx +0 -0
  139. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/send_message.jinx +0 -0
  140. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/serve.jinx +0 -0
  141. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/set.jinx +0 -0
  142. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sh.jinx +0 -0
  143. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/shh.jinx +0 -0
  144. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.npc +0 -0
  145. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sibiji.png +0 -0
  146. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sleep.jinx +0 -0
  147. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
  148. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/spool.png +0 -0
  149. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sql.jinx +0 -0
  150. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch.jinx +0 -0
  151. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
  152. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
  153. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/switches.jinx +0 -0
  154. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/sync.jinx +0 -0
  155. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
  156. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/trigger.jinx +0 -0
  157. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/type_text.jinx +0 -0
  158. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/usage.jinx +0 -0
  159. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  160. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/wait.jinx +0 -0
  161. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/write_file.jinx +0 -0
  162. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/yap.png +0 -0
  163. {npcsh-1.1.20.data → npcsh-1.1.21.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
  164. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/WHEEL +0 -0
  165. {npcsh-1.1.20.dist-info → npcsh-1.1.21.dist-info}/licenses/LICENSE +0 -0
  166. {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[45;37;1m' + header.ljust(width) + '\033[0m\n')
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[45;37m 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')
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[45;37m j/k:Scroll b:Back o:Browser i:Incognide p:PDF d:Download v:TermView q:Quit \033[0m')
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[46;37;1m' + header.ljust(width) + '\033[0m\n')
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[46;37m j/k/PgDn/PgUp:Scroll b:Back d:Download q:Quit [' + str(pct) + '%] \033[0m')
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 "anthropic"
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=gpt-4o provider=openai\n"
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