code-puppy 0.0.159__tar.gz → 0.0.161__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.
- {code_puppy-0.0.159 → code_puppy-0.0.161}/PKG-INFO +1 -1
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/command_runner.py +0 -98
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/file_modifications.py +20 -190
- {code_puppy-0.0.159 → code_puppy-0.0.161}/pyproject.toml +1 -1
- {code_puppy-0.0.159 → code_puppy-0.0.161}/.gitignore +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/LICENSE +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/README.md +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/__main__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agent.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/agent_code_puppy.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/agent_creator_agent.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/agent_manager.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/agent_orchestrator.json +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/base_agent.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/json_agent.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/agents/runtime_manager.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/callbacks.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/command_handler.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/file_path_completion.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/load_context_completion.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/add_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/base.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/handler.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/help_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/install_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/list_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/logs_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/remove_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/restart_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/search_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/start_all_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/start_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/status_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/stop_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/test_command.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/utils.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/meta_command_handler.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/model_picker_completion.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/motd.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/utils.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/config.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/http_utils.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/main.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/async_lifecycle.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/blocking_startup.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/captured_stdio_server.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/circuit_breaker.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/config_wizard.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/dashboard.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/error_isolation.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/examples/retry_example.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/health_monitor.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/managed_server.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/manager.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/registry.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/retry_manager.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/server_registry_catalog.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/status_tracker.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/mcp/system_tools.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/message_history_processor.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/message_queue.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/queue_console.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/renderers.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/spinner/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/spinner/console_spinner.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/spinner/spinner_base.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/messaging/spinner/textual_spinner.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/model_factory.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/models.json +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/plugins/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/reopenable_async_client.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/round_robin_model.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/state_management.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/status_display.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/summarization_agent.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/agent_tools.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/common.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/file_operations.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tools/tools_content.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/app.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/chat_view.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/command_history_modal.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/copy_button.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/custom_widgets.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/human_input_modal.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/input_area.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/sidebar.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/status_bar.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/messages.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/models/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/models/chat_message.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/models/command_history.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/models/enums.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/screens/__init__.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/screens/help.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/screens/mcp_install_wizard.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/screens/settings.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/screens/tools.py +0 -0
- {code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/version_checker.py +0 -0
|
@@ -494,104 +494,6 @@ def share_your_reasoning(
|
|
|
494
494
|
return ReasoningOutput(**{"success": True})
|
|
495
495
|
|
|
496
496
|
|
|
497
|
-
def register_command_runner_tools(agent):
|
|
498
|
-
@agent.tool
|
|
499
|
-
def agent_run_shell_command(
|
|
500
|
-
context: RunContext, command: str = "", cwd: str = None, timeout: int = 60
|
|
501
|
-
) -> ShellCommandOutput:
|
|
502
|
-
"""Execute a shell command with comprehensive monitoring and safety features.
|
|
503
|
-
|
|
504
|
-
This tool provides robust shell command execution with streaming output,
|
|
505
|
-
timeout handling, user confirmation (when not in yolo mode), and proper
|
|
506
|
-
process lifecycle management. Commands are executed in a controlled
|
|
507
|
-
environment with cross-platform process group handling.
|
|
508
|
-
|
|
509
|
-
Args:
|
|
510
|
-
context (RunContext): The PydanticAI runtime context for the agent.
|
|
511
|
-
command (str): The shell command to execute. Cannot be empty or whitespace-only.
|
|
512
|
-
cwd (str, optional): Working directory for command execution. If None,
|
|
513
|
-
uses the current working directory. Defaults to None.
|
|
514
|
-
timeout (int, optional): Inactivity timeout in seconds. If no output is
|
|
515
|
-
produced for this duration, the process will be terminated.
|
|
516
|
-
Defaults to 60 seconds.
|
|
517
|
-
|
|
518
|
-
Returns:
|
|
519
|
-
ShellCommandOutput: A structured response containing:
|
|
520
|
-
- success (bool): True if command executed successfully (exit code 0)
|
|
521
|
-
- command (str | None): The executed command string
|
|
522
|
-
- error (str | None): Error message if execution failed
|
|
523
|
-
- stdout (str | None): Standard output from the command (last 1000 lines)
|
|
524
|
-
- stderr (str | None): Standard error from the command (last 1000 lines)
|
|
525
|
-
- exit_code (int | None): Process exit code
|
|
526
|
-
- execution_time (float | None): Total execution time in seconds
|
|
527
|
-
- timeout (bool | None): True if command was terminated due to timeout
|
|
528
|
-
- user_interrupted (bool | None): True if user killed the process
|
|
529
|
-
|
|
530
|
-
Note:
|
|
531
|
-
- In interactive mode (not yolo), user confirmation is required before execution
|
|
532
|
-
- Commands have an absolute timeout of 270 seconds regardless of activity
|
|
533
|
-
- Process groups are properly managed for clean termination
|
|
534
|
-
- Output is streamed in real-time and displayed to the user
|
|
535
|
-
- Large output is truncated to the last 1000 lines for memory efficiency
|
|
536
|
-
|
|
537
|
-
Examples:
|
|
538
|
-
>>> result = agent_run_shell_command(ctx, "ls -la", cwd="/tmp", timeout=30)
|
|
539
|
-
>>> if result.success:
|
|
540
|
-
... print(f"Command completed in {result.execution_time:.2f}s")
|
|
541
|
-
... print(result.stdout)
|
|
542
|
-
|
|
543
|
-
Warning:
|
|
544
|
-
This tool can execute arbitrary shell commands. Exercise caution when
|
|
545
|
-
running untrusted commands, especially those that modify system state.
|
|
546
|
-
"""
|
|
547
|
-
result = run_shell_command(context, command, cwd, timeout)
|
|
548
|
-
on_run_shell_command(result)
|
|
549
|
-
|
|
550
|
-
@agent.tool
|
|
551
|
-
def agent_share_your_reasoning(
|
|
552
|
-
context: RunContext, reasoning: str = "", next_steps: str | None = None
|
|
553
|
-
) -> ReasoningOutput:
|
|
554
|
-
"""Share the agent's current reasoning and planned next steps with the user.
|
|
555
|
-
|
|
556
|
-
This tool provides transparency into the agent's decision-making process
|
|
557
|
-
by displaying the current reasoning and upcoming actions in a formatted,
|
|
558
|
-
user-friendly manner. It's essential for building trust and understanding
|
|
559
|
-
between the agent and user.
|
|
560
|
-
|
|
561
|
-
Args:
|
|
562
|
-
context (RunContext): The PydanticAI runtime context for the agent.
|
|
563
|
-
reasoning (str): The agent's current thought process, analysis, or
|
|
564
|
-
reasoning for the current situation. This should be clear,
|
|
565
|
-
comprehensive, and explain the 'why' behind decisions.
|
|
566
|
-
next_steps (str | None, optional): Planned upcoming actions or steps
|
|
567
|
-
the agent intends to take. Can be None if no specific next steps
|
|
568
|
-
are determined. Defaults to None.
|
|
569
|
-
|
|
570
|
-
Returns:
|
|
571
|
-
ReasoningOutput: A simple response object containing:
|
|
572
|
-
- success (bool): Always True, indicating the reasoning was shared
|
|
573
|
-
|
|
574
|
-
Note:
|
|
575
|
-
- Reasoning is displayed with Markdown formatting for better readability
|
|
576
|
-
- Next steps are only shown if provided and non-empty
|
|
577
|
-
- Output is visually separated with dividers in TUI mode
|
|
578
|
-
- This tool should be called before major actions to explain intent
|
|
579
|
-
|
|
580
|
-
Examples:
|
|
581
|
-
>>> reasoning = "I need to analyze the codebase structure before making changes"
|
|
582
|
-
>>> next_steps = "First, I'll list the directory contents, then read key files"
|
|
583
|
-
>>> result = agent_share_your_reasoning(ctx, reasoning, next_steps)
|
|
584
|
-
|
|
585
|
-
Best Practice:
|
|
586
|
-
Use this tool frequently to maintain transparency. Call it:
|
|
587
|
-
- Before starting complex operations
|
|
588
|
-
- When changing strategy or approach
|
|
589
|
-
- To explain why certain decisions are being made
|
|
590
|
-
- When encountering unexpected situations
|
|
591
|
-
"""
|
|
592
|
-
return share_your_reasoning(context, reasoning, next_steps)
|
|
593
|
-
|
|
594
|
-
|
|
595
497
|
def register_agent_run_shell_command(agent):
|
|
596
498
|
"""Register only the agent_run_shell_command tool."""
|
|
597
499
|
|
|
@@ -448,168 +448,6 @@ def _delete_file(
|
|
|
448
448
|
return res
|
|
449
449
|
|
|
450
450
|
|
|
451
|
-
def register_file_modifications_tools(agent):
|
|
452
|
-
"""Attach file-editing tools to *agent* with mandatory diff rendering."""
|
|
453
|
-
|
|
454
|
-
@agent.tool(retries=5)
|
|
455
|
-
def edit_file(context: RunContext, payload: EditFilePayload) -> Dict[str, Any]:
|
|
456
|
-
"""Comprehensive file editing tool supporting multiple modification strategies.
|
|
457
|
-
|
|
458
|
-
This is the primary file modification tool that supports three distinct editing
|
|
459
|
-
approaches: full content replacement, targeted text replacements, and snippet
|
|
460
|
-
deletion. It provides robust diff generation, error handling, and automatic
|
|
461
|
-
retry capabilities for reliable file operations.
|
|
462
|
-
|
|
463
|
-
Args:
|
|
464
|
-
context (RunContext): The PydanticAI runtime context for the agent.
|
|
465
|
-
payload (EditFilePayload): One of three payload types:
|
|
466
|
-
|
|
467
|
-
ContentPayload:
|
|
468
|
-
- content (str): Full file content to write
|
|
469
|
-
- overwrite (bool, optional): Whether to overwrite existing files.
|
|
470
|
-
Defaults to False (safe mode).
|
|
471
|
-
|
|
472
|
-
ReplacementsPayload:
|
|
473
|
-
- replacements (List[Replacement]): List of text replacements where
|
|
474
|
-
each Replacement contains:
|
|
475
|
-
- old_str (str): Exact text to find and replace
|
|
476
|
-
- new_str (str): Replacement text
|
|
477
|
-
|
|
478
|
-
DeleteSnippetPayload:
|
|
479
|
-
- delete_snippet (str): Exact text snippet to remove from file
|
|
480
|
-
|
|
481
|
-
file_path (str): Path to the target file. Can be relative or absolute.
|
|
482
|
-
File will be created if it doesn't exist (for ContentPayload).
|
|
483
|
-
|
|
484
|
-
Returns:
|
|
485
|
-
Dict[str, Any]: Operation result containing:
|
|
486
|
-
- success (bool): True if operation completed successfully
|
|
487
|
-
- path (str): Absolute path to the modified file
|
|
488
|
-
- message (str): Human-readable description of what occurred
|
|
489
|
-
- changed (bool): True if file content was actually modified
|
|
490
|
-
- error (str, optional): Error message if operation failed
|
|
491
|
-
|
|
492
|
-
Note:
|
|
493
|
-
- Automatic retry (up to 5 attempts) for transient failures
|
|
494
|
-
- Unified diff is generated and displayed for all operations
|
|
495
|
-
- Fuzzy matching (Jaro-Winkler) used for replacements when exact match fails
|
|
496
|
-
- Minimum similarity threshold of 0.95 for fuzzy replacements
|
|
497
|
-
- Creates parent directories automatically when needed
|
|
498
|
-
- UTF-8 encoding enforced for all file operations
|
|
499
|
-
|
|
500
|
-
Examples:
|
|
501
|
-
>>> # Create new file
|
|
502
|
-
>>> payload = ContentPayload(file_path="foo.py", content="print('Hello World')")
|
|
503
|
-
>>> result = edit_file(context, payload)
|
|
504
|
-
|
|
505
|
-
>>> # Replace specific text
|
|
506
|
-
>>> replacements = [Replacement(old_str="foo", new_str="bar")]
|
|
507
|
-
>>> payload = ReplacementsPayload(file_path="foo.py", replacements=replacements)
|
|
508
|
-
>>> result = edit_file(context, payload)
|
|
509
|
-
|
|
510
|
-
>>> # Delete code block
|
|
511
|
-
>>> payload = DeleteSnippetPayload(file_path="foo.py", delete_snippet="# TODO: remove this")
|
|
512
|
-
>>> result = edit_file(context, payload)
|
|
513
|
-
|
|
514
|
-
Warning:
|
|
515
|
-
- Always verify file contents after modification
|
|
516
|
-
- Use overwrite=False by default to prevent accidental data loss
|
|
517
|
-
- Large files may be slow due to diff generation
|
|
518
|
-
- Exact string matching required for reliable replacements
|
|
519
|
-
|
|
520
|
-
Best Practice:
|
|
521
|
-
- Use ReplacementsPayload for targeted changes to preserve file structure
|
|
522
|
-
- Read file first to understand current content before modifications
|
|
523
|
-
- Keep replacement strings specific and unique to avoid unintended matches
|
|
524
|
-
- Test modifications on non-critical files first
|
|
525
|
-
"""
|
|
526
|
-
# Generate group_id for edit_file tool execution
|
|
527
|
-
if isinstance(payload, str):
|
|
528
|
-
# Fallback for weird models that just can't help but send json strings...
|
|
529
|
-
payload = json.loads(json_repair.repair_json(payload))
|
|
530
|
-
if "replacements" in payload:
|
|
531
|
-
payload = ReplacementsPayload(**payload)
|
|
532
|
-
elif "delete_snippet" in payload:
|
|
533
|
-
payload = DeleteSnippetPayload(**payload)
|
|
534
|
-
elif "content" in payload:
|
|
535
|
-
payload = ContentPayload(**payload)
|
|
536
|
-
else:
|
|
537
|
-
file_path = "Unknown"
|
|
538
|
-
if "file_path" in payload:
|
|
539
|
-
file_path = payload["file_path"]
|
|
540
|
-
return {
|
|
541
|
-
"success": False,
|
|
542
|
-
"path": file_path,
|
|
543
|
-
"message": "One of 'content', 'replacements', or 'delete_snippet' must be provided in payload.",
|
|
544
|
-
"changed": False,
|
|
545
|
-
}
|
|
546
|
-
group_id = generate_group_id("edit_file", payload.file_path)
|
|
547
|
-
result = _edit_file(context, payload, group_id)
|
|
548
|
-
on_edit_file(result)
|
|
549
|
-
if "diff" in result:
|
|
550
|
-
del result["diff"]
|
|
551
|
-
return result
|
|
552
|
-
|
|
553
|
-
@agent.tool(retries=5)
|
|
554
|
-
def delete_file(context: RunContext, file_path: str) -> Dict[str, Any]:
|
|
555
|
-
"""Safely delete files with comprehensive logging and diff generation.
|
|
556
|
-
|
|
557
|
-
This tool provides safe file deletion with automatic diff generation to show
|
|
558
|
-
exactly what content was removed. It includes proper error handling and
|
|
559
|
-
automatic retry capabilities for reliable operation.
|
|
560
|
-
|
|
561
|
-
Args:
|
|
562
|
-
context (RunContext): The PydanticAI runtime context for the agent.
|
|
563
|
-
file_path (str): Path to the file to delete. Can be relative or absolute.
|
|
564
|
-
Must be an existing regular file (not a directory).
|
|
565
|
-
|
|
566
|
-
Returns:
|
|
567
|
-
Dict[str, Any]: Operation result containing:
|
|
568
|
-
- success (bool): True if file was successfully deleted
|
|
569
|
-
- path (str): Absolute path to the deleted file
|
|
570
|
-
- message (str): Human-readable description of the operation
|
|
571
|
-
- changed (bool): True if file was actually removed
|
|
572
|
-
- error (str, optional): Error message if deletion failed
|
|
573
|
-
|
|
574
|
-
Note:
|
|
575
|
-
- Automatic retry (up to 5 attempts) for transient failures
|
|
576
|
-
- Complete file content is captured and shown in diff before deletion
|
|
577
|
-
- Only deletes regular files, not directories or special files
|
|
578
|
-
- Generates unified diff showing all removed content
|
|
579
|
-
- Error if file doesn't exist or is not accessible
|
|
580
|
-
|
|
581
|
-
Examples:
|
|
582
|
-
>>> # Delete temporary file
|
|
583
|
-
>>> result = delete_file(ctx, "temp_output.txt")
|
|
584
|
-
>>> if result['success']:
|
|
585
|
-
... print(f"Successfully deleted {result['path']}")
|
|
586
|
-
|
|
587
|
-
>>> # Delete with error handling
|
|
588
|
-
>>> result = delete_file(ctx, "config.bak")
|
|
589
|
-
>>> if 'error' in result:
|
|
590
|
-
... print(f"Deletion failed: {result['error']}")
|
|
591
|
-
|
|
592
|
-
Warning:
|
|
593
|
-
- File deletion is irreversible - ensure you have backups if needed
|
|
594
|
-
- Will not delete directories (use appropriate directory removal tools)
|
|
595
|
-
- No "trash" or "recycle bin" - files are permanently removed
|
|
596
|
-
- Check file importance before deletion
|
|
597
|
-
|
|
598
|
-
Best Practice:
|
|
599
|
-
- Always verify file path before deletion
|
|
600
|
-
- Review the generated diff to confirm deletion scope
|
|
601
|
-
- Consider moving files to backup location instead of deleting
|
|
602
|
-
- Use in combination with list_files to verify target
|
|
603
|
-
"""
|
|
604
|
-
# Generate group_id for delete_file tool execution
|
|
605
|
-
group_id = generate_group_id("delete_file", file_path)
|
|
606
|
-
result = _delete_file(context, file_path, message_group=group_id)
|
|
607
|
-
on_delete_file(result)
|
|
608
|
-
if "diff" in result:
|
|
609
|
-
del result["diff"]
|
|
610
|
-
return result
|
|
611
|
-
|
|
612
|
-
|
|
613
451
|
def register_edit_file(agent):
|
|
614
452
|
"""Register only the edit_file tool."""
|
|
615
453
|
|
|
@@ -682,39 +520,31 @@ def register_edit_file(agent):
|
|
|
682
520
|
"""
|
|
683
521
|
# Handle string payload parsing (for models that send JSON strings)
|
|
684
522
|
if isinstance(payload, str):
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
payload = DeleteSnippetPayload(**payload)
|
|
691
|
-
elif "content" in payload and "file_path" in payload:
|
|
692
|
-
payload = ContentPayload(**payload)
|
|
693
|
-
else:
|
|
694
|
-
file_path = "Unknown"
|
|
695
|
-
if "file_path" in payload:
|
|
696
|
-
file_path = payload["file_path"]
|
|
697
|
-
# Diagnose what's missing
|
|
698
|
-
missing = []
|
|
699
|
-
if "file_path" not in payload:
|
|
700
|
-
missing.append("file_path")
|
|
701
|
-
|
|
702
|
-
payload_type = "unknown"
|
|
703
|
-
if "content" in payload:
|
|
704
|
-
payload_type = "content"
|
|
705
|
-
elif "replacements" in payload:
|
|
706
|
-
payload_type = "replacements"
|
|
523
|
+
try:
|
|
524
|
+
# Fallback for weird models that just can't help but send json strings...
|
|
525
|
+
payload = json.loads(json_repair.repair_json(payload))
|
|
526
|
+
if "replacements" in payload:
|
|
527
|
+
payload = ReplacementsPayload(**payload)
|
|
707
528
|
elif "delete_snippet" in payload:
|
|
708
|
-
|
|
529
|
+
payload = DeleteSnippetPayload(**payload)
|
|
530
|
+
elif "content" in payload:
|
|
531
|
+
payload = ContentPayload(**payload)
|
|
709
532
|
else:
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
533
|
+
file_path = "Unknown"
|
|
534
|
+
if "file_path" in payload:
|
|
535
|
+
file_path = payload["file_path"]
|
|
536
|
+
return {
|
|
537
|
+
"success": False,
|
|
538
|
+
"path": file_path,
|
|
539
|
+
"message": "One of 'content', 'replacements', or 'delete_snippet' must be provided in payload.",
|
|
540
|
+
"changed": False,
|
|
541
|
+
}
|
|
542
|
+
except Exception as e:
|
|
713
543
|
return {
|
|
714
544
|
"success": False,
|
|
715
545
|
"path": file_path,
|
|
716
|
-
"message": f"
|
|
717
|
-
"changed": False
|
|
546
|
+
"message": f"edit_file call failed: {str(e)}",
|
|
547
|
+
"changed": False
|
|
718
548
|
}
|
|
719
549
|
|
|
720
550
|
# Call _edit_file which will extract file_path from payload and handle group_id generation
|
|
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
|
{code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/load_context_completion.py
RENAMED
|
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
|
{code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/model_picker_completion.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/command_line/prompt_toolkit_completion.py
RENAMED
|
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
|
|
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
|
{code_puppy-0.0.159 → code_puppy-0.0.161}/code_puppy/tui/components/command_history_modal.py
RENAMED
|
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
|