voidx 3.7.1__tar.gz → 3.7.3__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.7.1/src/voidx.egg-info → voidx-3.7.3}/PKG-INFO +1 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_call_llm_compaction.py +49 -0
- voidx-3.7.3/src/tests/test_agent/graph/test_call_llm_structure.py +12 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_graph_authorization.py +187 -16
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_subagent_runner.py +14 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_tool_execution_auth.py +23 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_turn_control_e2e.py +5 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_turn_control_integration.py +30 -16
- voidx-3.7.3/src/tests/test_agent/graph/test_turn_stop_without_pending.py +236 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_workflow_done.py +10 -5
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_workflow_transactions_barrier.py +3 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_model.py +95 -10
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_model_advanced.py +4 -8
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_tavily.py +0 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission.py +38 -56
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission_phase2.py +11 -10
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission_phase4.py +15 -32
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission_phase5.py +12 -14
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission_phase6.py +38 -18
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_tool_filters_gemini.py +111 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_tool_result_storage.py +62 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_config/test_config.py +0 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_config/test_config_advanced.py +20 -33
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_gemini_provider.py +21 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_llm_catalog_fetchers.py +110 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_llm_usage.py +25 -0
- voidx-3.7.3/src/tests/test_permission/test_risk.py +150 -0
- voidx-3.7.3/src/tests/test_release_npm_wheel_sync.py +97 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_skills/test_workflow_advance.py +1 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/bash/test_router_git.py +24 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/bash/test_tool.py +98 -5
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_git_tool_destructive.py +2 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_git_tool_phase5.py +3 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_git_tool_raw_permissions.py +62 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_git_tool_schema_errors.py +0 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_git_tool_structured.py +4 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_powershell_tool.py +52 -2
- voidx-3.7.3/src/tests/test_tools/test_powershell_tool_phase6.py +102 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_shell_tool_phase6.py +54 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_adapter.py +46 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_gateway_v2_dispatch.py +3 -9
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_events_subagent.py +22 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_tool_display.py +32 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_tree_smoke.py +18 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_wheel_verify_cwd.py +5 -5
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/__init__.py +1 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/goal_resolver.py +13 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/contracts.py +7 -5
- voidx-3.7.3/src/voidx/agent/graph/core/context.py +94 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/core/helpers.py +62 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/core/llm.py +110 -331
- voidx-3.7.3/src/voidx/agent/graph/core/loop.py +108 -0
- voidx-3.7.3/src/voidx/agent/graph/core/turn.py +353 -0
- voidx-3.7.3/src/voidx/agent/graph/permissions.py +270 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/run_loop.py +2 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/session_runtime.py +1 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/subagent.py +22 -8
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/executor.py +23 -15
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/helpers.py +2 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/workflow.py +3 -31
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/turn_control.py +13 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/turn_runner.py +5 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/wiring.py +0 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/loop/slash.py +2 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/prompts.py +6 -5
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/runtime_context.py +22 -7
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/handler.py +27 -72
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/host.py +1 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/init.py +2 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/model.py +45 -36
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/todo_state.py +5 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/tool_filters.py +19 -8
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/tool_result_storage.py +34 -9
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/__init__.py +0 -12
- voidx-3.7.3/src/voidx/config/enums.py +41 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/models.py +2 -5
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings.py +1 -18
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_permissions.py +7 -67
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/permission.md +5 -7
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/reference.md +2 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/catalog.py +134 -25
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/provider.py +18 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/usage.py +20 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/paths.py +2 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/__init__.py +9 -0
- voidx-3.7.3/src/voidx/permission/constants.py +177 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/context.py +24 -9
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/engine.py +70 -41
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/git_policy.py +13 -67
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/grants.py +1 -0
- voidx-3.7.3/src/voidx/permission/presets.py +73 -0
- voidx-3.7.3/src/voidx/permission/risk.py +94 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/rules.py +11 -14
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/sandbox.py +11 -39
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/schema.py +9 -3
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/service.py +33 -136
- voidx-3.7.3/src/voidx/permission/shell_policy.py +242 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/intent.py +8 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/task_state.py +8 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/base.py +36 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/tool.py +18 -12
- voidx-3.7.3/src/voidx/tools/git/__init__.py +7 -0
- voidx-3.7.3/src/voidx/tools/git/access.py +251 -0
- voidx-3.7.3/src/voidx/tools/git/constants.py +54 -0
- voidx-3.7.3/src/voidx/tools/git/handlers.py +349 -0
- voidx-3.7.3/src/voidx/tools/git/models.py +38 -0
- voidx-3.7.3/src/voidx/tools/git/parsers.py +247 -0
- voidx-3.7.3/src/voidx/tools/git/process.py +81 -0
- voidx-3.7.3/src/voidx/tools/git/results.py +90 -0
- voidx-3.7.3/src/voidx/tools/git/routing.py +145 -0
- voidx-3.7.3/src/voidx/tools/git/tool.py +109 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/tool.py +18 -12
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/service.py +2 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/shell/common.py +19 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/shell/hint/git.py +15 -9
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/command_catalog.py +3 -6
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/commands.py +5 -16
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/method/settings.py +7 -19
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/capture.py +4 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/nodes.py +4 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/events/consumers.py +4 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/events/schema.py +3 -0
- voidx-3.7.3/src/voidx/ui/output/tool_display.py +136 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/types.py +0 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/__init__.py +0 -2
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/nodes.py +0 -73
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/policy.py +0 -4
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/schema.py +0 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/service.py +0 -1
- {voidx-3.7.1 → voidx-3.7.3/src/voidx.egg-info}/PKG-INFO +1 -1
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx.egg-info/SOURCES.txt +20 -2
- voidx-3.7.1/src/tests/test_tools/test_powershell_tool_phase6.py +0 -53
- voidx-3.7.1/src/voidx/agent/graph/permissions.py +0 -197
- voidx-3.7.1/src/voidx/config/enums.py +0 -60
- voidx-3.7.1/src/voidx/config/permissions.py +0 -24
- voidx-3.7.1/src/voidx/permission/shell_policy.py +0 -138
- voidx-3.7.1/src/voidx/tools/git.py +0 -1242
- voidx-3.7.1/src/voidx/ui/output/tool_display.py +0 -62
- {voidx-3.7.1 → voidx-3.7.3}/LICENSE +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/README.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/pyproject.toml +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/setup.cfg +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/conftest.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/conftest.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/conftest.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/run_loop_helpers.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/stream_llm_helpers.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_call_llm_compaction_advanced.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_call_llm_tools.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_compaction_flow.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_compaction_flow_run_once.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_convergence.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_execute_tools_guard.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_execute_tools_todo.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_graph_setup_prompts.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_guards_tool_op.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_parallel_subagents.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_parallel_subagents_dedup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_prepare_workflow.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_run_loop_startup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_run_loop_title_lsp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_run_loop_title_misc.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_run_loop_workflow.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_run_loop_workflow_advanced.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_runtime_guards.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_context_frames.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_crud.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_messages.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_persistence.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_run_once.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_runtime_state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_session_transcript.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_stream_llm_sanitization.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_subagent_llm_retry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_subagent_persistence.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_subagent_step_budget.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_subagent_step_budget_convergence.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_subagent_step_budget_final.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_todo_events.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_tool_result_preview.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_turn_runner_guidance_discard.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_turn_runner_idle_event.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_workflow_review.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/graph/test_workflow_transactions.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/loop/test_manager.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/loop/test_prompt_source.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_init.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_loop.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_mcp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_session.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_skills.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/slash/test_slash_upgrade.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_attachments.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_file_rwlock.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_goal_resolver.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_goal_resolver_advanced.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_guard_guidance.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_guide_command.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_message_trimming_parsers.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_message_trimming_rules.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_module_boundaries.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission_append.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_permission_phase3.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_prompts.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_runtime_context_builder.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_runtime_context_prompts.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_runtime_context_skill_stripping.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_task_state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_task_state_context_sync.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_task_state_rendering.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_todo_replay_sanitization.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_tool_exchange_sanitizer.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_tool_messages.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_turn_control.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_turn_control_prompt.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_turn_metrics.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_agent/test_turn_start.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_archive_script.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_config/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_config/test_retry_config.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_install_sh.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/conftest.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_compaction_retry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_fallback_summary.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_goal_resolver_retry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_instruction_cache.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_llm_catalog.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_llm_provider.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_llm_provider_advanced.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_overflow_threshold.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_prune_args.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_request_log.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_streaming_sanitize.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_llm/test_token_counting.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_logging/test_external.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_logging/test_internal_error.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_logging/test_tool_log.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_lsp/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_lsp/test_lsp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_lsp/test_lsp_advanced.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_mcp/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_mcp/test_mcp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_memory/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_memory/test_main.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_memory/test_main_startup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_memory/test_schema_migration.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_npm_package.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_permission/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_runtime/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_runtime/test_goal_resolution_refactor.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_runtime/test_processes.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_runtime/test_runtime_ui.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_selfupdate/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_selfupdate/test_selfupdate.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_skills/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_skills/conftest.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_skills/test_create_skill.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_skills/test_skill_parsing.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_skills/test_skill_references.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_test_runner.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/bash/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/bash/test_router_safety.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/bash/test_router_sed_grep.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_coverage_fingerprint.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_anchors.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_bounds_input.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_coverage.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_dedup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_drift_fallback.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_drift_fallback_e2e.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_errors.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_line_insert.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_llm_messages.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_replace.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_edit_trailing_newline.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_read.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_read_write.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_render_numbered_diff.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/file/test_write_file.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_clarify_tool.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_diffing.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_file_tools_redesign.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_infer_state_patch.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_interactive_tools.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_interactive_tools_write.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_load_doc_template.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_loop_integration.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_loop_registry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_make_interact_callback.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_plan_checkpoint.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_replace_failure_logging.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_resolve_safe.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_retry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_schedule_wakeup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_search.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_skills_tool.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_state_update_from_executed_tools.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_task_tracker.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_todo_tool.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_tool_error_handling.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_tool_registry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_tool_schemas.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_tool_state_patch.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_user_interaction_models.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_web_mcp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_webfetch.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_tools/test_workflow_tool.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/conftest.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/helpers.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_diff_review.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_gateway_headless_frontend.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_gateway_v2_crud_diff.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_gateway_v2_routing.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_gateway_v2_server.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_gateway_v2_session.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_guidance_fallback.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_run_manager.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_terminal.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_events_dock_bus.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_events_dock_prompts.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_events_dock_status.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_events_streaming.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_events_todo.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/gateway/test_ui_gateway.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_console_app.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_dock_formatting.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_fmt_args.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_output_browse.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_scrollback_flush.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_ui_diff.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/output/test_ui_session_changes.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/protocol/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/protocol/test_dto.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/protocol/test_v2_envelope.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/protocol/test_v2_methods.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/protocol/test_v2_snapshot.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/protocol/test_v2_threads.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/test_display_policy.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/test_file_picker.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/tools/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/tools/test_clipboard_image.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/tools/test_clipboard_image_windows.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/tools/test_clipboard_text.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/tools/test_clipboard_text_windows.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_ui/tools/test_code_ide.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_voidx_entrypoint.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_wheel_build.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_workflow/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_workflow/test_auto_advance.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/tests/test_workflow/test_workflow_reconcile.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/agents.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/attachments.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/compaction.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/compaction_coordinator.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/convergence.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/core/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/core/voidx_graph.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/runtime.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/runtime_guards.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/session_mixin.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/streaming.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/thread_context.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/title_mixin.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/todo_events.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_execution.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/guards.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/types.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/tool_executor/ui.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/topology.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/transcript_mixin.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/turn_metrics.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/turn_mixin.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/graph/workflow_utils.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/loop/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/loop/manager.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/loop/prompt_source.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/message_rows.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/message_trimming.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/code_ide.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/guide.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/lsp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/mcp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/profile.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/runtime.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/session.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/skills.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/slash/upgrade.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/task_state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/tool_call_ids.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/tool_exchange_sanitizer.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/agent/tool_messages.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/defaults.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_agent.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_api_keys.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_code_ide.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_custom.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_mcp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_retry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_skills.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_update.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_utils.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/config/settings_web.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/README.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/api-doc.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/capability-spec.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/implementation-spec.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/prd.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/readme.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/rfc.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/tasks.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/templates/tech-design.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/README.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/context.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/debug.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/extension.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/mode.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/model.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/preferences.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/quickstart.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/session.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/upgrade.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/web.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/data/documents/voidx-guide/workflow.md +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/diffing.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/compaction.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/context.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/instruction.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/message_markers.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/message_status.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/llm/service.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/logging/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/logging/external.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/logging/internal_error.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/logging/request_log.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/logging/tool_log.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/client.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/config.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/detector.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/detector_data.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/errors.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/manager.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/schema.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/lsp/service.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/main.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/client/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/client/base.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/client/errors.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/client/http_transport.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/client/sse_transport.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/client/stdio_transport.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/manager.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/schema.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp/tool.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp_servers/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/mcp_servers/web.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/cleanup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/context_frames.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/jsonl_store.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/model_profiles.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/runtime_state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/service.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/session.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/store.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/subagents.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/memory/transcript.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/evaluate.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/process_sandbox.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/permission/wildcard.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/_win32_jobs.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/attachments.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/processes.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/reference_tokens.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/todo.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/ui.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/runtime/ui_port.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/selfupdate.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/skills/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/skills/context.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/skills/references.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/skills/registry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/skills/schema.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/skills/service.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/agent.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/core.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/hint/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/hint/file.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/hint/git.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/hint/search.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/router.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/bash/safety.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/checkpoint.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/clarify.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/compact.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/document.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/manage.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/read.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/replace.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/replace_resolve.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/safe_path.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/types.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/file/write.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/lsp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/core.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/hint/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/hint/file.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/hint/search.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/router.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/safety.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/powershell/sandbox.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/registry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/retry.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/schedule_wakeup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/search.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/shell/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/shell/hint/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/skills.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/task_status.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/task_tracker.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/todo.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/web/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/web/content.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/web/fetch.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/web/mcp.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/web/search.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/tools/workflow.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/frontend.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/adapter.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/bootstrap.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/diff_review.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/frontend.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/run_manager.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/server.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/consumer.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/core.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/method/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/method/diff.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/method/integrations.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/method/sessions.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/session/method/terminal.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/gateway/terminal.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/agent_display.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/ansi_marker.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/browse.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/console/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/console/app.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/console/formatting.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/console/streaming.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/diff.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/display_policy.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/agent_placeholder.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/app.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/formatting.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/nodes_checkpoint.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/nodes_clarify.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/nodes_permission.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/nodes_startup.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/nodes_status.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/state.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/status.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/stream.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/dock/todo.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/events/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/events/bus.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/manage_display.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/output/tree.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/commands.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/requests.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/schema.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/transcript.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/v2/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/v2/envelope.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/v2/methods.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/v2/snapshot.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/protocol/v2/threads.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/session.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/__init__.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/attachment_tokens.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/clipboard_image.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/clipboard_text.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/code_ide.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/file_picker.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/tools/skill_picker.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/ui/transcript.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/auto_advance.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/context.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/dag.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/reconcile.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/render.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/route.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/runtime.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx/workflow/types.py +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx.egg-info/dependency_links.txt +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx.egg-info/entry_points.txt +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx.egg-info/requires.txt +0 -0
- {voidx-3.7.1 → voidx-3.7.3}/src/voidx.egg-info/top_level.txt +0 -0
|
@@ -19,6 +19,7 @@ from voidx.agent.task_state import TaskState, TodoRunState
|
|
|
19
19
|
from voidx.config import Config, ModelConfig
|
|
20
20
|
from voidx.agent.graph.compaction_coordinator import CompactionResult, PreflightCompactionResult
|
|
21
21
|
from voidx.llm.compaction import CompactionSelection, SUMMARY_TEMPLATE
|
|
22
|
+
from voidx.llm.usage import estimate_context_tokens
|
|
22
23
|
from voidx.llm.message_markers import is_guidance_message
|
|
23
24
|
from voidx.memory.context_frames import load_context_frames
|
|
24
25
|
from voidx.memory.session import MessageRow, create_session, delete_session, save_message
|
|
@@ -181,6 +182,7 @@ async def test_call_llm_updates_usage_stats_across_turn_control_calls(tmp_path,
|
|
|
181
182
|
"messages": [HumanMessage(content="hi")],
|
|
182
183
|
"step_count": 0,
|
|
183
184
|
"persona": "voidx",
|
|
185
|
+
"turn_state": "running",
|
|
184
186
|
})
|
|
185
187
|
|
|
186
188
|
assert result["step_count"] == 1
|
|
@@ -188,11 +190,38 @@ async def test_call_llm_updates_usage_stats_across_turn_control_calls(tmp_path,
|
|
|
188
190
|
assert graph.model.calls == 2
|
|
189
191
|
assert graph._usage_stats.last_input_tokens == 2
|
|
190
192
|
assert graph._usage_stats.last_output_tokens == 1
|
|
193
|
+
assert graph._usage_stats.context_tokens == 2
|
|
191
194
|
assert graph._usage_stats.total_input_tokens == 9
|
|
192
195
|
assert graph._usage_stats.total_output_tokens == 4
|
|
193
196
|
assert graph._usage_stats.total_calls == 2
|
|
194
197
|
|
|
195
198
|
|
|
199
|
+
@pytest.mark.asyncio
|
|
200
|
+
async def test_call_llm_fallback_context_estimate_includes_tool_schema(tmp_path, monkeypatch):
|
|
201
|
+
import voidx.agent.graph.core.llm as graph_module
|
|
202
|
+
|
|
203
|
+
monkeypatch.setattr(graph_module, "StreamingRenderer", FakeRenderer)
|
|
204
|
+
|
|
205
|
+
graph = VoidXGraph(
|
|
206
|
+
Config(
|
|
207
|
+
model=ModelConfig(provider="openai", model="gpt-4o"),
|
|
208
|
+
workspace=str(tmp_path),
|
|
209
|
+
),
|
|
210
|
+
api_key=None,
|
|
211
|
+
)
|
|
212
|
+
graph.model = FakeStreamingModel()
|
|
213
|
+
|
|
214
|
+
await graph._call_llm({
|
|
215
|
+
"messages": [HumanMessage(content="hi")],
|
|
216
|
+
"step_count": 0,
|
|
217
|
+
"persona": "voidx",
|
|
218
|
+
"turn_state": "running",
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
messages_only = estimate_context_tokens(graph.model.messages, graph.config.model.model)
|
|
222
|
+
assert graph._usage_stats.context_tokens > messages_only
|
|
223
|
+
|
|
224
|
+
|
|
196
225
|
@pytest.mark.asyncio
|
|
197
226
|
async def test_call_llm_persists_context_frame_for_session(tmp_path, monkeypatch):
|
|
198
227
|
import voidx.agent.graph.core.llm as graph_module
|
|
@@ -792,3 +821,23 @@ def test_llm_retry_delay_exponential_cap():
|
|
|
792
821
|
assert _llm_retry_delay(8) == 60.0
|
|
793
822
|
assert _llm_retry_delay(9) == 60.0
|
|
794
823
|
assert _llm_retry_delay(10) == 60.0
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
def test_clean_error_message():
|
|
827
|
+
from voidx.agent.graph.core.helpers import _clean_error_message
|
|
828
|
+
|
|
829
|
+
# Test case 1: OpenAI rate limit error with dict representation
|
|
830
|
+
exc1 = Exception("Error code: 402 - {'error': {'type': 'rate_limit_error', 'message': '每日额度超限: 当前 $50.813...'}}")
|
|
831
|
+
assert _clean_error_message(exc1) == "Error code: 402 - 每日额度超限: 当前 $50.813..."
|
|
832
|
+
|
|
833
|
+
# Test case 2: OpenAI error with json representation
|
|
834
|
+
exc2 = Exception('Error code: 400 - {"error": {"message": "Invalid prompt", "type": "invalid_request_error"}}')
|
|
835
|
+
assert _clean_error_message(exc2) == "Error code: 400 - Invalid prompt"
|
|
836
|
+
|
|
837
|
+
# Test case 3: Standard exception with no JSON/dict
|
|
838
|
+
exc3 = Exception("Connection refused")
|
|
839
|
+
assert _clean_error_message(exc3) == "Connection refused"
|
|
840
|
+
|
|
841
|
+
# Test case 4: Dict representation without error key
|
|
842
|
+
exc4 = Exception("Error: {'message': 'Something went wrong'}")
|
|
843
|
+
assert _clean_error_message(exc4) == "Error - Something went wrong"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Structure tests for the call_llm refactor."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_call_llm_helpers_live_in_core_modules():
|
|
7
|
+
for module_name in (
|
|
8
|
+
"voidx.agent.graph.core.loop",
|
|
9
|
+
"voidx.agent.graph.core.turn",
|
|
10
|
+
"voidx.agent.graph.core.context",
|
|
11
|
+
):
|
|
12
|
+
assert importlib.import_module(module_name)
|
|
@@ -72,6 +72,10 @@ def _result_task_state(result: dict) -> TaskState:
|
|
|
72
72
|
return TaskState.model_validate(result["task_state"])
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
def _asked_tool_calls(batch):
|
|
76
|
+
return [getattr(item, "tool_call", item) for item in batch]
|
|
77
|
+
|
|
78
|
+
|
|
75
79
|
def _child_goal_resolution(
|
|
76
80
|
goal_type: str = "feature",
|
|
77
81
|
*,
|
|
@@ -141,7 +145,6 @@ def test_permission_decision_splits_readonly_and_implement_agents():
|
|
|
141
145
|
@pytest.mark.asyncio
|
|
142
146
|
async def test_graph_authorization_auto_allows_readonly_agent(tmp_path):
|
|
143
147
|
graph = _graph(tmp_path)
|
|
144
|
-
graph._permission.approval_policy = "untrusted"
|
|
145
148
|
approved, denied = await graph._authorize_tool_calls(
|
|
146
149
|
[{
|
|
147
150
|
"name": "agent",
|
|
@@ -191,7 +194,7 @@ async def test_graph_authorization_prompts_for_implement_agent(tmp_path):
|
|
|
191
194
|
|
|
192
195
|
assert [tc["name"] for tc in approved] == ["agent"]
|
|
193
196
|
assert denied == []
|
|
194
|
-
assert [[tc["args"]["goal_resolution"]["plan"]["join"] for tc in batch] for batch in asked] == [["tdd"]]
|
|
197
|
+
assert [[tc["args"]["goal_resolution"]["plan"]["join"] for tc in _asked_tool_calls(batch)] for batch in asked] == [["tdd"]]
|
|
195
198
|
|
|
196
199
|
|
|
197
200
|
@pytest.mark.asyncio
|
|
@@ -210,10 +213,37 @@ async def test_graph_authorization_respects_session_deny_for_safe_bash(tmp_path)
|
|
|
210
213
|
assert "Permission denied" in denied[0][1]
|
|
211
214
|
|
|
212
215
|
|
|
216
|
+
@pytest.mark.asyncio
|
|
217
|
+
async def test_graph_authorization_never_approves_mixed_blocked_batch(tmp_path):
|
|
218
|
+
graph = _graph(tmp_path)
|
|
219
|
+
graph._permission.permission_mode = "safe"
|
|
220
|
+
asked: list[list[object]] = []
|
|
221
|
+
|
|
222
|
+
async def approve(tool_calls):
|
|
223
|
+
asked.append(tool_calls)
|
|
224
|
+
return "y"
|
|
225
|
+
|
|
226
|
+
graph._ask_tool_permission = approve
|
|
227
|
+
|
|
228
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
229
|
+
[
|
|
230
|
+
{"name": "bash", "args": {"command": "rm -rf /"}, "id": "blocked"},
|
|
231
|
+
{"name": "bash", "args": {"command": "echo $(date)"}, "id": "ask"},
|
|
232
|
+
],
|
|
233
|
+
plan_mode=False,
|
|
234
|
+
session_id="test",
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
assert [call["id"] for call in approved] == ["ask"]
|
|
238
|
+
assert [call["id"] for call, _ in denied] == ["blocked"]
|
|
239
|
+
assert len(asked) == 2
|
|
240
|
+
assert [item.tool_call["id"] for item in asked[0]] == ["blocked"]
|
|
241
|
+
assert [item.tool_call["id"] for item in asked[1]] == ["ask"]
|
|
242
|
+
|
|
243
|
+
|
|
213
244
|
@pytest.mark.asyncio
|
|
214
245
|
async def test_graph_authorization_asks_for_write_by_active_workflow_gate(tmp_path):
|
|
215
246
|
graph = _graph(tmp_path)
|
|
216
|
-
graph._permission.approval_policy = "on-request"
|
|
217
247
|
asked: list[list[dict]] = []
|
|
218
248
|
|
|
219
249
|
async def approve(tool_calls):
|
|
@@ -231,7 +261,7 @@ async def test_graph_authorization_asks_for_write_by_active_workflow_gate(tmp_pa
|
|
|
231
261
|
],
|
|
232
262
|
)
|
|
233
263
|
|
|
234
|
-
assert [[call["id"] for call in batch] for batch in asked] == [["call_1"]]
|
|
264
|
+
assert [[call["id"] for call in _asked_tool_calls(batch)] for batch in asked] == [["call_1"]]
|
|
235
265
|
assert [call["id"] for call in approved] == ["call_1"]
|
|
236
266
|
assert denied == []
|
|
237
267
|
|
|
@@ -239,8 +269,7 @@ async def test_graph_authorization_asks_for_write_by_active_workflow_gate(tmp_pa
|
|
|
239
269
|
@pytest.mark.asyncio
|
|
240
270
|
async def test_graph_authorization_uses_current_workflow_gate_only(tmp_path):
|
|
241
271
|
graph = _graph(tmp_path)
|
|
242
|
-
|
|
243
|
-
|
|
272
|
+
|
|
244
273
|
approved, denied = await graph._authorize_tool_calls(
|
|
245
274
|
[{
|
|
246
275
|
"name": "edit",
|
|
@@ -263,7 +292,6 @@ async def test_graph_authorization_uses_current_workflow_gate_only(tmp_path):
|
|
|
263
292
|
@pytest.mark.asyncio
|
|
264
293
|
async def test_graph_authorization_allows_plan_gate_doc_paths_only(tmp_path):
|
|
265
294
|
graph = _graph(tmp_path)
|
|
266
|
-
graph._permission.approval_policy = "on-request"
|
|
267
295
|
asked: list[list[dict]] = []
|
|
268
296
|
|
|
269
297
|
async def deny(tool_calls):
|
|
@@ -294,7 +322,7 @@ async def test_graph_authorization_allows_plan_gate_doc_paths_only(tmp_path):
|
|
|
294
322
|
)
|
|
295
323
|
|
|
296
324
|
assert [call["id"] for call in approved] == ["call_docs"]
|
|
297
|
-
assert [[call["id"] for call in batch] for batch in asked] == [["call_src"]]
|
|
325
|
+
assert [[call["id"] for call in _asked_tool_calls(batch)] for batch in asked] == [["call_src"]]
|
|
298
326
|
assert [call["id"] for call, _reason in denied] == ["call_src"]
|
|
299
327
|
assert denied[0][1] == "User denied: replace"
|
|
300
328
|
|
|
@@ -302,8 +330,7 @@ async def test_graph_authorization_allows_plan_gate_doc_paths_only(tmp_path):
|
|
|
302
330
|
@pytest.mark.asyncio
|
|
303
331
|
async def test_graph_authorization_allowed_paths_match_nested_docs(tmp_path):
|
|
304
332
|
graph = _graph(tmp_path)
|
|
305
|
-
|
|
306
|
-
|
|
333
|
+
|
|
307
334
|
approved, denied = await graph._authorize_tool_calls(
|
|
308
335
|
[{
|
|
309
336
|
"name": "edit",
|
|
@@ -325,8 +352,7 @@ async def test_graph_authorization_allowed_paths_match_nested_docs(tmp_path):
|
|
|
325
352
|
@pytest.mark.asyncio
|
|
326
353
|
async def test_graph_authorization_does_not_block_tools_outside_active_workflow_node_allowlist(tmp_path):
|
|
327
354
|
graph = _graph(tmp_path)
|
|
328
|
-
|
|
329
|
-
|
|
355
|
+
|
|
330
356
|
approved, denied = await graph._authorize_tool_calls(
|
|
331
357
|
[{
|
|
332
358
|
"name": "todo",
|
|
@@ -348,7 +374,6 @@ async def test_graph_authorization_does_not_block_tools_outside_active_workflow_
|
|
|
348
374
|
@pytest.mark.asyncio
|
|
349
375
|
async def test_graph_authorization_asks_for_workflow_gate_tools_instead_of_denying(tmp_path):
|
|
350
376
|
graph = _graph(tmp_path)
|
|
351
|
-
graph._permission.approval_policy = "on-request"
|
|
352
377
|
asked: list[list[dict]] = []
|
|
353
378
|
|
|
354
379
|
async def approve(tool_calls):
|
|
@@ -371,7 +396,7 @@ async def test_graph_authorization_asks_for_workflow_gate_tools_instead_of_denyi
|
|
|
371
396
|
],
|
|
372
397
|
)
|
|
373
398
|
|
|
374
|
-
assert [[call["id"] for call in batch] for batch in asked] == [["call_src"]]
|
|
399
|
+
assert [[call["id"] for call in _asked_tool_calls(batch)] for batch in asked] == [["call_src"]]
|
|
375
400
|
assert [call["id"] for call in approved] == ["call_src"]
|
|
376
401
|
assert denied == []
|
|
377
402
|
|
|
@@ -379,7 +404,6 @@ async def test_graph_authorization_asks_for_workflow_gate_tools_instead_of_denyi
|
|
|
379
404
|
@pytest.mark.asyncio
|
|
380
405
|
async def test_graph_authorization_asks_for_persona_blocked_write(tmp_path):
|
|
381
406
|
graph = _graph(tmp_path)
|
|
382
|
-
graph._permission.approval_policy = "on-request"
|
|
383
407
|
asked: list[list[dict]] = []
|
|
384
408
|
|
|
385
409
|
async def approve(tool_calls):
|
|
@@ -402,7 +426,6 @@ async def test_graph_authorization_asks_for_persona_blocked_write(tmp_path):
|
|
|
402
426
|
@pytest.mark.asyncio
|
|
403
427
|
async def test_permission_result_uses_transient_output(tmp_path):
|
|
404
428
|
graph = _graph(tmp_path)
|
|
405
|
-
graph._permission.approval_policy = "untrusted"
|
|
406
429
|
test_dock = BottomInputDock()
|
|
407
430
|
set_dock(test_dock)
|
|
408
431
|
test_dock.begin_capture()
|
|
@@ -470,6 +493,9 @@ async def test_permission_prompt_uses_dock_details_when_events_are_active(tmp_pa
|
|
|
470
493
|
"name": "bash",
|
|
471
494
|
"pattern": "npm install lodash",
|
|
472
495
|
"args": {"command": "npm install lodash"},
|
|
496
|
+
"risk": None,
|
|
497
|
+
"allowed_scopes": [],
|
|
498
|
+
"default_scope": None,
|
|
473
499
|
}]
|
|
474
500
|
record = test_dock.status_record("permission:request")
|
|
475
501
|
assert record is not None
|
|
@@ -480,3 +506,148 @@ async def test_permission_prompt_uses_dock_details_when_events_are_active(tmp_pa
|
|
|
480
506
|
await graph._ui.events.stop()
|
|
481
507
|
test_dock.deactivate()
|
|
482
508
|
set_dock(None)
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
@pytest.mark.asyncio
|
|
512
|
+
async def test_read_only_permission_prompt_limits_choices_to_once(tmp_path):
|
|
513
|
+
graph = _graph(tmp_path)
|
|
514
|
+
graph._permission.set_permission_mode("read_only")
|
|
515
|
+
captured_choices = None
|
|
516
|
+
|
|
517
|
+
class FakeApp:
|
|
518
|
+
async def ask_choice(self, _prompt, choices, details=None):
|
|
519
|
+
nonlocal captured_choices
|
|
520
|
+
captured_choices = choices
|
|
521
|
+
return "y"
|
|
522
|
+
|
|
523
|
+
graph._app = FakeApp()
|
|
524
|
+
|
|
525
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
526
|
+
[{"name": "bash", "args": {"command": "cat input.txt > output.txt"}, "id": "call_1"}],
|
|
527
|
+
plan_mode=False,
|
|
528
|
+
session_id="s",
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
assert [tc["name"] for tc in approved] == ["bash"]
|
|
532
|
+
assert denied == []
|
|
533
|
+
assert captured_choices == [
|
|
534
|
+
("Yes", "y", "Allow this tool use once"),
|
|
535
|
+
("No", "n", "Deny these tools"),
|
|
536
|
+
]
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
@pytest.mark.asyncio
|
|
540
|
+
async def test_permission_prompt_details_include_risk_and_scopes(tmp_path):
|
|
541
|
+
graph = _graph(tmp_path)
|
|
542
|
+
graph._permission.set_permission_mode("safe")
|
|
543
|
+
received_details = None
|
|
544
|
+
|
|
545
|
+
class FakeApp:
|
|
546
|
+
async def ask_choice(self, _prompt, _choices, details=None):
|
|
547
|
+
nonlocal received_details
|
|
548
|
+
received_details = details
|
|
549
|
+
return "y"
|
|
550
|
+
|
|
551
|
+
graph._app = FakeApp()
|
|
552
|
+
|
|
553
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
554
|
+
[{"name": "bash", "args": {"command": "npm install lodash"}, "id": "call_1"}],
|
|
555
|
+
plan_mode=False,
|
|
556
|
+
session_id="s",
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
assert [tc["name"] for tc in approved] == ["bash"]
|
|
560
|
+
assert denied == []
|
|
561
|
+
assert received_details == [{
|
|
562
|
+
"name": "bash",
|
|
563
|
+
"pattern": "npm install lodash",
|
|
564
|
+
"args": {"command": "npm install lodash"},
|
|
565
|
+
"risk": {
|
|
566
|
+
"level": "extreme",
|
|
567
|
+
"tags": ["dependency_install"],
|
|
568
|
+
"reason": "shell policy deferred: dependency install command",
|
|
569
|
+
"tool_name": "bash",
|
|
570
|
+
"pattern": "npm install lodash",
|
|
571
|
+
},
|
|
572
|
+
"allowed_scopes": ["once"],
|
|
573
|
+
"default_scope": "once",
|
|
574
|
+
}]
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
@pytest.mark.asyncio
|
|
578
|
+
async def test_graph_authorization_attaches_approved_risk_token_to_approved_shell_call(tmp_path):
|
|
579
|
+
graph = _graph(tmp_path)
|
|
580
|
+
graph._permission.set_permission_mode("read_only")
|
|
581
|
+
graph._permission.set_permission_mode("read_only")
|
|
582
|
+
|
|
583
|
+
async def approve(_tool_calls):
|
|
584
|
+
return "y"
|
|
585
|
+
|
|
586
|
+
graph._ask_tool_permission = approve
|
|
587
|
+
command = "cat input.txt > output.txt"
|
|
588
|
+
|
|
589
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
590
|
+
[{"name": "bash", "args": {"command": command}, "id": "call_1"}],
|
|
591
|
+
plan_mode=False,
|
|
592
|
+
session_id="s",
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
assert denied == []
|
|
596
|
+
assert approved[0]["metadata"]["approved_risk"] == {
|
|
597
|
+
"tool_name": "bash",
|
|
598
|
+
"pattern": command,
|
|
599
|
+
"risk_level": "extreme",
|
|
600
|
+
"tags": ["dynamic_shell"],
|
|
601
|
+
"reason": "shell policy deferred: compound shell syntax, compound shell operator",
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
@pytest.mark.asyncio
|
|
606
|
+
async def test_blocked_permission_prompt_only_acknowledges_and_denies_execution(tmp_path):
|
|
607
|
+
graph = _graph(tmp_path)
|
|
608
|
+
graph._permission.set_permission_mode("safe")
|
|
609
|
+
captured_choices = None
|
|
610
|
+
captured_details = None
|
|
611
|
+
|
|
612
|
+
class FakeApp:
|
|
613
|
+
async def ask_choice(self, _prompt, choices, details=None):
|
|
614
|
+
nonlocal captured_choices, captured_details
|
|
615
|
+
captured_choices = choices
|
|
616
|
+
captured_details = details
|
|
617
|
+
return "n"
|
|
618
|
+
|
|
619
|
+
graph._app = FakeApp()
|
|
620
|
+
|
|
621
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
622
|
+
[{"name": "bash", "args": {"command": "sudo true"}, "id": "call_blocked"}],
|
|
623
|
+
plan_mode=False,
|
|
624
|
+
session_id="s",
|
|
625
|
+
)
|
|
626
|
+
|
|
627
|
+
assert approved == []
|
|
628
|
+
assert denied == [({"name": "bash", "args": {"command": "sudo true"}, "id": "call_blocked"}, "Blocked: sudo is blocked — privilege escalation")]
|
|
629
|
+
assert captured_choices == [("Do not run", "n", "This command is blocked")]
|
|
630
|
+
assert captured_details[0]["risk"]["level"] == "blocked"
|
|
631
|
+
assert captured_details[0]["allowed_scopes"] == []
|
|
632
|
+
assert captured_details[0]["default_scope"] is None
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
@pytest.mark.asyncio
|
|
636
|
+
async def test_blocked_permission_prompt_cannot_be_approved_with_yes(tmp_path):
|
|
637
|
+
graph = _graph(tmp_path)
|
|
638
|
+
graph._permission.set_permission_mode("safe")
|
|
639
|
+
|
|
640
|
+
class FakeApp:
|
|
641
|
+
async def ask_choice(self, _prompt, _choices, details=None):
|
|
642
|
+
return "y"
|
|
643
|
+
|
|
644
|
+
graph._app = FakeApp()
|
|
645
|
+
|
|
646
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
647
|
+
[{"name": "bash", "args": {"command": "sudo true"}, "id": "call_blocked"}],
|
|
648
|
+
plan_mode=False,
|
|
649
|
+
session_id="s",
|
|
650
|
+
)
|
|
651
|
+
|
|
652
|
+
assert approved == []
|
|
653
|
+
assert denied == [({"name": "bash", "args": {"command": "sudo true"}, "id": "call_blocked"}, "Blocked: sudo is blocked — privilege escalation")]
|
|
@@ -72,6 +72,10 @@ def _result_task_state(result: dict) -> TaskState:
|
|
|
72
72
|
return TaskState.model_validate(result["task_state"])
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
def _asked_tool_calls(batch):
|
|
76
|
+
return [getattr(item, "tool_call", item) for item in batch]
|
|
77
|
+
|
|
78
|
+
|
|
75
79
|
def _child_goal_resolution(
|
|
76
80
|
goal_type: str = "feature",
|
|
77
81
|
*,
|
|
@@ -319,7 +323,13 @@ async def test_subagent_runner_authorizes_with_child_interaction_mode(tmp_path,
|
|
|
319
323
|
@pytest.mark.asyncio
|
|
320
324
|
async def test_graph_authorization_does_not_treat_goal_as_read_only_mode(tmp_path):
|
|
321
325
|
graph = _graph(tmp_path)
|
|
322
|
-
|
|
326
|
+
asked: list[list[dict]] = []
|
|
327
|
+
|
|
328
|
+
async def approve(tool_calls):
|
|
329
|
+
asked.append(tool_calls)
|
|
330
|
+
return "y"
|
|
331
|
+
|
|
332
|
+
graph._ask_tool_permission = approve
|
|
323
333
|
|
|
324
334
|
approved, denied = await graph._authorize_tool_calls(
|
|
325
335
|
[{"name": "edit", "args": {"file_path": "src/app.py"}, "id": "call_1"}],
|
|
@@ -331,6 +341,7 @@ async def test_graph_authorization_does_not_treat_goal_as_read_only_mode(tmp_pat
|
|
|
331
341
|
|
|
332
342
|
assert [tc["name"] for tc in approved] == ["replace"]
|
|
333
343
|
assert denied == []
|
|
344
|
+
assert [[tc["name"] for tc in _asked_tool_calls(batch)] for batch in asked] == [["replace"]]
|
|
334
345
|
|
|
335
346
|
|
|
336
347
|
@pytest.mark.asyncio
|
|
@@ -369,7 +380,7 @@ async def test_graph_authorization_prompts_for_edit(tmp_path):
|
|
|
369
380
|
|
|
370
381
|
assert [tc["name"] for tc in approved] == ["replace"]
|
|
371
382
|
assert denied == []
|
|
372
|
-
assert [[tc["name"] for tc in batch] for batch in asked] == [["replace"]]
|
|
383
|
+
assert [[tc["name"] for tc in _asked_tool_calls(batch)] for batch in asked] == [["replace"]]
|
|
373
384
|
|
|
374
385
|
|
|
375
386
|
@pytest.mark.asyncio
|
|
@@ -413,4 +424,4 @@ async def test_graph_authorization_prompts_for_unsafe_bash(tmp_path):
|
|
|
413
424
|
|
|
414
425
|
assert [tc["name"] for tc in approved] == ["bash"]
|
|
415
426
|
assert denied == []
|
|
416
|
-
assert [[tc["name"] for tc in batch] for batch in asked] == [["bash"]]
|
|
427
|
+
assert [[tc["name"] for tc in _asked_tool_calls(batch)] for batch in asked] == [["bash"]]
|
|
@@ -135,7 +135,7 @@ def _tree_nodes(root):
|
|
|
135
135
|
@pytest.mark.asyncio
|
|
136
136
|
async def test_graph_on_request_auto_approves_need_ask_tools(tmp_path):
|
|
137
137
|
graph = _graph(tmp_path)
|
|
138
|
-
graph._permission.
|
|
138
|
+
graph._permission.permission_mode = "full_access"
|
|
139
139
|
|
|
140
140
|
approved, denied = await graph._authorize_tool_calls(
|
|
141
141
|
[{"name": "write", "args": {"file_path": "app.py", "op": "append", "new_string": "x"}, "id": "call_1"}],
|
|
@@ -149,10 +149,30 @@ async def test_graph_on_request_auto_approves_need_ask_tools(tmp_path):
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
@pytest.mark.asyncio
|
|
152
|
-
async def
|
|
152
|
+
async def test_full_access_auto_approves_write_without_implement_persona(tmp_path):
|
|
153
153
|
graph = _graph(tmp_path)
|
|
154
|
-
graph._permission.
|
|
154
|
+
graph._permission.permission_mode = "full_access"
|
|
155
|
+
|
|
156
|
+
async def fail_if_asked(_tool_calls):
|
|
157
|
+
pytest.fail("full_access should not prompt for workspace edit")
|
|
158
|
+
|
|
159
|
+
graph._ask_tool_permission = fail_if_asked
|
|
160
|
+
|
|
161
|
+
approved, denied = await graph._authorize_tool_calls(
|
|
162
|
+
[{"name": "replace", "args": {"file_path": "app.py", "bounds": [{"line_no": 1, "anchor": "x"}], "new_string": "y"}, "id": "call_1"}],
|
|
163
|
+
runtime_persona="coordinate",
|
|
164
|
+
plan_mode=False,
|
|
165
|
+
session_id="test",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
assert [tc["name"] for tc in approved] == ["replace"]
|
|
169
|
+
assert denied == []
|
|
170
|
+
|
|
155
171
|
|
|
172
|
+
@pytest.mark.asyncio
|
|
173
|
+
async def test_graph_on_failure_asks_unsafe_bash_before_prompt(tmp_path):
|
|
174
|
+
graph = _graph(tmp_path)
|
|
175
|
+
|
|
156
176
|
asked: list[dict] = []
|
|
157
177
|
|
|
158
178
|
async def ask(tool_calls):
|
|
@@ -102,6 +102,7 @@ async def test_regular_tool_call_resets_missing_turn_count(tmp_path, monkeypatch
|
|
|
102
102
|
"messages": [HumanMessage(content="hello")],
|
|
103
103
|
"step_count": 0,
|
|
104
104
|
"persona": "coordinate",
|
|
105
|
+
"turn_state": "running",
|
|
105
106
|
})
|
|
106
107
|
# The regular tool call should route to execute, not end
|
|
107
108
|
assert result1["messages"][0].tool_calls
|
|
@@ -113,6 +114,7 @@ async def test_regular_tool_call_resets_missing_turn_count(tmp_path, monkeypatch
|
|
|
113
114
|
"messages": [HumanMessage(content="hello"), *result1["messages"]],
|
|
114
115
|
"step_count": 1,
|
|
115
116
|
"persona": "coordinate",
|
|
117
|
+
"turn_state": result1.get("turn_state", "running"),
|
|
116
118
|
})
|
|
117
119
|
assert result2["messages"][0].content == "Final answer."
|
|
118
120
|
assert not result2["messages"][0].tool_calls
|
|
@@ -170,6 +172,7 @@ async def test_turn_call_never_emits_permission_or_execution_events(tmp_path, mo
|
|
|
170
172
|
"messages": [HumanMessage(content="hello")],
|
|
171
173
|
"step_count": 0,
|
|
172
174
|
"persona": "coordinate",
|
|
175
|
+
"turn_state": "running",
|
|
173
176
|
})
|
|
174
177
|
|
|
175
178
|
# Check that no tool permission or tool execution events were emitted
|
|
@@ -195,6 +198,7 @@ async def test_successful_barrier_emits_one_committed_stream(tmp_path, monkeypat
|
|
|
195
198
|
"messages": [HumanMessage(content="hello")],
|
|
196
199
|
"step_count": 0,
|
|
197
200
|
"persona": "coordinate",
|
|
201
|
+
"turn_state": "running",
|
|
198
202
|
})
|
|
199
203
|
|
|
200
204
|
msgs = result["messages"]
|
|
@@ -221,6 +225,7 @@ async def test_regular_tool_continues_after_turn_prompt(tmp_path, monkeypatch):
|
|
|
221
225
|
"messages": [HumanMessage(content="hello")],
|
|
222
226
|
"step_count": 0,
|
|
223
227
|
"persona": "coordinate",
|
|
228
|
+
"turn_state": "running",
|
|
224
229
|
})
|
|
225
230
|
|
|
226
231
|
assert result["messages"][0].tool_calls
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Integration tests for turn control inside _call_llm."""
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
|
-
from langchain_core.messages import AIMessage, AIMessageChunk, HumanMessage
|
|
4
|
+
from langchain_core.messages import AIMessage, AIMessageChunk, HumanMessage, ToolMessage
|
|
5
5
|
|
|
6
6
|
from voidx.agent.graph import VoidXGraph
|
|
7
7
|
from voidx.agent.graph.turn_control import TURN_TOOL_DEFINITION
|
|
@@ -291,11 +291,11 @@ async def test_regular_tool_call_routes_to_execute(tmp_path, monkeypatch):
|
|
|
291
291
|
assert msgs[0].tool_calls[0]["name"] == "read"
|
|
292
292
|
|
|
293
293
|
|
|
294
|
-
# ── Test 4: first plain-text
|
|
294
|
+
# ── Test 4: first plain-text answer can complete immediately ────────────────
|
|
295
295
|
|
|
296
296
|
|
|
297
297
|
@pytest.mark.asyncio
|
|
298
|
-
async def
|
|
298
|
+
async def test_first_plain_text_commits_without_start_prompt(tmp_path, monkeypatch):
|
|
299
299
|
model = ScriptedStreamingModel([
|
|
300
300
|
[_text_chunk("Provisional answer.")],
|
|
301
301
|
[_turn_call_chunk()],
|
|
@@ -311,11 +311,13 @@ async def test_first_plain_text_triggers_first_prompt_then_turn(tmp_path, monkey
|
|
|
311
311
|
msgs = result["messages"]
|
|
312
312
|
assert msgs[0].content == "Provisional answer."
|
|
313
313
|
assert not msgs[0].tool_calls
|
|
314
|
-
assert
|
|
314
|
+
assert result["turn_state"] == "committed"
|
|
315
|
+
assert model.call_index == 1
|
|
316
|
+
assert len(model.received_messages) == 1
|
|
315
317
|
|
|
316
318
|
|
|
317
319
|
@pytest.mark.asyncio
|
|
318
|
-
async def
|
|
320
|
+
async def test_initial_plain_text_keeps_full_tool_set_without_reprompt(tmp_path, monkeypatch):
|
|
319
321
|
model = ScriptedStreamingModel([
|
|
320
322
|
[_text_chunk("Provisional answer.")],
|
|
321
323
|
[_turn_call_chunk()],
|
|
@@ -329,12 +331,8 @@ async def test_missing_turn_reprompt_keeps_full_tool_set_and_appends_turn_prompt
|
|
|
329
331
|
})
|
|
330
332
|
|
|
331
333
|
assert result["messages"][0].content == "Provisional answer."
|
|
332
|
-
assert model.call_index ==
|
|
333
|
-
|
|
334
|
-
assert any(
|
|
335
|
-
isinstance(msg, HumanMessage) and "operation='start'" in str(msg.content)
|
|
336
|
-
for msg in turn_prompt_messages
|
|
337
|
-
)
|
|
334
|
+
assert model.call_index == 1
|
|
335
|
+
assert len(model.received_messages) == 1
|
|
338
336
|
tool_names = [tool["function"]["name"] for tool in model.bound_tools]
|
|
339
337
|
assert "turn" in tool_names
|
|
340
338
|
assert "read" in tool_names
|
|
@@ -352,6 +350,7 @@ async def test_regular_tool_after_turn_prompt_continues_without_committing_text(
|
|
|
352
350
|
"messages": [HumanMessage(content="read x.py")],
|
|
353
351
|
"step_count": 0,
|
|
354
352
|
"persona": "coordinate",
|
|
353
|
+
"turn_state": "running",
|
|
355
354
|
})
|
|
356
355
|
|
|
357
356
|
assert result["messages"][0].tool_calls
|
|
@@ -384,7 +383,7 @@ async def test_decision_only_turn_with_text_is_rejected_before_stop(tmp_path, mo
|
|
|
384
383
|
|
|
385
384
|
|
|
386
385
|
@pytest.mark.asyncio
|
|
387
|
-
async def
|
|
386
|
+
async def test_initial_plain_text_commits_without_hidden_ui_followups(tmp_path, monkeypatch):
|
|
388
387
|
RecordingRenderer.reset()
|
|
389
388
|
model = ScriptedStreamingModel([
|
|
390
389
|
[_text_chunk("First provisional.")],
|
|
@@ -400,10 +399,12 @@ async def test_plain_text_prompts_start_then_stop_without_ui_leak(tmp_path, monk
|
|
|
400
399
|
})
|
|
401
400
|
|
|
402
401
|
visible_text = "".join(RecordingRenderer.visible_text)
|
|
403
|
-
assert result["messages"][0].content == "
|
|
402
|
+
assert result["messages"][0].content == "First provisional."
|
|
404
403
|
assert "First provisional." in visible_text
|
|
404
|
+
assert "Second provisional." not in visible_text
|
|
405
405
|
assert RecordingRenderer.headless_values[0] is False
|
|
406
|
-
assert
|
|
406
|
+
assert RecordingRenderer.headless_values == [False]
|
|
407
|
+
assert model.call_index == 1
|
|
407
408
|
|
|
408
409
|
|
|
409
410
|
# ── Test 6: second plain-text fallback keeps latest response ────────────────
|
|
@@ -422,6 +423,7 @@ async def test_invalid_turn_continue_recovers_with_regular_tool(tmp_path, monkey
|
|
|
422
423
|
"messages": [HumanMessage(content="hello")],
|
|
423
424
|
"step_count": 0,
|
|
424
425
|
"persona": "coordinate",
|
|
426
|
+
"turn_state": "running",
|
|
425
427
|
})
|
|
426
428
|
|
|
427
429
|
assert result["messages"][0].tool_calls
|
|
@@ -512,8 +514,8 @@ async def test_turn_with_non_empty_args_is_rejected(tmp_path, monkeypatch):
|
|
|
512
514
|
}],
|
|
513
515
|
)
|
|
514
516
|
model = ScriptedStreamingModel([
|
|
515
|
-
[_text_chunk("answer")],
|
|
516
517
|
[malformed_turn],
|
|
518
|
+
[_text_chunk("answer")],
|
|
517
519
|
[_turn_call_chunk()],
|
|
518
520
|
])
|
|
519
521
|
graph = _make_graph(tmp_path, model, monkeypatch)
|
|
@@ -623,7 +625,19 @@ async def test_start_prompt_injected_once_then_stop_prompt(tmp_path, monkeypatch
|
|
|
623
625
|
graph = _make_graph(tmp_path, model, monkeypatch)
|
|
624
626
|
|
|
625
627
|
result = await graph._call_llm({
|
|
626
|
-
"messages": [
|
|
628
|
+
"messages": [
|
|
629
|
+
HumanMessage(content="hello"),
|
|
630
|
+
AIMessage(
|
|
631
|
+
content="",
|
|
632
|
+
tool_calls=[{
|
|
633
|
+
"name": "read",
|
|
634
|
+
"args": {"file_path": "x.py"},
|
|
635
|
+
"id": "tc-prior",
|
|
636
|
+
"type": "tool_call",
|
|
637
|
+
}],
|
|
638
|
+
),
|
|
639
|
+
ToolMessage(content="ok", tool_call_id="tc-prior", name="read"),
|
|
640
|
+
],
|
|
627
641
|
"step_count": 0,
|
|
628
642
|
"persona": "coordinate",
|
|
629
643
|
"turn_state": "initial",
|