voidx 3.1.1__tar.gz → 3.1.2__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.
- {voidx-3.1.1 → voidx-3.1.2}/PKG-INFO +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/pyproject.toml +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/__init__.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/core/llm.py +1 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/runtime_guards.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/streaming.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/tool_exchange_sanitizer.py +23 -13
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/diffing.py +96 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/compaction.py +5 -3
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/engine.py +2 -2
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/evaluate.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/rules.py +4 -4
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/bash_router.py +11 -11
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/file_ops/__init__.py +4 -4
- voidx-3.1.2/src/voidx/tools/file_ops/edit_execute.py +279 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/file_ops/edit_resolve.py +0 -96
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/file_ops/file.py +2 -2
- voidx-3.1.2/src/voidx/tools/file_ops/types.py +35 -0
- voidx-3.1.2/src/voidx/tools/file_ops/write.py +140 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/registry.py +2 -2
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/console/app.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/console/formatting.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/display_policy.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/__init__.py +7 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/app.py +6 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/nodes.py +2 -2
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/nodes_status.py +2 -2
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/status.py +11 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/events/consumers.py +7 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/session.py +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/render_activity.py +4 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/nodes.py +7 -7
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx.egg-info/PKG-INFO +1 -1
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx.egg-info/SOURCES.txt +0 -1
- voidx-3.1.1/src/voidx/tools/file_ops/edit_execute.py +0 -559
- voidx-3.1.1/src/voidx/tools/file_ops/line.py +0 -150
- voidx-3.1.1/src/voidx/tools/file_ops/types.py +0 -79
- voidx-3.1.1/src/voidx/tools/file_ops/write.py +0 -89
- {voidx-3.1.1 → voidx-3.1.2}/README.md +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/setup.cfg +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/agents.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/attachments.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/goal_resolver.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/compaction.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/compaction_coordinator.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/contracts.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/convergence.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/core/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/core/_voidx_graph.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/core/helpers.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/permissions.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/run_loop.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/runtime.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/session_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/session_runtime.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/subagent.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/title_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/todo_events.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_execution.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/executor.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/guards.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/helpers.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/types.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/ui.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/tool_executor/workflow.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/topology.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/transcript_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/turn_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/turn_runner.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/wiring.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/graph/workflow_utils.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/message_rows.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/prompts.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/runtime_context.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/code_ide.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/guide.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/handler.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/host.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/init.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/lsp.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/mcp.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/model.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/profile.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/runtime.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/session.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/skills.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/slash/upgrade.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/task_state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/todo_state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/tool_call_ids.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/tool_filters.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/tool_messages.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/agent/tool_result_storage.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/enums.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/models.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/permissions.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_agent.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_api_keys.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_code_ide.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_custom.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_mcp.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_permissions.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_skills.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_update.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_utils.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/config/settings_web.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/data/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/data/templates/api-doc.md +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/data/templates/prd.md +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/data/templates/readme.md +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/data/templates/rfc.md +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/data/templates/tech-design.md +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/catalog.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/context.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/instruction.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/message_markers.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/message_status.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/provider.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/llm/usage.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/logging/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/logging/request_log.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/logging/tool_log.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/client.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/config.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/detector.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/detector_data.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/errors.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/manager.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/lsp/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/main.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/client/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/client/base.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/client/errors.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/client/http_transport.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/client/sse_transport.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/client/stdio_transport.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/manager.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp/tool.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp_servers/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/mcp_servers/web.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/cleanup.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/context_frames.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/jsonl_store.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/model_profiles.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/runtime_state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/session.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/store.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/subagents.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/memory/transcript.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/context.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/sandbox.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/permission/wildcard.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/attachments.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/intent.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/reference_tokens.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/task_state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/todo.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/ui.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/runtime/ui_port.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/selfupdate.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/skills/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/skills/context.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/skills/references.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/skills/registry.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/skills/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/skills/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/agent.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/base.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/bash.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/clarify.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/compact_context.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/file_ops/read.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/file_state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/git.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/load_doc_template.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/load_skills.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/lsp.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/plan_checkpoint.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/repomap.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/search.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/task_status.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/task_tracker.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/todo.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/web_content.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/web_mcp.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/webfetch.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/websearch.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/tools/workflow.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/commands.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/frontend.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/gateway/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/gateway/bootstrap.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/gateway/server.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/gateway/session.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/agent_display.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/browse.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/capture.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/console/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/console/streaming.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/diff.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/agent_placeholder.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/formatting.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/nodes_permission.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/nodes_startup.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/stream.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/dock/todo.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/events/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/events/bus.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/events/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/tree.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/output/types.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/protocol/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/protocol/commands.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/protocol/envelope.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/protocol/requests.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/protocol/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/protocol/transcript.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/attachment_tokens.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/clipboard_image.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/clipboard_text.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/code_ide.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/file_picker.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tools/skill_picker.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/transcript.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/activity.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/app.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/choice_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/clipboard_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/helpers.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/input.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/overlays.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/panels.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/parser.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/render_frame.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/render_input.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/render_status.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/render_todo.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/renderer.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/state.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/terminal_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/ui/tui/text_prompt_mixin.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/__init__.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/auto_advance.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/context.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/dag.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/policy.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/reconcile.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/render.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/route.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/runtime.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/schema.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/service.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx/workflow/types.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx.egg-info/dependency_links.txt +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx.egg-info/entry_points.txt +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx.egg-info/requires.txt +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/src/voidx.egg-info/top_level.txt +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/tests/test_install_sh.py +0 -0
- {voidx-3.1.1 → voidx-3.1.2}/tests/test_npm_package.py +0 -0
|
@@ -284,7 +284,7 @@ def tool_call_key(tool_call: dict[str, Any]) -> str:
|
|
|
284
284
|
|
|
285
285
|
|
|
286
286
|
def normalize_tool_args(tool_name: str, args: dict[str, Any]) -> str:
|
|
287
|
-
if tool_name in {"read", "file", "
|
|
287
|
+
if tool_name in {"read", "file", "write", "replace", "lsp_format"}:
|
|
288
288
|
return str(args.get("file_path") or "")
|
|
289
289
|
if tool_name == "lsp":
|
|
290
290
|
return stable_json({
|
|
@@ -138,7 +138,7 @@ def _sanitize_messages_for_replay(messages: list, *, protocol: str = "") -> list
|
|
|
138
138
|
sanitized,
|
|
139
139
|
preserve_latest_tool_exchange=True,
|
|
140
140
|
)
|
|
141
|
-
sanitized = sanitize_failed_tool_exchanges(sanitized, preserve_latest=True)
|
|
141
|
+
sanitized = sanitize_failed_tool_exchanges(sanitized, preserve_latest=True, preserve_rounds=2)
|
|
142
142
|
return _repair_tool_result_adjacency(sanitized)
|
|
143
143
|
|
|
144
144
|
|
|
@@ -14,10 +14,11 @@ def sanitize_failed_tool_exchanges(
|
|
|
14
14
|
messages: list[BaseMessage],
|
|
15
15
|
*,
|
|
16
16
|
preserve_latest: bool = False,
|
|
17
|
+
preserve_rounds: int = 1,
|
|
17
18
|
) -> list[BaseMessage]:
|
|
18
19
|
failed_ids = _failed_tool_call_ids(messages)
|
|
19
20
|
if preserve_latest:
|
|
20
|
-
failed_ids.difference_update(_latest_failed_tool_exchange_ids(messages))
|
|
21
|
+
failed_ids.difference_update(_latest_failed_tool_exchange_ids(messages, rounds=preserve_rounds))
|
|
21
22
|
if not failed_ids:
|
|
22
23
|
return messages
|
|
23
24
|
|
|
@@ -52,21 +53,30 @@ def _failed_tool_call_ids(messages: list[BaseMessage]) -> set[str]:
|
|
|
52
53
|
return failed
|
|
53
54
|
|
|
54
55
|
|
|
55
|
-
def _latest_failed_tool_exchange_ids(messages: list[BaseMessage]) -> set[str]:
|
|
56
|
-
|
|
56
|
+
def _latest_failed_tool_exchange_ids(messages: list[BaseMessage], *, rounds: int = 1) -> set[str]:
|
|
57
|
+
preserved: set[str] = set()
|
|
57
58
|
index = len(messages) - 1
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
index
|
|
59
|
+
rounds_found = 0
|
|
60
|
+
|
|
61
|
+
while index >= 0 and rounds_found < rounds:
|
|
62
|
+
# Collect trailing ToolMessages at current position
|
|
63
|
+
round_failed: set[str] = set()
|
|
64
|
+
while index >= 0 and isinstance(messages[index], ToolMessage):
|
|
65
|
+
message = messages[index]
|
|
66
|
+
tool_call_id = str(getattr(message, "tool_call_id", "") or "")
|
|
67
|
+
if tool_call_id and message_status(getattr(message, "status", None)) == "error":
|
|
68
|
+
round_failed.add(tool_call_id)
|
|
69
|
+
index -= 1
|
|
70
|
+
|
|
71
|
+
if not round_failed or index < 0 or not isinstance(messages[index], AIMessage):
|
|
72
|
+
break
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
ai_ids = set(ai_tool_call_ids(messages[index]))
|
|
75
|
+
preserved.update(round_failed.intersection(ai_ids))
|
|
76
|
+
rounds_found += 1
|
|
77
|
+
index -= 1
|
|
67
78
|
|
|
68
|
-
|
|
69
|
-
return trailing_failed_ids.intersection(ai_ids)
|
|
79
|
+
return preserved
|
|
70
80
|
|
|
71
81
|
|
|
72
82
|
def _sanitize_ai_failed_calls(message: AIMessage, failed_ids: set[str]) -> AIMessage | None:
|
|
@@ -159,6 +159,102 @@ def make_file_diff(
|
|
|
159
159
|
return "".join(diff)
|
|
160
160
|
|
|
161
161
|
|
|
162
|
+
def make_structured_diff(
|
|
163
|
+
filepath: str,
|
|
164
|
+
old_content: str,
|
|
165
|
+
new_content: str,
|
|
166
|
+
) -> FileDiff:
|
|
167
|
+
"""Generate a structured FileDiff directly, without a text round-trip.
|
|
168
|
+
|
|
169
|
+
Uses SequenceMatcher.get_grouped_opcodes(n=3) to match unified_diff's
|
|
170
|
+
hunk-grouping behavior. Handles the old_start=0 / new_start=0 convention
|
|
171
|
+
for pure-insert / pure-delete hunks.
|
|
172
|
+
"""
|
|
173
|
+
old = old_content.splitlines(keepends=True)
|
|
174
|
+
new = new_content.splitlines(keepends=True)
|
|
175
|
+
sm = difflib.SequenceMatcher(a=old, b=new, autojunk=False)
|
|
176
|
+
|
|
177
|
+
file_diff = FileDiff(
|
|
178
|
+
old_path=f"a/{filepath}",
|
|
179
|
+
new_path=f"b/{filepath}",
|
|
180
|
+
path=filepath,
|
|
181
|
+
operation="Update",
|
|
182
|
+
)
|
|
183
|
+
if not old and not new:
|
|
184
|
+
return file_diff
|
|
185
|
+
if not old:
|
|
186
|
+
file_diff.operation = "Create"
|
|
187
|
+
elif not new:
|
|
188
|
+
file_diff.operation = "Delete"
|
|
189
|
+
|
|
190
|
+
for group in sm.get_grouped_opcodes(n=3):
|
|
191
|
+
first_tag, first_i1, first_i2, first_j1, first_j2 = group[0]
|
|
192
|
+
last_tag, last_i1, last_i2, last_j1, last_j2 = group[-1]
|
|
193
|
+
|
|
194
|
+
old_count = last_i2 - first_i1
|
|
195
|
+
new_count = last_j2 - first_j1
|
|
196
|
+
old_start = 0 if old_count == 0 else first_i1 + 1
|
|
197
|
+
new_start = 0 if new_count == 0 else first_j1 + 1
|
|
198
|
+
|
|
199
|
+
hunk = DiffHunk(
|
|
200
|
+
old_start=old_start,
|
|
201
|
+
old_count=old_count,
|
|
202
|
+
new_start=new_start,
|
|
203
|
+
new_count=new_count,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
old_lineno = old_start
|
|
207
|
+
new_lineno = new_start
|
|
208
|
+
for tag, i1, i2, j1, j2 in group:
|
|
209
|
+
if tag == "equal":
|
|
210
|
+
for k in range(i2 - i1):
|
|
211
|
+
hunk.lines.append(DiffLine(
|
|
212
|
+
kind="context",
|
|
213
|
+
old_lineno=old_lineno,
|
|
214
|
+
new_lineno=new_lineno,
|
|
215
|
+
text=old[i1 + k].rstrip("\n"),
|
|
216
|
+
))
|
|
217
|
+
old_lineno += 1
|
|
218
|
+
new_lineno += 1
|
|
219
|
+
elif tag == "replace":
|
|
220
|
+
for k in range(i2 - i1):
|
|
221
|
+
hunk.lines.append(DiffLine(
|
|
222
|
+
kind="remove",
|
|
223
|
+
old_lineno=old_lineno,
|
|
224
|
+
text=old[i1 + k].rstrip("\n"),
|
|
225
|
+
))
|
|
226
|
+
old_lineno += 1
|
|
227
|
+
for k in range(j2 - j1):
|
|
228
|
+
hunk.lines.append(DiffLine(
|
|
229
|
+
kind="add",
|
|
230
|
+
new_lineno=new_lineno,
|
|
231
|
+
text=new[j1 + k].rstrip("\n"),
|
|
232
|
+
))
|
|
233
|
+
new_lineno += 1
|
|
234
|
+
elif tag == "delete":
|
|
235
|
+
for k in range(i2 - i1):
|
|
236
|
+
hunk.lines.append(DiffLine(
|
|
237
|
+
kind="remove",
|
|
238
|
+
old_lineno=old_lineno,
|
|
239
|
+
text=old[i1 + k].rstrip("\n"),
|
|
240
|
+
))
|
|
241
|
+
old_lineno += 1
|
|
242
|
+
elif tag == "insert":
|
|
243
|
+
for k in range(j2 - j1):
|
|
244
|
+
hunk.lines.append(DiffLine(
|
|
245
|
+
kind="add",
|
|
246
|
+
new_lineno=new_lineno,
|
|
247
|
+
text=new[j1 + k].rstrip("\n"),
|
|
248
|
+
))
|
|
249
|
+
new_lineno += 1
|
|
250
|
+
|
|
251
|
+
file_diff.hunks.append(hunk)
|
|
252
|
+
file_diff.added += sum(1 for line in hunk.lines if line.kind == "add")
|
|
253
|
+
file_diff.removed += sum(1 for line in hunk.lines if line.kind == "remove")
|
|
254
|
+
|
|
255
|
+
return file_diff
|
|
256
|
+
|
|
257
|
+
|
|
162
258
|
def diff_stat(diff_text: str) -> tuple[int, int]:
|
|
163
259
|
"""Return (added, removed) line counts from a unified diff."""
|
|
164
260
|
added = 0
|
|
@@ -150,7 +150,7 @@ def _prune_ai_tool_call_args(
|
|
|
150
150
|
saved_chars += len(args["new_string"]) - len(placeholder)
|
|
151
151
|
args["new_string"] = placeholder
|
|
152
152
|
changed = True
|
|
153
|
-
elif name == "
|
|
153
|
+
elif name == "write" and args.get("op") in ("insert", "append") and "new_string" in args:
|
|
154
154
|
placeholder = PRUNE_ARGS_PLACEHOLDER_DIFF
|
|
155
155
|
if len(args["new_string"]) > len(placeholder) and _tool_result_has_diff(messages, ai_msg_index, tc_id):
|
|
156
156
|
saved_chars += len(args["new_string"]) - len(placeholder)
|
|
@@ -267,8 +267,6 @@ class CompactionService:
|
|
|
267
267
|
# Count turns by user messages
|
|
268
268
|
if isinstance(msg, HumanMessage):
|
|
269
269
|
turns_seen += 1
|
|
270
|
-
if turns_seen > 2:
|
|
271
|
-
continue
|
|
272
270
|
|
|
273
271
|
if isinstance(msg, AIMessage) and hasattr(msg, "summary") and msg.summary:
|
|
274
272
|
break # stop at compaction boundary
|
|
@@ -301,6 +299,10 @@ class CompactionService:
|
|
|
301
299
|
if accumulated <= PRUNE_PROTECT:
|
|
302
300
|
continue
|
|
303
301
|
|
|
302
|
+
# Protect most recent 2 turns from ToolMessage truncation
|
|
303
|
+
if turns_seen < 2:
|
|
304
|
+
continue
|
|
305
|
+
|
|
304
306
|
if len(content) > TOOL_OUTPUT_MAX_CHARS:
|
|
305
307
|
truncated = content[:TOOL_OUTPUT_MAX_CHARS] + (
|
|
306
308
|
f"\n\n[Tool output truncated for context: omitted {len(content) - TOOL_OUTPUT_MAX_CHARS} chars]"
|
|
@@ -119,7 +119,7 @@ def strategy_action_for_tool(classified: ClassifiedToolCall, context: Permission
|
|
|
119
119
|
return "allow"
|
|
120
120
|
if classified.capability in {PermissionCapability.BASH_READ, PermissionCapability.GIT_READ}:
|
|
121
121
|
return "allow"
|
|
122
|
-
permission = "edit" if classified.name in {"file", "
|
|
122
|
+
permission = "edit" if classified.name in {"file", "write", "replace"} else classified.name
|
|
123
123
|
return evaluate(permission, classified.pattern, BASIC_RULES).action
|
|
124
124
|
|
|
125
125
|
|
|
@@ -148,7 +148,7 @@ def resolve_approval(classified: ClassifiedToolCall, context: PermissionContext)
|
|
|
148
148
|
|
|
149
149
|
|
|
150
150
|
def _session_rule_matches(tool: str, rule: str) -> bool:
|
|
151
|
-
if rule == "edit" and tool in {"file", "
|
|
151
|
+
if rule == "edit" and tool in {"file", "write", "replace"}:
|
|
152
152
|
return True
|
|
153
153
|
if wildcard_match(tool, rule):
|
|
154
154
|
return True
|
|
@@ -83,7 +83,7 @@ def merge(*rulesets: Ruleset) -> Ruleset:
|
|
|
83
83
|
|
|
84
84
|
def disabled_tools(all_tools: list[str], ruleset: Ruleset) -> set[str]:
|
|
85
85
|
"""Find which tools are completely disabled (denied with pattern="*")."""
|
|
86
|
-
EDIT_TOOLS = {"file", "
|
|
86
|
+
EDIT_TOOLS = {"file", "write", "replace"}
|
|
87
87
|
disabled: set[str] = set()
|
|
88
88
|
for tool in all_tools:
|
|
89
89
|
permission = "edit" if tool in EDIT_TOOLS else tool
|
|
@@ -89,7 +89,7 @@ def tool_call_from_pattern(tool: str, pattern: str = "*") -> dict:
|
|
|
89
89
|
|
|
90
90
|
def repair_tool_name(tool: str) -> str:
|
|
91
91
|
tool_map = {
|
|
92
|
-
"Read": "read", "Write": "file", "Edit": "replace", "Delete": "
|
|
92
|
+
"Read": "read", "Write": "file", "Edit": "replace", "Delete": "replace",
|
|
93
93
|
"MultiEdit": "replace", "multiEdit": "replace", "multi_edit": "replace",
|
|
94
94
|
"Glob": "glob", "Grep": "grep", "Bash": "bash",
|
|
95
95
|
"Agent": "agent", "TodoWrite": "todo", "Todo": "todo",
|
|
@@ -102,7 +102,7 @@ def repair_tool_name(tool: str) -> str:
|
|
|
102
102
|
"LspDiagnostics": "lsp", "LspSymbols": "lsp",
|
|
103
103
|
"LspDefinition": "lsp", "LspReferences": "lsp",
|
|
104
104
|
"CompactContext": "compact",
|
|
105
|
-
"
|
|
105
|
+
"edit": "replace", "insert": "write", "append": "write", "delete": "replace", "line": "write",
|
|
106
106
|
}
|
|
107
107
|
return tool_map.get(tool, tool_map.get(tool.lower(), tool))
|
|
108
108
|
|
|
@@ -357,7 +357,7 @@ def capability_for_tool(tool: str, args: dict) -> PermissionCapability:
|
|
|
357
357
|
"repo_map", "lsp",
|
|
358
358
|
}:
|
|
359
359
|
return PermissionCapability.READ_TOOLS
|
|
360
|
-
if tool in {"file", "
|
|
360
|
+
if tool in {"file", "write", "replace"}:
|
|
361
361
|
return PermissionCapability.FILE_WRITE
|
|
362
362
|
if tool == "bash":
|
|
363
363
|
return PermissionCapability.BASH_READ if is_safe_bash(str(args.get("command", ""))) else PermissionCapability.BASH_WRITE
|
|
@@ -372,7 +372,7 @@ def capability_for_tool(tool: str, args: dict) -> PermissionCapability:
|
|
|
372
372
|
|
|
373
373
|
|
|
374
374
|
_FILE_PATTERN_TOOLS = {
|
|
375
|
-
"read", "file", "
|
|
375
|
+
"read", "file", "write", "replace",
|
|
376
376
|
"lsp",
|
|
377
377
|
}
|
|
378
378
|
|
|
@@ -7,7 +7,7 @@ import shlex
|
|
|
7
7
|
from dataclasses import dataclass
|
|
8
8
|
from typing import Literal
|
|
9
9
|
|
|
10
|
-
_HintableTool = Literal["read", "git", "file", "
|
|
10
|
+
_HintableTool = Literal["read", "git", "file", "write", "replace", "glob", "grep"]
|
|
11
11
|
|
|
12
12
|
_HEREDOC_MAX_CONTENT = 200
|
|
13
13
|
|
|
@@ -835,12 +835,12 @@ def _hint_write_echo(stripped: str, words: list[str]) -> RouteHint | None:
|
|
|
835
835
|
|
|
836
836
|
if is_append:
|
|
837
837
|
return RouteHint(
|
|
838
|
-
tool_id="
|
|
839
|
-
llm_hint=f'Prefer
|
|
838
|
+
tool_id="write", ui_label="→ write",
|
|
839
|
+
llm_hint=f'Prefer write(file_path="{path}", op="append", new_string="{content}") for file tracking and diff output.',
|
|
840
840
|
)
|
|
841
841
|
return RouteHint(
|
|
842
842
|
tool_id="file", ui_label="→ file",
|
|
843
|
-
llm_hint=f'Prefer file(file_path="{path}", op="create") then line(file_path="{path}", op="
|
|
843
|
+
llm_hint=f'Prefer file(file_path="{path}", op="create") then line(file_path="{path}", op="append", new_string="{content}") for file tracking and diff output.',
|
|
844
844
|
)
|
|
845
845
|
|
|
846
846
|
|
|
@@ -887,12 +887,12 @@ def _hint_write_heredoc(stripped: str) -> RouteHint | None:
|
|
|
887
887
|
|
|
888
888
|
if is_append:
|
|
889
889
|
return RouteHint(
|
|
890
|
-
tool_id="
|
|
891
|
-
llm_hint=f'Prefer
|
|
890
|
+
tool_id="write", ui_label="→ write",
|
|
891
|
+
llm_hint=f'Prefer write(file_path="{path}", op="append", new_string="{content}") for file tracking and diff output.',
|
|
892
892
|
)
|
|
893
893
|
return RouteHint(
|
|
894
894
|
tool_id="file", ui_label="→ file",
|
|
895
|
-
llm_hint=f'Prefer file(file_path="{path}", op="create") then line(file_path="{path}", op="
|
|
895
|
+
llm_hint=f'Prefer file(file_path="{path}", op="create") then line(file_path="{path}", op="append", new_string="{content}") for file tracking and diff output.',
|
|
896
896
|
)
|
|
897
897
|
|
|
898
898
|
|
|
@@ -1199,8 +1199,8 @@ def _hint_sed(words: list[str]) -> RouteHint | None:
|
|
|
1199
1199
|
if m:
|
|
1200
1200
|
start, end = int(m.group(1)), int(m.group(2))
|
|
1201
1201
|
return RouteHint(
|
|
1202
|
-
tool_id="
|
|
1203
|
-
llm_hint=f'For line range deletion: first read {path} to see lines {start}-{end}, then use
|
|
1202
|
+
tool_id="replace", ui_label="→ replace",
|
|
1203
|
+
llm_hint=f'For line range deletion: first read {path} to see lines {start}-{end}, then use replace(file_path="{path}", start_no={start}, end_no={end}, prefix="...", suffix="...", new_string="").',
|
|
1204
1204
|
)
|
|
1205
1205
|
|
|
1206
1206
|
|
|
@@ -1208,8 +1208,8 @@ def _hint_sed(words: list[str]) -> RouteHint | None:
|
|
|
1208
1208
|
if m:
|
|
1209
1209
|
line_no = int(m.group(1))
|
|
1210
1210
|
return RouteHint(
|
|
1211
|
-
tool_id="
|
|
1212
|
-
llm_hint=f'For single line deletion: first read {path} to see line {line_no}, then use
|
|
1211
|
+
tool_id="replace", ui_label="→ replace",
|
|
1212
|
+
llm_hint=f'For single line deletion: first read {path} to see line {line_no}, then use replace(file_path="{path}", start_no={line_no}, end_no={line_no}, prefix="...", suffix="...", new_string="").',
|
|
1213
1213
|
)
|
|
1214
1214
|
m = _SED_PATTERN_DELETE.match(script)
|
|
1215
1215
|
if m:
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
"""File operation tools — read, file,
|
|
1
|
+
"""File operation tools — read, file, write, replace. Deterministic, typed I/O."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from .edit_execute import FileReplaceInput, FileReplaceTool
|
|
6
6
|
from .file import FileInput, FileTool
|
|
7
|
-
from .
|
|
7
|
+
from .write import WriteInput, WriteTool
|
|
8
8
|
from .read import FileReadInput, FileReadTool
|
|
9
9
|
|
|
10
10
|
__all__ = [
|
|
11
11
|
"FileTool",
|
|
12
12
|
"FileInput",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
13
|
+
"WriteTool",
|
|
14
|
+
"WriteInput",
|
|
15
15
|
"FileReadTool",
|
|
16
16
|
"FileReadInput",
|
|
17
17
|
"FileReplaceTool",
|