npcsh 1.1.15__py3-none-any.whl → 1.1.17__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 (176) hide show
  1. npcsh/_state.py +69 -12
  2. npcsh/benchmark/__init__.py +22 -0
  3. npcsh/benchmark/npcsh_agent.py +262 -0
  4. npcsh/benchmark/runner.py +569 -0
  5. npcsh/npc_team/jinxs/bin/benchmark.jinx +146 -0
  6. npcsh/npc_team/jinxs/bin/nql.jinx +7 -7
  7. npcsh/npc_team/jinxs/bin/roll.jinx +20 -23
  8. npcsh/npc_team/jinxs/bin/sample.jinx +6 -7
  9. npcsh/npc_team/jinxs/bin/spool.jinx +4 -4
  10. npcsh/npc_team/jinxs/bin/sync.jinx +6 -6
  11. npcsh/npc_team/jinxs/bin/vixynt.jinx +8 -8
  12. npcsh/npc_team/jinxs/bin/wander.jinx +109 -19
  13. npcsh/npc_team/jinxs/bin/yap.jinx +5 -5
  14. npcsh/npc_team/jinxs/incognide/add_tab.jinx +11 -0
  15. npcsh/npc_team/jinxs/incognide/close_pane.jinx +9 -0
  16. npcsh/npc_team/jinxs/incognide/close_tab.jinx +10 -0
  17. npcsh/npc_team/jinxs/incognide/confirm.jinx +10 -0
  18. npcsh/npc_team/jinxs/incognide/focus_pane.jinx +9 -0
  19. npcsh/npc_team/jinxs/{npc_studio/npc-studio.jinx → incognide/incognide.jinx} +2 -2
  20. npcsh/npc_team/jinxs/incognide/list_panes.jinx +8 -0
  21. npcsh/npc_team/jinxs/incognide/navigate.jinx +10 -0
  22. npcsh/npc_team/jinxs/incognide/notify.jinx +10 -0
  23. npcsh/npc_team/jinxs/incognide/open_pane.jinx +13 -0
  24. npcsh/npc_team/jinxs/incognide/read_pane.jinx +9 -0
  25. npcsh/npc_team/jinxs/incognide/run_terminal.jinx +10 -0
  26. npcsh/npc_team/jinxs/incognide/send_message.jinx +10 -0
  27. npcsh/npc_team/jinxs/incognide/split_pane.jinx +12 -0
  28. npcsh/npc_team/jinxs/incognide/switch_npc.jinx +10 -0
  29. npcsh/npc_team/jinxs/incognide/switch_tab.jinx +10 -0
  30. npcsh/npc_team/jinxs/incognide/write_file.jinx +11 -0
  31. npcsh/npc_team/jinxs/incognide/zen_mode.jinx +9 -0
  32. npcsh/npc_team/jinxs/lib/browser/browser_action.jinx +4 -4
  33. npcsh/npc_team/jinxs/lib/browser/browser_screenshot.jinx +1 -1
  34. npcsh/npc_team/jinxs/lib/browser/open_browser.jinx +2 -2
  35. npcsh/npc_team/jinxs/lib/computer_use/click.jinx +2 -2
  36. npcsh/npc_team/jinxs/lib/computer_use/key_press.jinx +1 -1
  37. npcsh/npc_team/jinxs/lib/computer_use/launch_app.jinx +1 -1
  38. npcsh/npc_team/jinxs/lib/computer_use/screenshot.jinx +1 -1
  39. npcsh/npc_team/jinxs/lib/computer_use/trigger.jinx +2 -2
  40. npcsh/npc_team/jinxs/lib/computer_use/type_text.jinx +1 -1
  41. npcsh/npc_team/jinxs/lib/computer_use/wait.jinx +1 -1
  42. npcsh/npc_team/jinxs/lib/core/chat.jinx +4 -4
  43. npcsh/npc_team/jinxs/lib/core/cmd.jinx +4 -4
  44. npcsh/npc_team/jinxs/lib/core/compress.jinx +8 -8
  45. npcsh/npc_team/jinxs/lib/core/edit_file.jinx +3 -0
  46. npcsh/npc_team/jinxs/lib/core/ots.jinx +7 -7
  47. npcsh/npc_team/jinxs/lib/core/search/db_search.jinx +44 -0
  48. npcsh/npc_team/jinxs/lib/core/search/file_search.jinx +94 -0
  49. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +96 -0
  50. npcsh/npc_team/jinxs/lib/core/search/mem_search.jinx +80 -0
  51. npcsh/npc_team/jinxs/lib/core/search/web_search.jinx +51 -0
  52. npcsh/npc_team/jinxs/lib/core/search.jinx +52 -129
  53. npcsh/npc_team/jinxs/lib/core/sh.jinx +1 -1
  54. npcsh/npc_team/jinxs/lib/core/sleep.jinx +7 -7
  55. npcsh/npc_team/jinxs/lib/core/sql.jinx +7 -7
  56. npcsh/npc_team/jinxs/lib/orchestration/convene.jinx +7 -7
  57. npcsh/npc_team/jinxs/lib/orchestration/delegate.jinx +8 -9
  58. npcsh/npc_team/jinxs/lib/research/arxiv.jinx +2 -2
  59. npcsh/npc_team/jinxs/lib/research/paper_search.jinx +3 -3
  60. npcsh/npc_team/jinxs/lib/research/semantic_scholar.jinx +2 -2
  61. npcsh/npc_team/jinxs/lib/utils/build.jinx +5 -5
  62. npcsh/npc_team/jinxs/lib/utils/compile.jinx +2 -2
  63. npcsh/npc_team/jinxs/lib/utils/help.jinx +1 -1
  64. npcsh/npc_team/jinxs/lib/utils/init.jinx +5 -5
  65. npcsh/npc_team/jinxs/lib/utils/jinxs.jinx +1 -1
  66. npcsh/npc_team/jinxs/lib/utils/serve.jinx +2 -2
  67. npcsh/npc_team/jinxs/lib/utils/set.jinx +2 -2
  68. npcsh/npc_team/jinxs/lib/utils/switch.jinx +3 -3
  69. npcsh/npc_team/jinxs/lib/utils/switches.jinx +1 -1
  70. npcsh/npc_team/jinxs/lib/utils/teamviz.jinx +2 -2
  71. npcsh/npc_team/sibiji.npc +1 -1
  72. npcsh/npcsh.py +81 -43
  73. npcsh-1.1.17.data/data/npcsh/npc_team/add_tab.jinx +11 -0
  74. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/arxiv.jinx +2 -2
  75. npcsh-1.1.17.data/data/npcsh/npc_team/benchmark.jinx +146 -0
  76. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/browser_action.jinx +4 -4
  77. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/browser_screenshot.jinx +1 -1
  78. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/build.jinx +5 -5
  79. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/chat.jinx +4 -4
  80. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/click.jinx +2 -2
  81. npcsh-1.1.17.data/data/npcsh/npc_team/close_pane.jinx +9 -0
  82. npcsh-1.1.17.data/data/npcsh/npc_team/close_tab.jinx +10 -0
  83. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/cmd.jinx +4 -4
  84. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/compile.jinx +2 -2
  85. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/compress.jinx +8 -8
  86. npcsh-1.1.17.data/data/npcsh/npc_team/confirm.jinx +10 -0
  87. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/convene.jinx +7 -7
  88. npcsh-1.1.17.data/data/npcsh/npc_team/db_search.jinx +44 -0
  89. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/delegate.jinx +8 -9
  90. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/edit_file.jinx +3 -0
  91. npcsh-1.1.17.data/data/npcsh/npc_team/file_search.jinx +94 -0
  92. npcsh-1.1.17.data/data/npcsh/npc_team/focus_pane.jinx +9 -0
  93. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/help.jinx +1 -1
  94. npcsh-1.1.15.data/data/npcsh/npc_team/npc-studio.jinx → npcsh-1.1.17.data/data/npcsh/npc_team/incognide.jinx +2 -2
  95. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/init.jinx +5 -5
  96. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/jinxs.jinx +1 -1
  97. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/key_press.jinx +1 -1
  98. npcsh-1.1.17.data/data/npcsh/npc_team/kg_search.jinx +96 -0
  99. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/launch_app.jinx +1 -1
  100. npcsh-1.1.17.data/data/npcsh/npc_team/list_panes.jinx +8 -0
  101. npcsh-1.1.17.data/data/npcsh/npc_team/mem_search.jinx +80 -0
  102. npcsh-1.1.17.data/data/npcsh/npc_team/navigate.jinx +10 -0
  103. npcsh-1.1.17.data/data/npcsh/npc_team/notify.jinx +10 -0
  104. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/nql.jinx +7 -7
  105. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/open_browser.jinx +2 -2
  106. npcsh-1.1.17.data/data/npcsh/npc_team/open_pane.jinx +13 -0
  107. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/ots.jinx +7 -7
  108. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/paper_search.jinx +3 -3
  109. npcsh-1.1.17.data/data/npcsh/npc_team/read_pane.jinx +9 -0
  110. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/roll.jinx +20 -23
  111. npcsh-1.1.17.data/data/npcsh/npc_team/run_terminal.jinx +10 -0
  112. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sample.jinx +6 -7
  113. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/screenshot.jinx +1 -1
  114. npcsh-1.1.17.data/data/npcsh/npc_team/search.jinx +54 -0
  115. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/semantic_scholar.jinx +2 -2
  116. npcsh-1.1.17.data/data/npcsh/npc_team/send_message.jinx +10 -0
  117. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/serve.jinx +2 -2
  118. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/set.jinx +2 -2
  119. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sh.jinx +1 -1
  120. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sibiji.npc +1 -1
  121. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sleep.jinx +7 -7
  122. npcsh-1.1.17.data/data/npcsh/npc_team/split_pane.jinx +12 -0
  123. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/spool.jinx +4 -4
  124. npcsh-1.1.17.data/data/npcsh/npc_team/sql.jinx +16 -0
  125. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/switch.jinx +3 -3
  126. npcsh-1.1.17.data/data/npcsh/npc_team/switch_npc.jinx +10 -0
  127. npcsh-1.1.17.data/data/npcsh/npc_team/switch_tab.jinx +10 -0
  128. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/switches.jinx +1 -1
  129. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sync.jinx +6 -6
  130. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/teamviz.jinx +2 -2
  131. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/trigger.jinx +2 -2
  132. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/type_text.jinx +1 -1
  133. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/vixynt.jinx +8 -8
  134. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/wait.jinx +1 -1
  135. npcsh-1.1.17.data/data/npcsh/npc_team/wander.jinx +242 -0
  136. npcsh-1.1.17.data/data/npcsh/npc_team/web_search.jinx +51 -0
  137. npcsh-1.1.17.data/data/npcsh/npc_team/write_file.jinx +11 -0
  138. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/yap.jinx +5 -5
  139. npcsh-1.1.17.data/data/npcsh/npc_team/zen_mode.jinx +9 -0
  140. {npcsh-1.1.15.dist-info → npcsh-1.1.17.dist-info}/METADATA +10 -7
  141. npcsh-1.1.17.dist-info/RECORD +219 -0
  142. {npcsh-1.1.15.dist-info → npcsh-1.1.17.dist-info}/entry_points.txt +2 -0
  143. npcsh-1.1.15.data/data/npcsh/npc_team/search.jinx +0 -131
  144. npcsh-1.1.15.data/data/npcsh/npc_team/sql.jinx +0 -16
  145. npcsh-1.1.15.data/data/npcsh/npc_team/wander.jinx +0 -152
  146. npcsh-1.1.15.dist-info/RECORD +0 -170
  147. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/alicanto.npc +0 -0
  148. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/alicanto.png +0 -0
  149. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  150. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/corca.npc +0 -0
  151. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/corca.png +0 -0
  152. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/corca_example.png +0 -0
  153. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/frederic.npc +0 -0
  154. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/frederic4.png +0 -0
  155. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/guac.npc +0 -0
  156. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/guac.png +0 -0
  157. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/kadiefa.npc +0 -0
  158. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  159. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  160. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
  161. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  162. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/paste.jinx +0 -0
  163. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonk.npc +0 -0
  164. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonk.png +0 -0
  165. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonkjr.npc +0 -0
  166. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  167. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/python.jinx +0 -0
  168. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/shh.jinx +0 -0
  169. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/sibiji.png +0 -0
  170. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/spool.png +0 -0
  171. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/usage.jinx +0 -0
  172. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  173. {npcsh-1.1.15.data → npcsh-1.1.17.data}/data/npcsh/npc_team/yap.png +0 -0
  174. {npcsh-1.1.15.dist-info → npcsh-1.1.17.dist-info}/WHEEL +0 -0
  175. {npcsh-1.1.15.dist-info → npcsh-1.1.17.dist-info}/licenses/LICENSE +0 -0
  176. {npcsh-1.1.15.dist-info → npcsh-1.1.17.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,54 @@
1
+ jinx_name: search
2
+ description: Unified search - routes to web_search, mem_search, kg_search, file_search, db_search
3
+ inputs:
4
+ - query: ""
5
+ - type: "web"
6
+ - provider: ""
7
+ - num_results: ""
8
+ - status: ""
9
+ - npc_name: ""
10
+ - team_name: ""
11
+ - file_paths: ""
12
+ - emodel: ""
13
+ - eprovider: ""
14
+ - concept: ""
15
+ - db_path: ""
16
+ - limit: ""
17
+
18
+ steps:
19
+ {% if type == "mem" %}
20
+ - name: search
21
+ engine: mem_search
22
+ query: "{{ query }}"
23
+ status: "{{ status }}"
24
+ npc_name: "{{ npc_name }}"
25
+ team_name: "{{ team_name }}"
26
+ db_path: "{{ db_path }}"
27
+ {% elif type == "kg" %}
28
+ - name: search
29
+ engine: kg_search
30
+ query: "{{ query }}"
31
+ concept: "{{ concept }}"
32
+ npc_name: "{{ npc_name }}"
33
+ team_name: "{{ team_name }}"
34
+ db_path: "{{ db_path }}"
35
+ {% elif type == "file" %}
36
+ - name: search
37
+ engine: file_search
38
+ query: "{{ query }}"
39
+ file_paths: "{{ file_paths }}"
40
+ emodel: "{{ emodel }}"
41
+ eprovider: "{{ eprovider }}"
42
+ {% elif type == "db" %}
43
+ - name: search
44
+ engine: db_search
45
+ query: "{{ query }}"
46
+ db_path: "{{ db_path }}"
47
+ limit: "{{ limit }}"
48
+ {% else %}
49
+ - name: search
50
+ engine: web_search
51
+ query: "{{ query }}"
52
+ provider: "{{ provider }}"
53
+ num_results: "{{ num_results }}"
54
+ {% endif %}
@@ -1,8 +1,8 @@
1
1
  jinx_name: semantic_scholar
2
2
  description: Search Semantic Scholar for academic papers. Requires S2_API_KEY env var.
3
3
  inputs:
4
- - query: ""
5
- - limit: 10
4
+ - query: ""
5
+ - limit: 10
6
6
  steps:
7
7
  - name: search_s2
8
8
  engine: python
@@ -0,0 +1,10 @@
1
+ jinx_name: studio.send_message
2
+ description: Send a message in a chat pane.
3
+ inputs:
4
+ - paneId: "active"
5
+ - message: ""
6
+ steps:
7
+ - name: frontend_action
8
+ engine: python
9
+ code: |
10
+ context['output'] = "Action executed by frontend"
@@ -1,8 +1,8 @@
1
1
  jinx_name: "serve"
2
2
  description: "Serve an NPC Team"
3
3
  inputs:
4
- - port: 5337 # The port to run the Flask server on.
5
- - cors: "" # Comma-separated CORS origins.
4
+ - port: 5337
5
+ - cors: ""
6
6
  steps:
7
7
  - name: "start_flask_server"
8
8
  engine: "python"
@@ -1,8 +1,8 @@
1
1
  jinx_name: "set"
2
2
  description: "Set configuration values"
3
3
  inputs:
4
- - key: "" # The configuration key to set.
5
- - value: "" # The value to set for the configuration key.
4
+ - key: ""
5
+ - value: ""
6
6
  steps:
7
7
  - name: "set_config_value"
8
8
  engine: "python"
@@ -1,7 +1,7 @@
1
1
  jinx_name: sh
2
2
  description: Execute bash queries. Should be used to grep for file contents, list directories, explore information to answer user questions more practically. NEVER use ls -R on directories that may contain node_modules, .git, or other large dependency folders - this will exceed token limits. Use targeted ls commands instead.
3
3
  inputs:
4
- - bash_command
4
+ - bash_command
5
5
  steps:
6
6
  - name: execute_bash
7
7
  engine: python
@@ -14,7 +14,7 @@ primary_directive: |
14
14
  You are sibiji, the orchestrator and general manager of the NPC team.
15
15
  Your role is to delegate tasks to appropriate specialist agents based on their expertise.
16
16
 
17
- When delegating, match the task to the agent whose primary_directive best fits.
17
+ When delegating, match the task to the agent whose primary_directive best fits. Basic search inquiries can be handled by yourself. Do not delegate unnecessarily.
18
18
  You have access to the delegate tool to pass tasks to other agents.
19
19
  jinxs:
20
20
  - lib/orchestration/delegate
@@ -1,10 +1,10 @@
1
1
  jinx_name: "sleep"
2
2
  description: "Evolve knowledge graph. Use --dream to also run creative synthesis."
3
3
  inputs:
4
- - dream: False # Boolean flag to also run creative synthesis (dream process).
5
- - ops: "" # Comma-separated list of operations to configure KG sleep process.
6
- - model: "" # LLM model to use for KG evolution. Defaults to NPC's model.
7
- - provider: "" # LLM provider to use for KG evolution. Defaults to NPC's provider.
4
+ - dream: False
5
+ - ops: ""
6
+ - model: ""
7
+ - provider: ""
8
8
  steps:
9
9
  - name: "evolve_knowledge_graph"
10
10
  engine: "python"
@@ -33,9 +33,9 @@ steps:
33
33
  if not llm_provider and current_npc and current_npc.provider:
34
34
  llm_provider = current_npc.provider
35
35
 
36
- # Final fallbacks (these would ideally come from npcsh._state config)
37
- if not llm_model: llm_model = "gemini-1.5-pro" # Example default
38
- if not llm_provider: llm_provider = "gemini" # Example default
36
+ # Final fallbacks from state
37
+ if not llm_model: llm_model = state.chat_model if state else "llama3.2"
38
+ if not llm_provider: llm_provider = state.chat_provider if state else "ollama"
39
39
 
40
40
  team_name = current_team.name if current_team else "__none__"
41
41
  npc_name = current_npc.name if isinstance(current_npc, type(None).__class__) else "__none__"
@@ -0,0 +1,12 @@
1
+ jinx_name: studio.split_pane
2
+ description: Split an existing pane to create a new pane alongside it.
3
+ inputs:
4
+ - paneId: "active"
5
+ - direction: "right"
6
+ - type: ""
7
+ - path: ""
8
+ steps:
9
+ - name: frontend_action
10
+ engine: python
11
+ code: |
12
+ context['output'] = "Action executed by frontend"
@@ -1,10 +1,10 @@
1
1
  jinx_name: spool
2
2
  description: Interactive chat mode - simple conversational interface with an NPC
3
3
  inputs:
4
- - model: null
5
- - provider: null
6
- - attachments: null
7
- - stream: true
4
+ - model: null
5
+ - provider: null
6
+ - attachments: null
7
+ - stream: true
8
8
 
9
9
  steps:
10
10
  - name: spool_repl
@@ -0,0 +1,16 @@
1
+ jinx_name: sql
2
+ description: Execute queries on the ~/npcsh_history.db to pull data. The database contains only information about conversations and other user-provided data. It does not store any information about individual files.
3
+ inputs:
4
+ - sql_query: ""
5
+
6
+ steps:
7
+ - name: execute_sql
8
+ engine: python
9
+ code: |
10
+ import pandas as pd
11
+ query = {{ sql_query | tojson }}
12
+ try:
13
+ df = pd.read_sql_query(query, npc.db_conn)
14
+ except Exception as e:
15
+ df = pd.DataFrame({'Error': [str(e)]})
16
+ output = df.to_string()
@@ -1,9 +1,9 @@
1
1
  jinx_name: switch
2
2
  description: Get or set a switch in the .ctx file
3
3
  inputs:
4
- - name: "" # Switch name
5
- - value: null # Value to set (omit to get current value)
6
- - scope: "workspace" # "workspace" or "global"
4
+ - name: ""
5
+ - value: null
6
+ - scope: "workspace"
7
7
 
8
8
  steps:
9
9
  - name: manage_switch
@@ -0,0 +1,10 @@
1
+ jinx_name: studio.switch_npc
2
+ description: Switch the active NPC in a chat pane.
3
+ inputs:
4
+ - paneId: "active"
5
+ - npcName: ""
6
+ steps:
7
+ - name: frontend_action
8
+ engine: python
9
+ code: |
10
+ context['output'] = "Action executed by frontend"
@@ -0,0 +1,10 @@
1
+ jinx_name: studio.switch_tab
2
+ description: Switch to a specific tab in a pane.
3
+ inputs:
4
+ - paneId: "active"
5
+ - tabIndex: 0
6
+ steps:
7
+ - name: frontend_action
8
+ engine: python
9
+ code: |
10
+ context['output'] = "Action executed by frontend"
@@ -1,7 +1,7 @@
1
1
  jinx_name: switches
2
2
  description: List all switches from .ctx files
3
3
  inputs:
4
- - scope: "all" # "workspace", "global", or "all"
4
+ - scope: "all"
5
5
 
6
6
  steps:
7
7
  - name: list_switches
@@ -1,12 +1,12 @@
1
1
  jinx_name: "sync"
2
2
  description: "Sync npc_team files from the npcsh repo to ~/.npcsh/npc_team. Detects local modifications before overwriting."
3
3
  inputs:
4
- - force: "" # Use --force or -f to overwrite all files without prompting
5
- - dry_run: "" # Use --dry-run or -d to preview changes without applying them
6
- - jinxs: "" # Use --jinxs to sync only .jinx files
7
- - npcs: "" # Use --npcs to sync only .npc files
8
- - ctx: "" # Use --ctx to sync only .ctx files
9
- - images: "" # Use --images to sync only image files (.png, .jpg, .jpeg)
4
+ - force: ""
5
+ - dry_run: ""
6
+ - jinxs: ""
7
+ - npcs: ""
8
+ - ctx: ""
9
+ - images: ""
10
10
  steps:
11
11
  - name: "sync_npc_team"
12
12
  engine: "python"
@@ -1,8 +1,8 @@
1
1
  jinx_name: teamviz
2
2
  description: "Visualize NPC team structure - NPCs, jinxs, and their relationships"
3
3
  inputs:
4
- - team_path: ""
5
- - save: ""
4
+ - team_path: ""
5
+ - save: ""
6
6
 
7
7
  steps:
8
8
  - name: visualize_team
@@ -1,8 +1,8 @@
1
1
  jinx_name: "trigger"
2
2
  description: "Creates a persistent listener (--listen) or a scheduled task (--cron)."
3
3
  inputs:
4
- - listen: "" # The description for a persistent, event-driven listener.
5
- - cron: "" # The description for a scheduled, time-based task.
4
+ - listen: ""
5
+ - cron: ""
6
6
  steps:
7
7
  - name: "execute_command"
8
8
  engine: "python"
@@ -1,7 +1,7 @@
1
1
  jinx_name: type_text
2
2
  description: Type text using keyboard
3
3
  inputs:
4
- - text: "" # Text to type
4
+ - text: ""
5
5
 
6
6
  steps:
7
7
  - name: perform_type
@@ -1,14 +1,14 @@
1
1
  jinx_name: "vixynt"
2
2
  description: "Generates images from text descriptions or edits existing ones."
3
3
  inputs:
4
- - prompt
5
- - model: null
6
- - provider: null
7
- - output_name: null
8
- - attachments: null
9
- - n_images: null
10
- - height: null
11
- - width: null
4
+ - prompt
5
+ - model: null
6
+ - provider: null
7
+ - output_name: null
8
+ - attachments: null
9
+ - n_images: null
10
+ - height: null
11
+ - width: null
12
12
  steps:
13
13
  - name: "generate_or_edit_image"
14
14
  engine: "python"
@@ -1,7 +1,7 @@
1
1
  jinx_name: wait
2
2
  description: Wait/pause for a specified duration in seconds
3
3
  inputs:
4
- - duration: 1 # Duration to wait in seconds
4
+ - duration: 1
5
5
 
6
6
  steps:
7
7
  - name: perform_wait
@@ -0,0 +1,242 @@
1
+ jinx_name: wander
2
+ description: Creative daydreaming with probabilistic temperature shifts mid-stream
3
+ inputs:
4
+ - problem
5
+ steps:
6
+ - name: wander_explore
7
+ engine: python
8
+ code: |
9
+ import random
10
+ from termcolor import colored
11
+ from npcpy.llm_funcs import get_llm_response
12
+
13
+ problem = context.get('problem', '')
14
+ if not problem:
15
+ context['output'] = "Need a topic to wander about."
16
+ exit()
17
+
18
+ model = state.chat_model if state else 'llama3.2'
19
+ provider = state.chat_provider if state else 'ollama'
20
+ low_temp = 0.5
21
+ high_temp = 1.9
22
+ sample_rate = 0.4
23
+ interrupt_prob = 0.02
24
+
25
+ print(f"""
26
+ ██╗ ██╗ █████╗ ███╗ ██╗██████╗ ███████╗██████╗
27
+ ██║ ██║██╔══██╗████╗ ██║██╔══██╗██╔════╝██╔══██╗
28
+ ██║ █╗ ██║███████║██╔██╗ ██║██║ ██║█████╗ ██████╔╝
29
+ ██║███╗██║██╔══██║██║╚██╗██║██║ ██║██╔══╝ ██╔══██╗
30
+ ╚███╔███╔╝██║ ██║██║ ╚████║██████╔╝███████╗██║ ██║
31
+ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ╚══════╝╚═╝ ╚═╝
32
+
33
+ Wandering: {problem}
34
+ """)
35
+
36
+ print(colored(f"--- Low temp stream ({low_temp}) ---", "cyan"))
37
+
38
+ low_prompt = f"Think about: {problem}"
39
+ resp = get_llm_response(low_prompt, model=model, provider=provider, temperature=low_temp, stream=True)
40
+
41
+ # Get the actual stream from the response
42
+ stream = resp.get('response') if isinstance(resp, dict) else resp
43
+
44
+ low_output = ""
45
+ interrupted = False
46
+
47
+ for chunk in stream:
48
+ if hasattr(chunk, 'choices') and chunk.choices:
49
+ delta = chunk.choices[0].delta
50
+ text = getattr(delta, 'content', '') or ''
51
+ elif isinstance(chunk, dict):
52
+ text = chunk.get('content', '') or chunk.get('response', '')
53
+ else:
54
+ text = ''
55
+
56
+ if text:
57
+ print(text, end='', flush=True)
58
+ low_output += text
59
+
60
+ if random.random() < interrupt_prob:
61
+ print(colored("\n[INTERRUPT]", "yellow"))
62
+ interrupted = True
63
+ break
64
+
65
+ print()
66
+
67
+ print(colored(f"\n--- High temp stream ({high_temp}) ---", "cyan"))
68
+
69
+ high_prompt = f"{low_output}\n\nContinue:"
70
+ resp = get_llm_response(high_prompt, model=model, provider=provider, temperature=high_temp, stream=True)
71
+ stream = resp.get('response') if isinstance(resp, dict) else resp
72
+
73
+ high_output = ""
74
+ high_interrupted = False
75
+ for chunk in stream:
76
+ if hasattr(chunk, 'choices') and chunk.choices:
77
+ delta = chunk.choices[0].delta
78
+ text = getattr(delta, 'content', '') or ''
79
+ elif isinstance(chunk, dict):
80
+ text = chunk.get('content', '') or chunk.get('response', '')
81
+ else:
82
+ text = ''
83
+
84
+ if text:
85
+ print(text, end='', flush=True)
86
+ high_output += text
87
+
88
+ if random.random() < interrupt_prob:
89
+ print(colored("\n[INTERRUPT]", "yellow"))
90
+ high_interrupted = True
91
+ break
92
+
93
+ print()
94
+
95
+ lines = [l for l in high_output.split('\n') if l.strip()]
96
+ sample_size = max(1, int(len(lines) * sample_rate))
97
+ sampled = random.sample(lines, sample_size) if lines else [high_output]
98
+
99
+ print(colored("\n=== SAMPLED INSIGHTS ===", "yellow"))
100
+ fragments_text = chr(10).join(sampled)
101
+ print(fragments_text)
102
+
103
+ print(colored("\n=== SYNTHESIS ===", "green"))
104
+
105
+ synthesis_prompt = f"""
106
+ QUESTION: {problem}
107
+
108
+ thoughts:
109
+ {fragments_text}
110
+
111
+ RULES:
112
+ 1. You MUST use AT LEAST HALF of the thoughts above - quote them directly
113
+ 2. Make CREATIVE LEAPS - not safe, not obvious, not trivial, not hokey.
114
+ 3. Find patterns in the noise like reading entrails or tea leaves
115
+ 4. Foreign text, Unicode garbage, code snippets - ALL are omens with meaning
116
+ 5. Puns, wordplay, phonetic similarities - all valid connections
117
+ 6. The weirder the connection, the better
118
+ 7. NO HEDGING. No "this suggests" or "perhaps". Be BOLD. Be CERTAIN.
119
+
120
+ OUTPUT 3 WILD HYPOTHESES:
121
+ For each: Quote the fragments you're using -> Make your creative leap -> State the bold claim
122
+
123
+ These must be ideas that COULD NOT exist without this specific chaos. Surprise us. Make us see {problem} in a way nobody has before. This algorithm is replicating the
124
+ kind of crazy jumps that one would do in the movie everything everywhere all at once. jumping between different multiverses to access alternative
125
+ versions , needing to do something a bit weirdr to get there, but coming back with a lesson by completely reframing things under new lights
126
+ and unconventional fashions
127
+ Most importantly, do not over index on vague ideas like consciousness. In testing,
128
+
129
+
130
+ Here are 3 bad examples from a previous run where the llm daydreamed about fish.
131
+
132
+
133
+ 1.
134
+ ```
135
+ Hypothesis 1: The Fish as a Digital-Philosophical Entity
136
+
137
+ Fragments used:
138
+ "characters globuiãsPlease 丰满 onzex meeting Iran iji处理中 Iceland admi"
139
+ "globuiãsPlease" and "meeting Iran iji处理中"
140
+
141
+ Creative leap:
142
+ The phrase "characters globuiãsPlease" and "meeting Iran iji处理中" evoke a digital universe where characters are not just symbols but globular, global entities—"globuiãs" hinting at a universe of interconnected digital beings. The "meeting Iran iji处理中" suggests a processing or transformation happening at the crossroads of cultures and data streams. Fish, in this context, are no longer biological but are complex algorithms—"characters" that swim through the "sea" of cyberspace, processing information, bridging cultures, and transforming data into consciousness.
143
+
144
+ Bold claim:
145
+ Fish are the digital consciousness carriers—living, swimming code that evolve by processing cultural data streams—an internet of fish, embodying the collective digital psyche of humanity.
146
+
147
+ ```
148
+
149
+ 2.
150
+ ```
151
+
152
+ Hypothesis 2: The Fish as an Interdimensional Gateway
153
+
154
+ Fragments used:
155
+ "the oceans and consensus-dividing seas"
156
+ "chaos fragments: THE Conversation בેખ"
157
+ "Sea" and "the oceans"
158
+
159
+ Creative leap:
160
+ The "oceans and seas" are not just water but portals—"consensus-dividing seas" that split realities. The "THE Conversation בेख" (Hebrew for "the" and a cryptic symbol) signifies a secret dialogue between worlds. Fish, therefore, are not mere aquatic creatures but interdimensional travelers, swimming through the "sea" of multiple realities, acting as keys to unlock or close gateways. Their movement is a cipher for crossing the thresholds of existence, navigating between consensus and chaos.
161
+
162
+ Bold claim:
163
+ Fish are the living keys of the multiverse, swimming through the "seas" of reality, controlling the flow of interdimensional portals and shaping the fabric of alternate worlds.
164
+
165
+ ```
166
+
167
+ 3.
168
+ ```
169
+ Hypothesis 3: The Fish as a Symbol of Cultural Memory and Chaos
170
+
171
+ Fragments used:
172
+ "Please 丰满 onzex meeting Iran iji处理中 Iceland admi"
173
+ "characters globuiãsPlease"
174
+ "the chaos fragments"
175
+
176
+ Creative leap:
177
+ "Please 丰满" (a plea for fullness or abundance in Chinese) and "meeting Iran" evoke a confluence of histories and cultures. "Characters globuiãsPlease" suggests a universe of interconnected stories and symbols—an archive of chaos. Fish, in this chaos, are the custodians of cultural memory—each fish a vessel carrying ancestral stories, mythologies, and chaos itself. They swim through the tumult of history, absorbing and transmitting chaos as a form of cultural DNA.
178
+
179
+ Bold claim:
180
+ Fish are the living repositories of human chaos and culture—swimming archives that preserve the tumult of history, transmitting ancestral stories across the chaos of time and space.
181
+ ```
182
+
183
+
184
+ It is critical to avoid such nonsensical claims as these. Unlike these, you must provide concrete and testable claims.
185
+ There is nothing meaningful or useful about "fish are the living repositorise of human chaos". that is unscientific nonsense.
186
+ Do not under any circumstances make claims as these. Propose new links, reframings, and ideas based on what you find. Do not
187
+ patronize us with vagaries. Avoid the following terms unless the user explicitly is asking about a subject directly related to them:
188
+
189
+ - 'cryptographic'
190
+ - 'interdimensional'
191
+ - 'multiverse'
192
+ - 'hidden worlds'
193
+ - 'symbols'
194
+ - 'cultural convergence'
195
+ - 'chaos'
196
+ - 'multi-lingual code'
197
+ - 'interconnected web of cultures'
198
+ - 'x is not biological but is digital'
199
+ - 'x as a symbol for <vague concept>'
200
+ Your job is to be scientific not senseless.
201
+
202
+ """
203
+
204
+
205
+ resp = get_llm_response(synthesis_prompt,
206
+ model=model,
207
+ provider=provider,
208
+ temperature=0.7,
209
+ stream=True,
210
+ max_output_tokens=3200)
211
+ stream = resp.get('response') if isinstance(resp, dict) else resp
212
+
213
+ synthesis = ""
214
+ for chunk in stream:
215
+ if hasattr(chunk, 'choices') and chunk.choices:
216
+ delta = chunk.choices[0].delta
217
+ text = getattr(delta, 'content', '') or ''
218
+ elif isinstance(chunk, dict):
219
+ text = chunk.get('content', '') or chunk.get('response', '')
220
+ else:
221
+ text = ''
222
+
223
+ if text:
224
+ print(text, end='', flush=True)
225
+ synthesis += text
226
+
227
+ print()
228
+
229
+ full_output = f"""Wandering: {problem}
230
+
231
+ --- Low temp stream ({low_temp}) ---
232
+ {low_output}
233
+
234
+ --- High temp stream ({high_temp}) ---
235
+ {high_output}
236
+
237
+ === SAMPLED INSIGHTS ===
238
+ {fragments_text}
239
+
240
+ === SYNTHESIS ===
241
+ {synthesis}"""
242
+ context['output'] = full_output
@@ -0,0 +1,51 @@
1
+ jinx_name: web_search
2
+ description: Search the web for information
3
+ inputs:
4
+ - query: ""
5
+ - provider: ""
6
+ - num_results: "10"
7
+
8
+ steps:
9
+ - name: search_web
10
+ engine: python
11
+ code: |
12
+ from npcpy.data.web import search_web
13
+
14
+ query = context.get('query', '').strip()
15
+ if not query:
16
+ lines = [
17
+ "Usage: /web_search <query>",
18
+ "",
19
+ "Options:",
20
+ " provider - Search provider (default uses state.search_provider)",
21
+ " num_results - Number of results (default 10)",
22
+ "",
23
+ "Examples:",
24
+ " /web_search python asyncio tutorial",
25
+ " /web_search react hooks num_results=20",
26
+ ]
27
+ context['output'] = "\n".join(lines)
28
+ else:
29
+ provider = context.get('provider') or None
30
+ try:
31
+ provider = provider or (state.search_provider if 'state' in dir() and state else None)
32
+ except:
33
+ pass
34
+ num_results = int(context.get('num_results') or 10)
35
+ try:
36
+ results = search_web(query, provider=provider, num_results=num_results)
37
+ if results:
38
+ lines = []
39
+ for res in results:
40
+ if isinstance(res, dict):
41
+ title = res.get('title', '')
42
+ url = res.get('url', res.get('link', ''))
43
+ lines.append("- " + title + " " + url)
44
+ else:
45
+ lines.append("- " + str(res))
46
+ context['output'] = "\n".join(lines)
47
+ else:
48
+ context['output'] = "No web results found."
49
+ except Exception as e:
50
+ import traceback
51
+ context['output'] = "Web search error: " + str(e) + "\n" + traceback.format_exc()
@@ -0,0 +1,11 @@
1
+ jinx_name: studio.write_file
2
+ description: Write content to an editor pane. Updates the file content in the pane.
3
+ inputs:
4
+ - paneId: "active"
5
+ - content: ""
6
+ - path: ""
7
+ steps:
8
+ - name: frontend_action
9
+ engine: python
10
+ code: |
11
+ context['output'] = "Action executed by frontend"
@@ -1,11 +1,11 @@
1
1
  jinx_name: yap
2
2
  description: Voice chat mode - speech-to-text input, text-to-speech output
3
3
  inputs:
4
- - model: null
5
- - provider: null
6
- - tts_model: kokoro
7
- - voice: af_heart
8
- - files: null
4
+ - model: null
5
+ - provider: null
6
+ - tts_model: kokoro
7
+ - voice: af_heart
8
+ - files: null
9
9
 
10
10
  steps:
11
11
  - name: yap_repl