npcsh 1.1.21__py3-none-any.whl → 1.1.22__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 (136) hide show
  1. npcsh/_state.py +10 -5
  2. npcsh/benchmark/npcsh_agent.py +22 -14
  3. npcsh/benchmark/templates/install-npcsh.sh.j2 +2 -2
  4. npcsh/mcp_server.py +9 -1
  5. npcsh/npc_team/alicanto.npc +12 -6
  6. npcsh/npc_team/corca.npc +0 -1
  7. npcsh/npc_team/frederic.npc +2 -3
  8. npcsh/npc_team/jinxs/lib/core/edit_file.jinx +83 -61
  9. npcsh/npc_team/jinxs/modes/alicanto.jinx +102 -41
  10. npcsh/npc_team/jinxs/modes/build.jinx +378 -0
  11. npcsh/npc_team/jinxs/modes/convene.jinx +597 -0
  12. npcsh/npc_team/jinxs/modes/corca.jinx +777 -387
  13. npcsh/npc_team/jinxs/modes/kg.jinx +69 -2
  14. npcsh/npc_team/jinxs/modes/plonk.jinx +16 -7
  15. npcsh/npc_team/jinxs/modes/yap.jinx +628 -187
  16. npcsh/npc_team/kadiefa.npc +2 -1
  17. npcsh/npc_team/sibiji.npc +3 -3
  18. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.jinx +102 -41
  19. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.npc +12 -6
  20. npcsh-1.1.22.data/data/npcsh/npc_team/build.jinx +378 -0
  21. npcsh-1.1.22.data/data/npcsh/npc_team/corca.jinx +820 -0
  22. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca.npc +0 -1
  23. npcsh-1.1.22.data/data/npcsh/npc_team/edit_file.jinx +119 -0
  24. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/frederic.npc +2 -3
  25. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kadiefa.npc +2 -1
  26. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kg.jinx +69 -2
  27. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.jinx +16 -7
  28. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sibiji.npc +3 -3
  29. npcsh-1.1.22.data/data/npcsh/npc_team/yap.jinx +716 -0
  30. {npcsh-1.1.21.dist-info → npcsh-1.1.22.dist-info}/METADATA +246 -281
  31. {npcsh-1.1.21.dist-info → npcsh-1.1.22.dist-info}/RECORD +127 -130
  32. npcsh/npc_team/jinxs/lib/core/search/kg_search.jinx +0 -429
  33. npcsh/npc_team/jinxs/lib/core/search.jinx +0 -54
  34. npcsh/npc_team/jinxs/lib/utils/build.jinx +0 -65
  35. npcsh-1.1.21.data/data/npcsh/npc_team/build.jinx +0 -65
  36. npcsh-1.1.21.data/data/npcsh/npc_team/corca.jinx +0 -430
  37. npcsh-1.1.21.data/data/npcsh/npc_team/edit_file.jinx +0 -97
  38. npcsh-1.1.21.data/data/npcsh/npc_team/kg_search.jinx +0 -429
  39. npcsh-1.1.21.data/data/npcsh/npc_team/search.jinx +0 -54
  40. npcsh-1.1.21.data/data/npcsh/npc_team/yap.jinx +0 -275
  41. /npcsh/npc_team/jinxs/lib/{core → utils}/chat.jinx +0 -0
  42. /npcsh/npc_team/jinxs/lib/{core → utils}/cmd.jinx +0 -0
  43. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/add_tab.jinx +0 -0
  44. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/alicanto.png +0 -0
  45. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/arxiv.jinx +0 -0
  46. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/benchmark.jinx +0 -0
  47. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/browser_action.jinx +0 -0
  48. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/browser_screenshot.jinx +0 -0
  49. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/chat.jinx +0 -0
  50. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/click.jinx +0 -0
  51. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_browser.jinx +0 -0
  52. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_pane.jinx +0 -0
  53. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/close_tab.jinx +0 -0
  54. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/cmd.jinx +0 -0
  55. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/compile.jinx +0 -0
  56. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/compress.jinx +0 -0
  57. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/config_tui.jinx +0 -0
  58. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/confirm.jinx +0 -0
  59. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/convene.jinx +0 -0
  60. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca.png +0 -0
  61. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/corca_example.png +0 -0
  62. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/db_search.jinx +0 -0
  63. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/delegate.jinx +0 -0
  64. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/file_search.jinx +0 -0
  65. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/focus_pane.jinx +0 -0
  66. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/frederic4.png +0 -0
  67. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/git.jinx +0 -0
  68. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.jinx +0 -0
  69. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.npc +0 -0
  70. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/guac.png +0 -0
  71. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/help.jinx +0 -0
  72. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/incognide.jinx +0 -0
  73. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/init.jinx +0 -0
  74. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/jinxs.jinx +0 -0
  75. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/kadiefa.png +0 -0
  76. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/key_press.jinx +0 -0
  77. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/launch_app.jinx +0 -0
  78. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/list_panes.jinx +0 -0
  79. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/load_file.jinx +0 -0
  80. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/memories.jinx +0 -0
  81. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/models.jinx +0 -0
  82. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/navigate.jinx +0 -0
  83. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/notify.jinx +0 -0
  84. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/npcsh.ctx +0 -0
  85. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/npcsh_sibiji.png +0 -0
  86. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/nql.jinx +0 -0
  87. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/open_browser.jinx +0 -0
  88. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/open_pane.jinx +0 -0
  89. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/ots.jinx +0 -0
  90. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/papers.jinx +0 -0
  91. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/paste.jinx +0 -0
  92. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.npc +0 -0
  93. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonk.png +0 -0
  94. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/plonkjr.png +0 -0
  95. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/pti.jinx +0 -0
  96. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/python.jinx +0 -0
  97. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/read_pane.jinx +0 -0
  98. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/reattach.jinx +0 -0
  99. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/roll.jinx +0 -0
  100. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/run_terminal.jinx +0 -0
  101. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sample.jinx +0 -0
  102. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/screenshot.jinx +0 -0
  103. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/send_message.jinx +0 -0
  104. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/serve.jinx +0 -0
  105. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/set.jinx +0 -0
  106. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/setup.jinx +0 -0
  107. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sh.jinx +0 -0
  108. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/shh.jinx +0 -0
  109. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sibiji.png +0 -0
  110. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sleep.jinx +0 -0
  111. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/split_pane.jinx +0 -0
  112. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/spool.jinx +0 -0
  113. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/spool.png +0 -0
  114. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sql.jinx +0 -0
  115. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch.jinx +0 -0
  116. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch_npc.jinx +0 -0
  117. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switch_tab.jinx +0 -0
  118. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/switches.jinx +0 -0
  119. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/sync.jinx +0 -0
  120. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/team.jinx +0 -0
  121. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/teamviz.jinx +0 -0
  122. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/trigger.jinx +0 -0
  123. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/type_text.jinx +0 -0
  124. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/usage.jinx +0 -0
  125. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/verbose.jinx +0 -0
  126. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/vixynt.jinx +0 -0
  127. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/wait.jinx +0 -0
  128. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/wander.jinx +0 -0
  129. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/web_search.jinx +0 -0
  130. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/write_file.jinx +0 -0
  131. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/yap.png +0 -0
  132. {npcsh-1.1.21.data → npcsh-1.1.22.data}/data/npcsh/npc_team/zen_mode.jinx +0 -0
  133. {npcsh-1.1.21.dist-info → npcsh-1.1.22.dist-info}/WHEEL +0 -0
  134. {npcsh-1.1.21.dist-info → npcsh-1.1.22.dist-info}/entry_points.txt +0 -0
  135. {npcsh-1.1.21.dist-info → npcsh-1.1.22.dist-info}/licenses/LICENSE +0 -0
  136. {npcsh-1.1.21.dist-info → npcsh-1.1.22.dist-info}/top_level.txt +0 -0
@@ -27,5 +27,4 @@ jinxs:
27
27
  - lib/core/python
28
28
  - lib/core/edit_file
29
29
  - lib/core/load_file
30
- - lib/core/search
31
30
 
@@ -0,0 +1,119 @@
1
+ jinx_name: edit_file
2
+ description: Creates or edits a file. If the file does not exist, creates it with
3
+ the specified content. If the file exists, examines it and applies changes.
4
+ inputs:
5
+ - file_path
6
+ - edit_instructions
7
+ - backup: true
8
+ steps:
9
+ - name: "edit_file"
10
+ engine: "python"
11
+ code: |
12
+ import os
13
+ from npcpy.llm_funcs import get_llm_response
14
+
15
+
16
+ file_path = os.path.expanduser({{ file_path | tojson }})
17
+ edit_instructions = {{ edit_instructions | string | tojson }}
18
+ backup_str = {{ backup | default("true") | string | tojson }}
19
+ create_backup = backup_str.lower() not in ('false', 'no', '0', '')
20
+
21
+ # Ensure parent directory exists
22
+ os.makedirs(os.path.dirname(file_path) or '.', exist_ok=True)
23
+
24
+ # If file doesn't exist, create it
25
+ if not os.path.exists(file_path):
26
+ prompt = """You are a code writing assistant. Create the content for a new file based on these instructions.
27
+
28
+ Instructions: """ + edit_instructions + """
29
+
30
+ Return a JSON object with:
31
+ 1. "content": The full content to write to the file
32
+ 2. "explanation": Brief explanation of what was created
33
+
34
+ Example response:
35
+ {"content": "print('hello world')", "explanation": "Created a Python hello world script"}
36
+ """
37
+ response = get_llm_response(prompt, model=npc.model, provider=npc.provider, npc=npc, format="json")
38
+ result = response.get("response", {})
39
+ content = result.get("content", edit_instructions)
40
+ explanation = result.get("explanation", "Created new file")
41
+
42
+ with open(file_path, 'w') as f:
43
+ f.write(content)
44
+
45
+ output = "Created " + file_path + "\n\n" + explanation
46
+ else:
47
+ with open(file_path, 'r') as f:
48
+ original_content = f.read()
49
+
50
+ if create_backup:
51
+ backup_path = file_path + ".bak"
52
+ with open(backup_path, 'w') as f:
53
+ f.write(original_content)
54
+
55
+ prompt = """You are a code editing assistant. Analyze this file and make the requested changes.
56
+
57
+ File content:
58
+ """ + original_content + """
59
+
60
+ Edit instructions: """ + edit_instructions + """
61
+
62
+ Return a JSON object with these fields:
63
+ 1. "modifications": An array of modification objects, where each object has:
64
+ - "type": One of "replace", "insert_after", "insert_before", or "delete"
65
+ - "target": For "insert_after" and "insert_before", the text to insert after/before
66
+ For "delete", the text to delete
67
+ - "original": For "replace", the text to be replaced
68
+ - "replacement": For "replace", the text to replace with
69
+ - "insertion": For "insert_after" and "insert_before", the text to insert
70
+ 2. "explanation": Brief explanation of the changes made
71
+
72
+ Example response:
73
+ {"modifications": [{"type": "replace", "original": "old code", "replacement": "new code"}], "explanation": "Updated the code"}
74
+ """
75
+
76
+ response = get_llm_response(prompt, model=npc.model, provider=npc.provider, npc=npc, format="json")
77
+
78
+ result = response.get("response", {})
79
+ modifications = result.get("modifications", [])
80
+ explanation = result.get("explanation", "No explanation provided")
81
+
82
+ updated_content = original_content
83
+ changes_applied = 0
84
+
85
+ for mod in modifications:
86
+ print(mod)
87
+ mod_type = mod.get("type")
88
+
89
+ if mod_type == "replace":
90
+ original = mod.get("original")
91
+ replacement = mod.get("replacement")
92
+ if original in updated_content:
93
+ updated_content = updated_content.replace(original, replacement)
94
+ changes_applied += 1
95
+
96
+ elif mod_type == "insert_after":
97
+ target = mod.get("target")
98
+ insertion = mod.get("insertion")
99
+ if target in updated_content:
100
+ updated_content = updated_content.replace(target, target + insertion)
101
+ changes_applied += 1
102
+
103
+ elif mod_type == "insert_before":
104
+ target = mod.get("target")
105
+ insertion = mod.get("insertion")
106
+ if target in updated_content:
107
+ updated_content = updated_content.replace(target, insertion + target)
108
+ changes_applied += 1
109
+
110
+ elif mod_type == "delete":
111
+ target = mod.get("target")
112
+ if target in updated_content:
113
+ updated_content = updated_content.replace(target, "")
114
+ changes_applied += 1
115
+
116
+ with open(file_path, 'w') as f:
117
+ f.write(updated_content)
118
+
119
+ output = "Applied " + str(changes_applied) + " changes to " + file_path + "\n\n" + explanation
@@ -22,6 +22,5 @@ jinxs:
22
22
  - lib/core/sql
23
23
  - lib/core/sh
24
24
  - lib/core/load_file
25
- - lib/core/search
26
- - lib/gen/*
27
- - bin/wander
25
+ - lib/core/search/web_search
26
+ - lib/core/edit_file
@@ -18,4 +18,5 @@ primary_directive: |
18
18
  Use web search and browsing tools to discover new information.
19
19
  jinxs:
20
20
  - lib/core/python
21
- - bin/wander
21
+ - lib/core/sh
22
+ - lib/core/search/web_search
@@ -1,7 +1,11 @@
1
1
  jinx_name: kg
2
2
  description: Interactive knowledge graph browser - explore facts, concepts, and links
3
3
  interactive: true
4
- inputs: []
4
+ inputs:
5
+ - action: ""
6
+ - dream: false
7
+ - backfill: false
8
+ - ops: ""
5
9
  steps:
6
10
  - name: kg_browser
7
11
  engine: python
@@ -12,7 +16,70 @@ steps:
12
16
  import termios
13
17
  import select
14
18
 
15
- if not sys.stdin.isatty():
19
+ _kg_action = (context.get('action') or '').strip().lower()
20
+
21
+ if _kg_action in ('sleep', 'evolve', 'dream'):
22
+ # Route to KG evolution operations
23
+ import traceback
24
+ from npcpy.memory.command_history import CommandHistory, load_kg_from_db, save_kg_to_db
25
+ from npcpy.memory.knowledge_graph import kg_sleep_process, kg_dream_process, kg_backfill_from_memories
26
+
27
+ _npc = context.get('npc')
28
+ _team = context.get('team')
29
+ _msgs = context.get('messages', [])
30
+ _do_dream = _kg_action == 'dream' or str(context.get('dream', '')).lower() in ('true', '1', 'yes')
31
+ _do_backfill = str(context.get('backfill', '')).lower() in ('true', '1', 'yes')
32
+ _ops_str = context.get('ops', '')
33
+ _ops_config = [op.strip() for op in _ops_str.split(',') if op.strip()] if _ops_str else None
34
+
35
+ _model = (_npc.model if _npc and hasattr(_npc, 'model') else None) or (state.chat_model if state else 'llama3.2')
36
+ _provider = (_npc.provider if _npc and hasattr(_npc, 'provider') else None) or (state.chat_provider if state else 'ollama')
37
+
38
+ _team_name = _team.name if _team else '__none__'
39
+ _npc_name = _npc.name if _npc else '__none__'
40
+ _cur_path = os.getcwd()
41
+
42
+ try:
43
+ _db_path = os.getenv('NPCSH_DB_PATH', os.path.expanduser('~/npcsh_history.db'))
44
+ _ch = CommandHistory(_db_path)
45
+ _eng = _ch.engine
46
+
47
+ _result = ''
48
+ if _do_backfill:
49
+ print('Backfilling from approved memories...')
50
+ _stats = kg_backfill_from_memories(_eng, model=_model, provider=_provider, npc=_npc, get_concepts=True, dry_run=False)
51
+ _result += f"Backfill: +{_stats['facts_after'] - _stats['facts_before']} facts, +{_stats['concepts_after'] - _stats['concepts_before']} concepts\n"
52
+
53
+ _kg = load_kg_from_db(_eng, _team_name, _npc_name, _cur_path)
54
+ if not _kg or not _kg.get('facts'):
55
+ context['output'] = _result + 'Knowledge graph is empty. Use /kg backfill=true or have conversations first.'
56
+ context['messages'] = _msgs
57
+ _ch.close()
58
+ exit()
59
+
60
+ _f0 = len(_kg.get('facts', []))
61
+ _c0 = len(_kg.get('concepts', []))
62
+ _label = 'Sleep'
63
+
64
+ _kg, _ = kg_sleep_process(existing_kg=_kg, model=_model, provider=_provider, npc=_npc, operations_config=_ops_config)
65
+
66
+ if _do_dream:
67
+ _label += ' & Dream'
68
+ _kg, _ = kg_dream_process(existing_kg=_kg, model=_model, provider=_provider, npc=_npc)
69
+
70
+ save_kg_to_db(_eng, _kg, _team_name, _npc_name, _cur_path)
71
+ _f1 = len(_kg.get('facts', []))
72
+ _c1 = len(_kg.get('concepts', []))
73
+ _result += f"{_label} complete. Facts: {_f0} -> {_f1} ({_f1-_f0:+}), Concepts: {_c0} -> {_c1} ({_c1-_c0:+})"
74
+ context['output'] = _result
75
+ context['messages'] = _msgs
76
+ _ch.close()
77
+ except Exception as e:
78
+ traceback.print_exc()
79
+ context['output'] = f'KG evolution error: {e}'
80
+ context['messages'] = _msgs
81
+
82
+ elif not sys.stdin.isatty():
16
83
  context['output'] = "KG browser requires an interactive terminal."
17
84
 
18
85
  else:
@@ -123,7 +123,7 @@ steps:
123
123
  render_screen()
124
124
 
125
125
  try:
126
- ss = capture_screenshot()
126
+ ss = capture_screenshot(full=True)
127
127
  if not ss or 'file_path' not in ss:
128
128
  task['actions'].append({"action": "fail", "reason": "Screenshot failed"})
129
129
  task['status'] = 'failed'
@@ -143,6 +143,9 @@ steps:
143
143
  history_context += " - " + act.get('reason', '') + "\n"
144
144
 
145
145
  prompt = "You are a GUI automation assistant. Analyze this screenshot and determine the next action.\n\n"
146
+ prompt += "IMPORTANT: Before taking new actions, VERIFY the current screenshot shows the expected result of your previous actions. "
147
+ prompt += "If the page is still loading or hasn't changed yet, use 'wait' with duration 2-3 seconds. "
148
+ prompt += "Do NOT blindly proceed — confirm each step worked before moving on.\n\n"
146
149
  prompt += "TASK: " + task['text'] + "\n"
147
150
  prompt += history_context + "\n"
148
151
  prompt += "Available actions:\n"
@@ -150,7 +153,7 @@ steps:
150
153
  prompt += "- type: Type text (use 'text' field)\n"
151
154
  prompt += "- key: Press key like enter, tab, escape (use 'text' field)\n"
152
155
  prompt += "- launch: Launch application (use 'command' field, e.g. " + app_examples + ")\n"
153
- prompt += "- wait: Wait for 'duration' seconds\n"
156
+ prompt += "- wait: Wait for 'duration' seconds (use when page is loading or UI hasn't updated)\n"
154
157
  prompt += "- done: Task completed successfully\n"
155
158
  prompt += "- fail: Task cannot be completed\n\n"
156
159
  prompt += "Respond with JSON, e.g.: " + json_schema_example
@@ -196,20 +199,20 @@ steps:
196
199
 
197
200
  if action == 'click':
198
201
  x, y = action_response.get('x', 50), action_response.get('y', 50)
199
- perform_action('click', x=x, y=y)
202
+ perform_action({"type": "click", "x": x, "y": y})
200
203
  act_record['x'] = x
201
204
  act_record['y'] = y
202
205
  elif action == 'type':
203
206
  txt = action_response.get('text', '')
204
- perform_action('type', text=txt)
207
+ perform_action({"type": "type", "text": txt})
205
208
  act_record['text'] = txt
206
209
  elif action == 'key':
207
210
  key = action_response.get('text', 'enter')
208
- perform_action('key', key=key)
211
+ perform_action({"type": "key", "key": key})
209
212
  act_record['key'] = key
210
213
  elif action == 'launch':
211
214
  cmd = action_response.get('command', '')
212
- perform_action('launch', command=cmd)
215
+ perform_action({"type": "launch", "command": cmd})
213
216
  act_record['command'] = cmd
214
217
  time.sleep(2)
215
218
  elif action == 'wait':
@@ -219,7 +222,13 @@ steps:
219
222
 
220
223
  task['actions'].append(act_record)
221
224
  ui.status = action + " - " + reason[:40]
222
- time.sleep(0.3)
225
+ # Wait for UI to settle after state-changing actions
226
+ if action in ('key', 'click'):
227
+ time.sleep(2.0)
228
+ elif action == 'type':
229
+ time.sleep(0.5)
230
+ else:
231
+ time.sleep(0.3)
223
232
 
224
233
  if ui.mode == 'step':
225
234
  ui.mode = 'paused'
@@ -17,8 +17,8 @@ primary_directive: |
17
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
- - lib/orchestration/delegate
21
- - lib/orchestration/convene
20
+ - lib/core/delegate
21
+ - lib/core/convene
22
22
  - lib/core/sh
23
23
  - lib/core/python
24
- - lib/core/search
24
+ - lib/core/search/web_search