code-puppy 0.0.324__py3-none-any.whl → 0.0.326__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.
@@ -4,7 +4,6 @@ import asyncio
4
4
  import json
5
5
  import math
6
6
  import signal
7
- import sys
8
7
  import threading
9
8
  import uuid
10
9
  from abc import ABC, abstractmethod
@@ -1340,15 +1339,19 @@ class BaseAgent(ABC):
1340
1339
  ) -> None:
1341
1340
  """Handle streaming events from the agent run.
1342
1341
 
1343
- This method processes streaming events and emits TextPart and ThinkingPart
1344
- content with styled banners as they stream in.
1342
+ This method processes streaming events and emits TextPart, ThinkingPart,
1343
+ and ToolCallPart content with styled banners/tokens as they stream in.
1345
1344
 
1346
1345
  Args:
1347
1346
  ctx: The run context.
1348
1347
  events: Async iterable of streaming events (PartStartEvent, PartDeltaEvent, etc.).
1349
1348
  """
1350
1349
  from pydantic_ai import PartDeltaEvent, PartStartEvent
1351
- from pydantic_ai.messages import TextPartDelta, ThinkingPartDelta
1350
+ from pydantic_ai.messages import (
1351
+ TextPartDelta,
1352
+ ThinkingPartDelta,
1353
+ ToolCallPartDelta,
1354
+ )
1352
1355
  from rich.console import Console
1353
1356
  from rich.markdown import Markdown
1354
1357
  from rich.markup import escape
@@ -1364,15 +1367,16 @@ class BaseAgent(ABC):
1364
1367
  # Fallback if console not set (shouldn't happen in normal use)
1365
1368
  console = Console()
1366
1369
 
1367
- # Track which part indices we're currently streaming (for Text/Thinking parts)
1370
+ # Track which part indices we're currently streaming (for Text/Thinking/Tool parts)
1368
1371
  streaming_parts: set[int] = set()
1369
1372
  thinking_parts: set[int] = (
1370
1373
  set()
1371
1374
  ) # Track which parts are thinking (for dim style)
1372
1375
  text_parts: set[int] = set() # Track which parts are text
1376
+ tool_parts: set[int] = set() # Track which parts are tool calls
1373
1377
  banner_printed: set[int] = set() # Track if banner was already printed
1374
1378
  text_buffer: dict[int, list[str]] = {} # Buffer text for final markdown render
1375
- token_count: dict[int, int] = {} # Track token count per text part
1379
+ token_count: dict[int, int] = {} # Track token count per text/tool part
1376
1380
  did_stream_anything = False # Track if we streamed any content
1377
1381
 
1378
1382
  def _print_thinking_banner() -> None:
@@ -1442,7 +1446,16 @@ class BaseAgent(ABC):
1442
1446
  # Buffer initial content if present
1443
1447
  if part.content and part.content.strip():
1444
1448
  text_buffer[event.index].append(part.content)
1445
- token_count[event.index] += 1
1449
+ # Use len(content) / 3 for token estimation (more accurate than chunk counting)
1450
+ token_count[event.index] += len(part.content) // 3
1451
+ elif isinstance(part, ToolCallPart):
1452
+ streaming_parts.add(event.index)
1453
+ tool_parts.add(event.index)
1454
+ token_count[event.index] = 0 # Initialize token counter
1455
+ # Track tool name for display
1456
+ banner_printed.add(
1457
+ event.index
1458
+ ) # Use banner_printed to track if we've shown tool info
1446
1459
 
1447
1460
  # PartDeltaEvent - stream the content as it arrives
1448
1461
  elif isinstance(event, PartDeltaEvent):
@@ -1460,7 +1473,10 @@ class BaseAgent(ABC):
1460
1473
  banner_printed.add(event.index)
1461
1474
  # Accumulate text for final markdown render
1462
1475
  text_buffer[event.index].append(delta.content_delta)
1463
- token_count[event.index] += 1
1476
+ # Use len(content) / 3 for token estimation
1477
+ token_count[event.index] += (
1478
+ len(delta.content_delta) // 3
1479
+ )
1464
1480
  # Update token counter in place (single line)
1465
1481
  count = token_count[event.index]
1466
1482
  sys.stdout.write(
@@ -1474,14 +1490,32 @@ class BaseAgent(ABC):
1474
1490
  banner_printed.add(event.index)
1475
1491
  escaped = escape(delta.content_delta)
1476
1492
  console.print(f"[dim]{escaped}[/dim]", end="")
1493
+ elif isinstance(delta, ToolCallPartDelta):
1494
+ import sys
1495
+
1496
+ # For tool calls, show token counter (use string repr for estimation)
1497
+ token_count[event.index] += len(str(delta)) // 3
1498
+ # Get tool name if available
1499
+ tool_name = getattr(delta, "tool_name_delta", "")
1500
+ count = token_count[event.index]
1501
+ # Display with tool wrench icon and tool name
1502
+ if tool_name:
1503
+ sys.stdout.write(
1504
+ f"\r\x1b[K 🔧 Calling {tool_name}... {count} tokens"
1505
+ )
1506
+ else:
1507
+ sys.stdout.write(
1508
+ f"\r\x1b[K 🔧 Calling tool... {count} tokens"
1509
+ )
1510
+ sys.stdout.flush()
1477
1511
 
1478
1512
  # PartEndEvent - finish the streaming with a newline
1479
1513
  elif isinstance(event, PartEndEvent):
1480
1514
  if event.index in streaming_parts:
1515
+ import sys
1516
+
1481
1517
  # For text parts, clear counter line and render markdown
1482
1518
  if event.index in text_parts:
1483
- import sys
1484
-
1485
1519
  # Clear the token counter line
1486
1520
  sys.stdout.write("\r\x1b[K")
1487
1521
  sys.stdout.flush()
@@ -1494,24 +1528,31 @@ class BaseAgent(ABC):
1494
1528
  except Exception:
1495
1529
  pass
1496
1530
  del text_buffer[event.index]
1497
- # Clean up token count
1498
- token_count.pop(event.index, None)
1531
+ # For tool parts, clear the token counter line
1532
+ elif event.index in tool_parts:
1533
+ # Clear the token counter line
1534
+ sys.stdout.write("\r\x1b[K")
1535
+ sys.stdout.flush()
1499
1536
  # For thinking parts, just print newline
1500
1537
  elif event.index in banner_printed:
1501
1538
  console.print() # Final newline after streaming
1539
+
1540
+ # Clean up token count
1541
+ token_count.pop(event.index, None)
1502
1542
  # Clean up all tracking sets
1503
1543
  streaming_parts.discard(event.index)
1504
1544
  thinking_parts.discard(event.index)
1505
1545
  text_parts.discard(event.index)
1546
+ tool_parts.discard(event.index)
1506
1547
  banner_printed.discard(event.index)
1507
1548
 
1508
- # Resume spinner if next part is NOT text/thinking (avoid race condition)
1509
- # If next part is a tool call or None, it's safe to resume
1549
+ # Resume spinner if next part is NOT text/thinking/tool (avoid race condition)
1550
+ # If next part is None or handled differently, it's safe to resume
1510
1551
  # Note: spinner itself handles blank line before appearing
1511
1552
  from code_puppy.messaging.spinner import resume_all_spinners
1512
1553
 
1513
1554
  next_kind = getattr(event, "next_part_kind", None)
1514
- if next_kind not in ("text", "thinking"):
1555
+ if next_kind not in ("text", "thinking", "tool-call"):
1515
1556
  resume_all_spinners()
1516
1557
 
1517
1558
  # Spinner is resumed in PartEndEvent when appropriate (based on next_part_kind)
@@ -1910,73 +1951,32 @@ class BaseAgent(ABC):
1910
1951
  def graceful_sigint_handler(_sig, _frame):
1911
1952
  # When using keyboard-based cancel, SIGINT should be a no-op
1912
1953
  # (just show a hint to user about the configured cancel key)
1913
- from code_puppy.keymap import get_cancel_agent_display_name
1914
1954
  import sys
1915
1955
 
1956
+ from code_puppy.keymap import get_cancel_agent_display_name
1957
+
1916
1958
  cancel_key = get_cancel_agent_display_name()
1917
- if sys.platform == "win32":
1918
- # On Windows, we use keyboard listener, so SIGINT might still fire
1919
- # but we handle cancellation via the key listener
1920
- pass # Silent on Windows - the key listener handles it
1921
- else:
1922
- emit_info(f"Use {cancel_key} to cancel the agent task.")
1959
+ emit_info(f"Use {cancel_key} to cancel the agent task.")
1923
1960
 
1924
1961
  original_handler = None
1925
1962
  key_listener_stop_event = None
1926
1963
  _key_listener_thread = None
1927
- _windows_ctrl_handler = None # Store reference to prevent garbage collection
1928
1964
 
1929
1965
  try:
1930
- if sys.platform == "win32":
1931
- # Windows: Use SetConsoleCtrlHandler for reliable Ctrl+C handling
1932
- import ctypes
1933
-
1934
- # Define the handler function type
1935
- HANDLER_ROUTINE = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_ulong)
1936
-
1937
- def windows_ctrl_handler(ctrl_type):
1938
- """Handle Windows console control events."""
1939
- CTRL_C_EVENT = 0
1940
- CTRL_BREAK_EVENT = 1
1941
-
1942
- if ctrl_type in (CTRL_C_EVENT, CTRL_BREAK_EVENT):
1943
- # Check if we're awaiting user input
1944
- if is_awaiting_user_input():
1945
- return False # Let default handler run
1946
-
1947
- # Schedule agent cancellation
1948
- schedule_agent_cancel()
1949
- return True # We handled it, don't terminate
1950
-
1951
- return False # Let other handlers process it
1952
-
1953
- # Create the callback - must keep reference alive!
1954
- _windows_ctrl_handler = HANDLER_ROUTINE(windows_ctrl_handler)
1955
-
1956
- # Register the handler
1957
- kernel32 = ctypes.windll.kernel32
1958
- if not kernel32.SetConsoleCtrlHandler(_windows_ctrl_handler, True):
1959
- emit_warning("Failed to set Windows Ctrl+C handler")
1960
-
1961
- # Also spawn keyboard listener for Ctrl+X (shell cancel) and other keys
1962
- key_listener_stop_event = threading.Event()
1963
- _key_listener_thread = self._spawn_ctrl_x_key_listener(
1964
- key_listener_stop_event,
1965
- on_escape=lambda: None, # Ctrl+X handled by command_runner
1966
- on_cancel_agent=None, # Ctrl+C handled by SetConsoleCtrlHandler above
1967
- )
1968
- elif cancel_agent_uses_signal():
1969
- # Unix with Ctrl+C: Use SIGINT-based cancellation
1966
+ if cancel_agent_uses_signal():
1967
+ # Use SIGINT-based cancellation (default Ctrl+C behavior)
1970
1968
  original_handler = signal.signal(
1971
1969
  signal.SIGINT, keyboard_interrupt_handler
1972
1970
  )
1973
1971
  else:
1974
- # Unix with different cancel key: Use keyboard listener
1972
+ # Use keyboard listener for agent cancellation
1973
+ # Set a graceful SIGINT handler that shows a hint
1975
1974
  original_handler = signal.signal(signal.SIGINT, graceful_sigint_handler)
1975
+ # Spawn keyboard listener with the cancel agent callback
1976
1976
  key_listener_stop_event = threading.Event()
1977
1977
  _key_listener_thread = self._spawn_ctrl_x_key_listener(
1978
1978
  key_listener_stop_event,
1979
- on_escape=lambda: None,
1979
+ on_escape=lambda: None, # Ctrl+X handled by command_runner
1980
1980
  on_cancel_agent=schedule_agent_cancel,
1981
1981
  )
1982
1982
 
@@ -2001,17 +2001,8 @@ class BaseAgent(ABC):
2001
2001
  # Stop keyboard listener if it was started
2002
2002
  if key_listener_stop_event is not None:
2003
2003
  key_listener_stop_event.set()
2004
-
2005
- # Unregister Windows Ctrl handler
2006
- if sys.platform == "win32" and _windows_ctrl_handler is not None:
2007
- try:
2008
- import ctypes
2009
-
2010
- kernel32 = ctypes.windll.kernel32
2011
- kernel32.SetConsoleCtrlHandler(_windows_ctrl_handler, False)
2012
- except Exception:
2013
- pass # Best effort cleanup
2014
-
2015
- # Restore original signal handler (Unix)
2016
- if original_handler is not None:
2004
+ # Restore original signal handler
2005
+ if (
2006
+ original_handler is not None
2007
+ ): # Explicit None check - SIG_DFL can be 0/falsy!
2017
2008
  signal.signal(signal.SIGINT, original_handler)
code_puppy/cli_runner.py CHANGED
@@ -790,6 +790,5 @@ def main_entry():
790
790
  DBOS.destroy()
791
791
  return 0
792
792
  finally:
793
- # Reset terminal on all platforms for clean state
794
- reset_windows_terminal_full() # Safe no-op on non-Windows
793
+ # Reset terminal on Unix-like systems (not Windows)
795
794
  reset_unix_terminal()
@@ -571,6 +571,7 @@ class AddModelMenu:
571
571
  "cerebras": "cerebras",
572
572
  "cohere": "custom_openai",
573
573
  "perplexity": "custom_openai",
574
+ "minimax": "custom_anthropic",
574
575
  }
575
576
 
576
577
  # Determine the model type
@@ -600,6 +601,16 @@ class AddModelMenu:
600
601
  api_key_env = f"${provider.env[0]}" if provider.env else "$API_KEY"
601
602
  config["custom_endpoint"] = {"url": api_url, "api_key": api_key_env}
602
603
 
604
+ # Special handling for minimax: uses custom_anthropic but needs custom_endpoint
605
+ # and the URL needs /v1 stripped (comes as https://api.minimax.io/anthropic/v1)
606
+ if provider.id == "minimax" and provider.api:
607
+ api_url = provider.api
608
+ # Strip /v1 suffix if present
609
+ if api_url.endswith("/v1"):
610
+ api_url = api_url[:-3]
611
+ api_key_env = f"${provider.env[0]}" if provider.env else "$API_KEY"
612
+ config["custom_endpoint"] = {"url": api_url, "api_key": api_key_env}
613
+
603
614
  # Add context length if available
604
615
  if model.context_length and model.context_length > 0:
605
616
  config["context_length"] = model.context_length
code_puppy/keymap.py CHANGED
@@ -86,15 +86,9 @@ def cancel_agent_uses_signal() -> bool:
86
86
  """Check if the cancel agent key uses SIGINT (Ctrl+C).
87
87
 
88
88
  Returns:
89
- True if the cancel key is ctrl+c AND we're not on Windows
90
- (uses SIGINT handler), False if it uses keyboard listener approach.
89
+ True if the cancel key is ctrl+c (uses SIGINT handler),
90
+ False if it uses keyboard listener approach.
91
91
  """
92
- import sys
93
-
94
- # On Windows, always use keyboard listener - SIGINT is unreliable
95
- if sys.platform == "win32":
96
- return False
97
-
98
92
  return get_cancel_agent_key() == "ctrl+c"
99
93
 
100
94
 
@@ -18,6 +18,9 @@ def _load_builtin_plugins(plugins_dir: Path) -> list[str]:
18
18
 
19
19
  Returns list of successfully loaded plugin names.
20
20
  """
21
+ # Import safety permission check for shell_safety plugin
22
+ from code_puppy.config import get_safety_permission_level
23
+
21
24
  loaded = []
22
25
 
23
26
  for item in plugins_dir.iterdir():
@@ -26,6 +29,15 @@ def _load_builtin_plugins(plugins_dir: Path) -> list[str]:
26
29
  callbacks_file = item / "register_callbacks.py"
27
30
 
28
31
  if callbacks_file.exists():
32
+ # Skip shell_safety plugin unless safety_permission_level is "low" or "none"
33
+ if plugin_name == "shell_safety":
34
+ safety_level = get_safety_permission_level()
35
+ if safety_level not in ("none", "low"):
36
+ logger.debug(
37
+ f"Skipping shell_safety plugin - safety_permission_level is '{safety_level}' (needs 'low' or 'none')"
38
+ )
39
+ continue
40
+
29
41
  try:
30
42
  module_name = f"code_puppy.plugins.{plugin_name}.register_callbacks"
31
43
  importlib.import_module(module_name)
@@ -192,11 +192,6 @@ def kill_all_running_shell_processes() -> int:
192
192
  """Kill all currently tracked running shell processes and stop reader threads.
193
193
 
194
194
  Returns the number of processes signaled.
195
-
196
- Implementation notes:
197
- - Atomically snapshot and clear the registry to prevent race conditions
198
- - Deduplicate by PID to ensure each process is killed at most once
199
- - Let exceptions from _kill_process_group propagate (tests expect this)
200
195
  """
201
196
  global _READER_STOP_EVENT
202
197
 
@@ -204,52 +199,30 @@ def kill_all_running_shell_processes() -> int:
204
199
  if _READER_STOP_EVENT:
205
200
  _READER_STOP_EVENT.set()
206
201
 
207
- # Atomically take snapshot and clear registry
208
- # This prevents other threads from seeing/processing the same processes
202
+ procs: list[subprocess.Popen]
209
203
  with _RUNNING_PROCESSES_LOCK:
210
- procs_snapshot = list(_RUNNING_PROCESSES)
211
- _RUNNING_PROCESSES.clear()
212
-
213
- # Deduplicate by pid to ensure at-most-one kill per process
214
- seen_pids: set = set()
215
- killed_count = 0
216
-
217
- for proc in procs_snapshot:
218
- if proc is None:
219
- continue
220
-
221
- pid = getattr(proc, "pid", None)
222
- key = pid if pid is not None else id(proc)
223
-
224
- if key in seen_pids:
225
- continue
226
- seen_pids.add(key)
227
-
228
- # Close pipes first to unblock readline()
204
+ procs = list(_RUNNING_PROCESSES)
205
+ count = 0
206
+ for p in procs:
229
207
  try:
230
- if proc.stdout and not proc.stdout.closed:
231
- proc.stdout.close()
232
- if proc.stderr and not proc.stderr.closed:
233
- proc.stderr.close()
234
- if proc.stdin and not proc.stdin.closed:
235
- proc.stdin.close()
236
- except (OSError, ValueError):
237
- pass
238
-
239
- # Only attempt to kill processes that are still running
240
- if proc.poll() is None:
241
- # Let exceptions bubble up (tests expect this behavior)
242
- _kill_process_group(proc)
243
- killed_count += 1
244
-
245
- # Track user-killed PIDs
246
- if pid is not None:
247
- try:
248
- _USER_KILLED_PROCESSES.add(pid)
249
- except Exception:
250
- pass # Non-fatal bookkeeping
208
+ # Close pipes first to unblock readline()
209
+ try:
210
+ if p.stdout and not p.stdout.closed:
211
+ p.stdout.close()
212
+ if p.stderr and not p.stderr.closed:
213
+ p.stderr.close()
214
+ if p.stdin and not p.stdin.closed:
215
+ p.stdin.close()
216
+ except (OSError, ValueError):
217
+ pass
251
218
 
252
- return killed_count
219
+ if p.poll() is None:
220
+ _kill_process_group(p)
221
+ count += 1
222
+ _USER_KILLED_PROCESSES.add(p.pid)
223
+ finally:
224
+ _unregister_process(p)
225
+ return count
253
226
 
254
227
 
255
228
  def get_running_shell_process_count() -> int:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.324
3
+ Version: 0.0.326
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -3,12 +3,12 @@ code_puppy/__main__.py,sha256=pDVssJOWP8A83iFkxMLY9YteHYat0EyWDQqMkKHpWp4,203
3
3
  code_puppy/callbacks.py,sha256=hqTV--dNxG5vwWWm3MrEjmb8MZuHFFdmHePl23NXPHk,8621
4
4
  code_puppy/chatgpt_codex_client.py,sha256=Om0ANB_kpHubhCwNzF9ENf8RvKBqs0IYzBLl_SNw0Vk,9833
5
5
  code_puppy/claude_cache_client.py,sha256=hZr_YtXZSQvBoJFtRbbecKucYqJgoMopqUmm0IxFYGY,6071
6
- code_puppy/cli_runner.py,sha256=UIM04pqMb3qkVKG0lKtHQuVSrevsQhEqDC__wAdjqy8,29646
6
+ code_puppy/cli_runner.py,sha256=qAP5cocyUoRVJwvOmlhNsDcoh6h-AXEakDomWxNYlfs,29581
7
7
  code_puppy/config.py,sha256=qqeJrQP7gqADqeYqVzfksP7NYGROLrBQCuYic5PuQfY,52295
8
8
  code_puppy/error_logging.py,sha256=a80OILCUtJhexI6a9GM-r5LqIdjvSRzggfgPp2jv1X0,3297
9
9
  code_puppy/gemini_code_assist.py,sha256=KGS7sO5OLc83nDF3xxS-QiU6vxW9vcm6hmzilu79Ef8,13867
10
10
  code_puppy/http_utils.py,sha256=w5mWYIGIWJZJvgvMahXs9BmdidoJvGn4CASDRY88a8o,13414
11
- code_puppy/keymap.py,sha256=kbC6S_s57rXcONdE2e1xdj2XNRJ4nHJI32RxbI83DC4,3400
11
+ code_puppy/keymap.py,sha256=Uzvq7HB-6inTjKox-90JWzuijztRdWqhJpfTDZVy5no,3235
12
12
  code_puppy/main.py,sha256=82r3vZy_XcyEsenLn82BnUusaoyL3Bpm_Th_jKgqecE,273
13
13
  code_puppy/model_factory.py,sha256=H_a5nX462Q-dhX3g3ZY7dmBCIAUOd1aOSZa4HMxF1o4,34191
14
14
  code_puppy/model_utils.py,sha256=NU8W8NW5F7QS_PXHaLeh55Air1koUV7IVYFP7Rz3XpY,3615
@@ -39,11 +39,11 @@ code_puppy/agents/agent_qa_expert.py,sha256=5Ikb4U3SZQknUEfwlHZiyZXKqnffnOTQagr_
39
39
  code_puppy/agents/agent_qa_kitten.py,sha256=5PeFFSwCFlTUvP6h5bGntx0xv5NmRwBiw0HnMqY8nLI,9107
40
40
  code_puppy/agents/agent_security_auditor.py,sha256=SpiYNA0XAsIwBj7S2_EQPRslRUmF_-b89pIJyW7DYtY,12022
41
41
  code_puppy/agents/agent_typescript_reviewer.py,sha256=vsnpp98xg6cIoFAEJrRTUM_i4wLEWGm5nJxs6fhHobM,10275
42
- code_puppy/agents/base_agent.py,sha256=TP_iXzoKzqg160EwFVCQmaXfbDF-WX_XH4dyxsypwYc,83200
42
+ code_puppy/agents/base_agent.py,sha256=cnfzDbmFlXUpg6bxFXbIs4NdOWM7hiMmied9_W6Sp5k,83040
43
43
  code_puppy/agents/json_agent.py,sha256=lhopDJDoiSGHvD8A6t50hi9ZBoNRKgUywfxd0Po_Dzc,4886
44
44
  code_puppy/agents/prompt_reviewer.py,sha256=JJrJ0m5q0Puxl8vFsyhAbY9ftU9n6c6UxEVdNct1E-Q,5558
45
45
  code_puppy/command_line/__init__.py,sha256=y7WeRemfYppk8KVbCGeAIiTuiOszIURCDjOMZv_YRmU,45
46
- code_puppy/command_line/add_model_menu.py,sha256=ReF8Rel6CitWY_EYwGkLIALgKaqnaSinjz04z0M2RLk,42466
46
+ code_puppy/command_line/add_model_menu.py,sha256=6hefLnlcVJGWdjxEBEmSHrEOWRZWMjUB1es2nHuw19E,43057
47
47
  code_puppy/command_line/attachments.py,sha256=4Q5I2Es4j0ltnz5wjw2z0QXMsiMJvEfWRkPf_lJeITM,13093
48
48
  code_puppy/command_line/autosave_menu.py,sha256=7w2SXfEfR-SGFZcHxM-QZfT0p42KxJjX36UWS66QObc,19987
49
49
  code_puppy/command_line/colors_menu.py,sha256=F_OYuApwXWGP2w9o0CMEbIHtqwdKUh5eDhi7qtDP9h0,17144
@@ -116,7 +116,7 @@ code_puppy/messaging/rich_renderer.py,sha256=Kln4L3Lt-KD0orCav9CBxK0Ggz1u8eV4Hbo
116
116
  code_puppy/messaging/spinner/__init__.py,sha256=KpK5tJqq9YnN3wklqvdH0BQmuwYnT83Mp4tPfQa9RqI,1664
117
117
  code_puppy/messaging/spinner/console_spinner.py,sha256=YIReuWPD01YPy58FqWdMDWj2QhauTUxKo675Ub4-eDA,8451
118
118
  code_puppy/messaging/spinner/spinner_base.py,sha256=JiQDAhCfwrWUFunb8Xcj1caEl34JJY7Bcio7mDeckSc,2694
119
- code_puppy/plugins/__init__.py,sha256=4prVc8Q-QkknyEKyyyyPJ3-GtkBwb1Cx1x-ITNppiNY,6090
119
+ code_puppy/plugins/__init__.py,sha256=gWgrXWoFpl-3Mxz2DAvxKW6SkCWrOnw-hKsY9O7nHcI,6710
120
120
  code_puppy/plugins/oauth_puppy_html.py,sha256=Wpa-V_NlRiBAvo_OXHuR7wvOH_jSt8L9HSFGiab6xI0,13058
121
121
  code_puppy/plugins/chatgpt_oauth/__init__.py,sha256=Kjc6Hsz1sWvMD2OdAlWZvJRiKJSj4fx22boa-aVFKjA,189
122
122
  code_puppy/plugins/chatgpt_oauth/config.py,sha256=H_wAH9Duyn8WH2Kq8oe72uda-_4qu1uXLPun_SDdtsk,2023
@@ -144,7 +144,7 @@ code_puppy/plugins/shell_safety/register_callbacks.py,sha256=W3v664RR48Fdbbbltf_
144
144
  code_puppy/prompts/codex_system_prompt.md,sha256=hEFTCziroLqZmqNle5kG34A8kvTteOWezCiVrAEKhE0,24400
145
145
  code_puppy/tools/__init__.py,sha256=BVTZ85jLHgDANwOnUSOz3UDlp8VQDq4DoGF23BRlyWw,6032
146
146
  code_puppy/tools/agent_tools.py,sha256=snBI6FlFtR03CbYKXwu53R48c_fRSuDIwcNdVUruLcA,21020
147
- code_puppy/tools/command_runner.py,sha256=Sz2AI9CCE3fUcFv-86p1BB5tBkt_UbrPNi57Tfk031E,45281
147
+ code_puppy/tools/command_runner.py,sha256=WLesijwbXEsnyuIJvWZHbVVyoUAPQcTWJbz31pXPSi0,44325
148
148
  code_puppy/tools/common.py,sha256=IboS6sbwN4a3FzHdfsZJtEFiyDUCszevI6LpH14ydEk,40561
149
149
  code_puppy/tools/file_modifications.py,sha256=vz9n7R0AGDSdLUArZr_55yJLkyI30M8zreAppxIx02M,29380
150
150
  code_puppy/tools/file_operations.py,sha256=CqhpuBnOFOcQCIYXOujskxq2VMLWYJhibYrH0YcPSfA,35692
@@ -159,10 +159,10 @@ code_puppy/tools/browser/browser_scripts.py,sha256=sNb8eLEyzhasy5hV4B9OjM8yIVMLV
159
159
  code_puppy/tools/browser/browser_workflows.py,sha256=nitW42vCf0ieTX1gLabozTugNQ8phtoFzZbiAhw1V90,6491
160
160
  code_puppy/tools/browser/camoufox_manager.py,sha256=RZjGOEftE5sI_tsercUyXFSZI2wpStXf-q0PdYh2G3I,8680
161
161
  code_puppy/tools/browser/vqa_agent.py,sha256=DBn9HKloILqJSTSdNZzH_PYWT0B2h9VwmY6akFQI_uU,2913
162
- code_puppy-0.0.324.data/data/code_puppy/models.json,sha256=IPABdOrDw2OZJxa0XGBWSWmBRerV6_pIEmKVLRtUbAk,3105
163
- code_puppy-0.0.324.data/data/code_puppy/models_dev_api.json,sha256=wHjkj-IM_fx1oHki6-GqtOoCrRMR0ScK0f-Iz0UEcy8,548187
164
- code_puppy-0.0.324.dist-info/METADATA,sha256=-ExYXf8pscVAS3uSfNB0PPXgk87LyuPVcaW16HLNQEY,28030
165
- code_puppy-0.0.324.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
166
- code_puppy-0.0.324.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
167
- code_puppy-0.0.324.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
168
- code_puppy-0.0.324.dist-info/RECORD,,
162
+ code_puppy-0.0.326.data/data/code_puppy/models.json,sha256=IPABdOrDw2OZJxa0XGBWSWmBRerV6_pIEmKVLRtUbAk,3105
163
+ code_puppy-0.0.326.data/data/code_puppy/models_dev_api.json,sha256=wHjkj-IM_fx1oHki6-GqtOoCrRMR0ScK0f-Iz0UEcy8,548187
164
+ code_puppy-0.0.326.dist-info/METADATA,sha256=GN-GsY0X1fQgsUUshbY-tRpn5lVdRR4OwBJF5uNHtGc,28030
165
+ code_puppy-0.0.326.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
166
+ code_puppy-0.0.326.dist-info/entry_points.txt,sha256=Tp4eQC99WY3HOKd3sdvb22vZODRq0XkZVNpXOag_KdI,91
167
+ code_puppy-0.0.326.dist-info/licenses/LICENSE,sha256=31u8x0SPgdOq3izJX41kgFazWsM43zPEF9eskzqbJMY,1075
168
+ code_puppy-0.0.326.dist-info/RECORD,,