npcsh 1.0.29__tar.gz → 1.0.30__tar.gz

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 (52) hide show
  1. {npcsh-1.0.29 → npcsh-1.0.30}/PKG-INFO +1 -1
  2. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/_state.py +1 -1
  3. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/corca.py +20 -7
  4. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/guac.py +31 -2
  5. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npcsh.py +15 -22
  6. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh.egg-info/PKG-INFO +1 -1
  7. {npcsh-1.0.29 → npcsh-1.0.30}/setup.py +1 -1
  8. {npcsh-1.0.29 → npcsh-1.0.30}/LICENSE +0 -0
  9. {npcsh-1.0.29 → npcsh-1.0.30}/README.md +0 -0
  10. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/__init__.py +0 -0
  11. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/alicanto.py +0 -0
  12. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/mcp_helpers.py +0 -0
  13. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/mcp_server.py +0 -0
  14. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc.py +0 -0
  15. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/alicanto.npc +0 -0
  16. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/alicanto.png +0 -0
  17. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/corca.npc +0 -0
  18. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/corca.png +0 -0
  19. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/foreman.npc +0 -0
  20. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/frederic.npc +0 -0
  21. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/frederic4.png +0 -0
  22. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/guac.png +0 -0
  23. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/jinxs/bash_executer.jinx +0 -0
  24. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/jinxs/edit_file.jinx +0 -0
  25. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/jinxs/image_generation.jinx +0 -0
  26. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/jinxs/internet_search.jinx +0 -0
  27. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/jinxs/python_executor.jinx +0 -0
  28. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/jinxs/screen_cap.jinx +0 -0
  29. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/kadiefa.npc +0 -0
  30. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/kadiefa.png +0 -0
  31. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/npcsh.ctx +0 -0
  32. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/npcsh_sibiji.png +0 -0
  33. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/plonk.npc +0 -0
  34. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/plonk.png +0 -0
  35. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/plonkjr.npc +0 -0
  36. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/plonkjr.png +0 -0
  37. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/sibiji.npc +0 -0
  38. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/sibiji.png +0 -0
  39. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/spool.png +0 -0
  40. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/npc_team/yap.png +0 -0
  41. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/plonk.py +0 -0
  42. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/pti.py +0 -0
  43. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/routes.py +0 -0
  44. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/spool.py +0 -0
  45. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/wander.py +0 -0
  46. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh/yap.py +0 -0
  47. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh.egg-info/SOURCES.txt +0 -0
  48. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh.egg-info/dependency_links.txt +0 -0
  49. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh.egg-info/entry_points.txt +0 -0
  50. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh.egg-info/requires.txt +0 -0
  51. {npcsh-1.0.29 → npcsh-1.0.30}/npcsh.egg-info/top_level.txt +0 -0
  52. {npcsh-1.0.29 → npcsh-1.0.30}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: npcsh
3
- Version: 1.0.29
3
+ Version: 1.0.30
4
4
  Summary: npcsh is a command-line toolkit for using AI agents in novel ways.
5
5
  Home-page: https://github.com/NPC-Worldwide/npcsh
6
6
  Author: Christopher Agostino
@@ -2018,7 +2018,7 @@ def process_pipeline_command(
2018
2018
  stdin_input: Optional[str],
2019
2019
  state: ShellState,
2020
2020
  stream_final: bool,
2021
- review = True,
2021
+ review = False,
2022
2022
  router = None,
2023
2023
  ) -> Tuple[ShellState, Any]:
2024
2024
  '''
@@ -236,15 +236,20 @@ def process_mcp_stream(stream_response, active_npc):
236
236
  tool_calls[idx]['function']['arguments'] += tool_call_delta.function.arguments
237
237
  except KeyboardInterrupt:
238
238
  interrupted = True
239
- print('⚠️ Stream interrupted by user')
239
+ print('\n⚠️ Stream interrupted by user')
240
240
 
241
241
  sys.stdout.write('\033[u')
242
- sys.stdout.write('\033[J')
242
+ sys.stdout.write('\033[0J')
243
243
  sys.stdout.flush()
244
244
 
245
- # Use the render_markdown function for proper markdown rendering
246
- render_markdown(collected_content)
245
+ if collected_content:
246
+ render_markdown(collected_content)
247
+
247
248
  return collected_content, tool_calls
249
+
250
+
251
+
252
+
248
253
  def execute_command_corca(command: str, state: ShellState, command_history, selected_mcp_tools_names: Optional[List[str]] = None) -> Tuple[ShellState, Any]:
249
254
  mcp_tools_for_llm = []
250
255
 
@@ -265,6 +270,17 @@ def execute_command_corca(command: str, state: ShellState, command_history, sele
265
270
 
266
271
  active_npc = state.npc if isinstance(state.npc, NPC) else NPC(name="default")
267
272
 
273
+ if len(state.messages) > 20:
274
+ compressed_state = active_npc.compress_planning_state({
275
+ "goal": "ongoing session",
276
+ "facts": [],
277
+ "successes": [],
278
+ "mistakes": [],
279
+ "todos": [],
280
+ "constraints": []
281
+ })
282
+ state.messages = [{"role": "system", "content": f"Session context: {compressed_state}"}]
283
+
268
284
  response_dict = get_llm_response(
269
285
  prompt=command,
270
286
  npc=state.npc,
@@ -280,7 +296,6 @@ def execute_command_corca(command: str, state: ShellState, command_history, sele
280
296
 
281
297
  collected_content, tool_calls = process_mcp_stream(stream_response, active_npc)
282
298
 
283
-
284
299
  state.messages = messages
285
300
  if collected_content or tool_calls:
286
301
  assistant_message = {"role": "assistant", "content": collected_content}
@@ -293,8 +308,6 @@ def execute_command_corca(command: str, state: ShellState, command_history, sele
293
308
  "tool_calls": tool_calls,
294
309
  "messages": state.messages
295
310
  }
296
-
297
-
298
311
  def _resolve_and_copy_mcp_server_path(
299
312
  explicit_path: Optional[str],
300
313
  current_path: Optional[str],
@@ -1145,12 +1145,10 @@ def _get_guac_agent_emoji(failures: int, max_fail: int = 3) -> str:
1145
1145
 
1146
1146
 
1147
1147
 
1148
-
1149
1148
  def _run_agentic_mode(command: str,
1150
1149
  state: ShellState,
1151
1150
  locals_dict: Dict[str, Any],
1152
1151
  npc_team_dir: Path) -> Tuple[ShellState, Any]:
1153
- """Run agentic mode with continuous iteration based on progress"""
1154
1152
  max_iterations = 5
1155
1153
  iteration = 0
1156
1154
  full_output = []
@@ -1158,6 +1156,37 @@ def _run_agentic_mode(command: str,
1158
1156
  consecutive_failures = 0
1159
1157
  max_consecutive_failures = 3
1160
1158
 
1159
+ if len(state.messages) > 15:
1160
+ planning_state = {
1161
+ "goal": "ongoing guac session",
1162
+ "facts": [f"Working in {state.current_path}", f"Variables: {list(locals_dict.keys())[:10]}"],
1163
+ "successes": [],
1164
+ "mistakes": [],
1165
+ "todos": [],
1166
+ "constraints": ["Focus on Python code execution", "Use existing variables when possible"]
1167
+ }
1168
+ compressed_state = state.npc.compress_planning_state(planning_state)
1169
+ state.messages = [{"role": "system", "content": f"Session context: {compressed_state}"}]
1170
+
1171
+ existing_vars_context = "EXISTING VARIABLES IN ENVIRONMENT:\n"
1172
+ for var_name, var_value in locals_dict.items():
1173
+ if not var_name.startswith('_') and var_name not in ['In', 'Out', 'exit', 'quit', 'get_ipython']:
1174
+ try:
1175
+ var_type = type(var_value).__name__
1176
+ var_repr = repr(var_value)
1177
+ if len(var_repr) > 100:
1178
+ var_repr = var_repr[:97] + "..."
1179
+ existing_vars_context += f"- {var_name} ({var_type}): {var_repr}\n"
1180
+ except:
1181
+ existing_vars_context += f"- {var_name} ({type(var_value).__name__}): <unrepresentable>\n"
1182
+ previous_code = ''
1183
+ next_step = ''
1184
+ steps = []
1185
+ while iteration < max_iterations and consecutive_failures < max_consecutive_failures:
1186
+ iteration += 1
1187
+ print(f"\n{_get_guac_agent_emoji(consecutive_failures, max_consecutive_failures)} Agentic iteration {iteration} ")
1188
+
1189
+
1161
1190
 
1162
1191
  existing_vars_context = "EXISTING VARIABLES IN ENVIRONMENT:\n"
1163
1192
  for var_name, var_value in locals_dict.items():
@@ -68,22 +68,14 @@ Begin by asking a question, issuing a bash command, or typing '/help' for more i
68
68
  )
69
69
 
70
70
 
71
-
72
71
  def run_repl(command_history: CommandHistory, initial_state: ShellState):
73
-
74
-
75
- '''
76
- Func for running the npcsh repl
77
- '''
78
72
  state = initial_state
79
73
  print_welcome_message()
80
74
 
81
-
82
75
  render_markdown(f'- Using {state.current_mode} mode. Use /agent, /cmd, or /chat to switch to other modes')
83
76
  render_markdown(f'- To switch to a different NPC, type /npc <npc_name> or /n <npc_name> to switch to that NPC.')
84
77
  render_markdown('\n- Here are the current NPCs available in your team: ' + ', '.join([npc_name for npc_name in state.team.npcs.keys()]))
85
78
 
86
-
87
79
  is_windows = platform.system().lower().startswith("win")
88
80
  try:
89
81
  completer = make_completer(state)
@@ -92,23 +84,16 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
92
84
  pass
93
85
  session_scopes = set()
94
86
 
95
-
96
87
  def exit_shell(current_state: ShellState):
97
- """
98
- On exit, iterates through all active scopes from the session and
99
- creates/updates the specific knowledge graph for each one.
100
- """
101
88
  print("\nGoodbye!")
102
89
  print(colored("Processing and archiving all session knowledge...", "cyan"))
103
90
 
104
91
  engine = command_history.engine
105
92
 
106
-
107
93
  for team_name, npc_name, path in session_scopes:
108
94
  try:
109
95
  print(f" -> Archiving knowledge for: T='{team_name}', N='{npc_name}', P='{path}'")
110
96
 
111
-
112
97
  convo_id = current_state.conversation_id
113
98
  all_messages = command_history.get_conversations_by_id(convo_id)
114
99
 
@@ -123,10 +108,8 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
123
108
  print(" ...No content for this scope, skipping.")
124
109
  continue
125
110
 
126
-
127
111
  current_kg = load_kg_from_db(engine, team_name, npc_name, path)
128
112
 
129
-
130
113
  evolved_kg, _ = kg_evolve_incremental(
131
114
  existing_kg=current_kg,
132
115
  new_content_text=full_text,
@@ -137,10 +120,8 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
137
120
  link_concepts_facts = True,
138
121
  link_concepts_concepts = True,
139
122
  link_facts_facts = True,
140
-
141
123
  )
142
124
 
143
-
144
125
  save_kg_to_db(engine,
145
126
  evolved_kg,
146
127
  team_name,
@@ -154,10 +135,20 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
154
135
 
155
136
  sys.exit(0)
156
137
 
157
-
158
-
159
138
  while True:
160
139
  try:
140
+ if len(state.messages) > 20:
141
+ planning_state = {
142
+ "goal": "ongoing npcsh session",
143
+ "facts": [f"Working in {state.current_path}", f"Current mode: {state.current_mode}"],
144
+ "successes": [],
145
+ "mistakes": [],
146
+ "todos": [],
147
+ "constraints": ["Follow user requests", "Use appropriate mode for tasks"]
148
+ }
149
+ compressed_state = state.npc.compress_planning_state(planning_state)
150
+ state.messages = [{"role": "system", "content": f"Session context: {compressed_state}"}]
151
+
161
152
  try:
162
153
  completer = make_completer(state)
163
154
  readline.set_completer(completer)
@@ -198,6 +189,7 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
198
189
  continue
199
190
  else:
200
191
  exit_shell(state)
192
+
201
193
  team_name = state.team.name if state.team else "__none__"
202
194
  npc_name = state.npc.name if isinstance(state.npc, NPC) else "__none__"
203
195
  session_scopes.add((team_name, npc_name, state.current_path))
@@ -224,7 +216,8 @@ def run_repl(command_history: CommandHistory, initial_state: ShellState):
224
216
  if is_windows and "EOF" in str(e).lower():
225
217
  print("\nHint: On Windows, use Ctrl+Z then Enter for EOF, or type 'exit'")
226
218
  continue
227
- raise # Re-raise if it's not the expected case
219
+ raise
220
+
228
221
 
229
222
  def main() -> None:
230
223
  parser = argparse.ArgumentParser(description="npcsh - An NPC-powered shell.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: npcsh
3
- Version: 1.0.29
3
+ Version: 1.0.30
4
4
  Summary: npcsh is a command-line toolkit for using AI agents in novel ways.
5
5
  Home-page: https://github.com/NPC-Worldwide/npcsh
6
6
  Author: Christopher Agostino
@@ -78,7 +78,7 @@ extra_files = package_files("npcsh/npc_team/")
78
78
 
79
79
  setup(
80
80
  name="npcsh",
81
- version="1.0.29",
81
+ version="1.0.30",
82
82
  packages=find_packages(exclude=["tests*"]),
83
83
  install_requires=base_requirements, # Only install base requirements by default
84
84
  extras_require={
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes