voidx 3.5.1__tar.gz → 3.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (555) hide show
  1. {voidx-3.5.1/src/voidx.egg-info → voidx-3.6.0}/PKG-INFO +1 -1
  2. {voidx-3.5.1 → voidx-3.6.0}/pyproject.toml +1 -1
  3. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_execute_tools_guard.py +128 -1
  4. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_graph_authorization.py +7 -3
  5. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_prepare_workflow.py +46 -0
  6. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_run_loop_startup.py +156 -0
  7. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_run_loop_workflow.py +1 -1
  8. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_persistence.py +98 -0
  9. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_run_once.py +90 -2
  10. voidx-3.6.0/src/tests/test_agent/graph/test_subagent_llm_retry.py +301 -0
  11. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_subagent_runner.py +1 -1
  12. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_tool_execution_auth.py +1 -1
  13. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_workflow_done.py +2 -5
  14. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_workflow_review.py +1 -1
  15. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_workflow_transactions_barrier.py +1 -1
  16. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_model.py +74 -0
  17. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_file_rwlock.py +36 -1
  18. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_goal_resolver.py +56 -8
  19. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_goal_resolver_advanced.py +65 -5
  20. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_permission.py +51 -6
  21. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_task_state.py +11 -2
  22. voidx-3.6.0/src/tests/test_agent/test_task_state_context_sync.py +93 -0
  23. voidx-3.6.0/src/tests/test_archive_script.py +180 -0
  24. voidx-3.6.0/src/tests/test_config/test_retry_config.py +95 -0
  25. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_install_sh.py +8 -3
  26. voidx-3.6.0/src/tests/test_llm/test_goal_resolver_retry.py +98 -0
  27. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_llm_provider.py +74 -1
  28. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_mcp/test_mcp.py +96 -1
  29. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_npm_package.py +1 -1
  30. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_runtime/test_runtime_ui.py +3 -1
  31. voidx-3.6.0/src/tests/test_selfupdate/test_selfupdate.py +245 -0
  32. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/bash/test_router_git.py +3 -3
  33. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/bash/test_router_safety.py +1 -1
  34. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/bash/test_router_sed_grep.py +7 -7
  35. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/bash/test_tool.py +7 -7
  36. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_coverage_fingerprint.py +27 -35
  37. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_anchors.py +3 -3
  38. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_bounds_input.py +3 -3
  39. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_coverage.py +3 -3
  40. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_dedup.py +3 -3
  41. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_drift_fallback.py +12 -12
  42. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_drift_fallback_e2e.py +3 -3
  43. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_errors.py +3 -3
  44. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_line_insert.py +10 -10
  45. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_llm_messages.py +3 -3
  46. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_replace.py +88 -3
  47. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_edit_trailing_newline.py +3 -3
  48. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_read.py +9 -9
  49. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_read_write.py +9 -9
  50. voidx-3.6.0/src/tests/test_tools/file/test_render_numbered_diff.py +59 -0
  51. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/test_write_file.py +32 -13
  52. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_clarify_tool.py +6 -6
  53. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_diffing.py +28 -2
  54. voidx-3.6.0/src/tests/test_tools/test_file_tools_redesign.py +390 -0
  55. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_infer_state_patch.py +6 -6
  56. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_interactive_tools.py +8 -6
  57. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_interactive_tools_write.py +8 -6
  58. voidx-3.6.0/src/tests/test_tools/test_load_doc_template.py +164 -0
  59. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_make_interact_callback.py +6 -6
  60. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_plan_checkpoint.py +6 -6
  61. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_replace_failure_logging.py +8 -10
  62. voidx-3.6.0/src/tests/test_tools/test_retry.py +176 -0
  63. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_search.py +6 -6
  64. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_state_update_from_executed_tools.py +6 -6
  65. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_task_tracker.py +6 -6
  66. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_tool_error_handling.py +10 -10
  67. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_tool_registry.py +6 -6
  68. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_tool_schemas.py +6 -6
  69. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_tool_state_patch.py +6 -6
  70. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_user_interaction_models.py +6 -6
  71. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_web_mcp.py +5 -5
  72. voidx-3.6.0/src/tests/test_tools/test_webfetch.py +286 -0
  73. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_workflow_tool.py +218 -36
  74. voidx-3.6.0/src/tests/test_ui/gateway/test_gateway_headless_frontend.py +80 -0
  75. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_gateway_v2_dispatch.py +117 -2
  76. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_gateway_v2_routing.py +46 -6
  77. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_gateway_v2_session.py +60 -0
  78. voidx-3.6.0/src/tests/test_ui/gateway/test_guidance_fallback.py +116 -0
  79. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_events_dock_status.py +50 -2
  80. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_events_streaming.py +1 -1
  81. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_gateway.py +35 -2
  82. voidx-3.6.0/src/tests/test_wheel_build.py +94 -0
  83. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_workflow/test_auto_advance.py +27 -0
  84. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/__init__.py +1 -1
  85. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/goal_resolver.py +63 -38
  86. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/core/helpers.py +3 -0
  87. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/core/voidx_graph.py +43 -0
  88. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/permissions.py +0 -1
  89. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/run_loop.py +57 -51
  90. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/subagent.py +46 -7
  91. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/executor.py +62 -1
  92. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/helpers.py +18 -0
  93. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/turn_runner.py +13 -0
  94. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/message_trimming.py +1 -1
  95. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/handler.py +1 -1
  96. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/model.py +27 -75
  97. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/__init__.py +2 -0
  98. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/models.py +12 -0
  99. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings.py +3 -0
  100. voidx-3.6.0/src/voidx/config/settings_retry.py +28 -0
  101. voidx-3.6.0/src/voidx/data/documents/README.md +12 -0
  102. voidx-3.6.0/src/voidx/data/documents/templates/readme.md +9 -0
  103. voidx-3.6.0/src/voidx/data/documents/voidx-guide/README.md +17 -0
  104. voidx-3.6.0/src/voidx/data/documents/voidx-guide/context.md +13 -0
  105. voidx-3.6.0/src/voidx/data/documents/voidx-guide/debug.md +9 -0
  106. voidx-3.6.0/src/voidx/data/documents/voidx-guide/extension.md +34 -0
  107. voidx-3.6.0/src/voidx/data/documents/voidx-guide/mode.md +14 -0
  108. voidx-3.6.0/src/voidx/data/documents/voidx-guide/model.md +16 -0
  109. voidx-3.6.0/src/voidx/data/documents/voidx-guide/permission.md +33 -0
  110. voidx-3.6.0/src/voidx/data/documents/voidx-guide/preferences.md +12 -0
  111. voidx-3.6.0/src/voidx/data/documents/voidx-guide/quickstart.md +40 -0
  112. voidx-3.6.0/src/voidx/data/documents/voidx-guide/reference.md +29 -0
  113. voidx-3.6.0/src/voidx/data/documents/voidx-guide/session.md +19 -0
  114. voidx-3.6.0/src/voidx/data/documents/voidx-guide/upgrade.md +10 -0
  115. voidx-3.6.0/src/voidx/data/documents/voidx-guide/web.md +11 -0
  116. voidx-3.6.0/src/voidx/data/documents/voidx-guide/workflow.md +24 -0
  117. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/diffing.py +24 -0
  118. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/provider.py +79 -24
  119. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/client/base.py +41 -25
  120. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/client/stdio_transport.py +1 -0
  121. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/manager.py +2 -1
  122. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp_servers/web.py +1 -2
  123. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/engine.py +7 -5
  124. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/rules.py +49 -6
  125. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/task_state.py +9 -1
  126. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/ui.py +5 -1
  127. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/selfupdate.py +109 -15
  128. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/hint/file.py +4 -4
  129. voidx-3.6.0/src/voidx/tools/document.py +135 -0
  130. {voidx-3.5.1/src/voidx/tools/file_ops → voidx-3.6.0/src/voidx/tools/file}/__init__.py +6 -3
  131. voidx-3.6.0/src/voidx/tools/file/manage.py +277 -0
  132. {voidx-3.5.1/src/voidx/tools/file_ops → voidx-3.6.0/src/voidx/tools/file}/read.py +1 -1
  133. voidx-3.5.1/src/voidx/tools/file_ops/edit_execute.py → voidx-3.6.0/src/voidx/tools/file/replace.py +51 -7
  134. voidx-3.5.1/src/voidx/tools/file_ops/edit_resolve.py → voidx-3.6.0/src/voidx/tools/file/replace_resolve.py +2 -2
  135. {voidx-3.5.1/src/voidx/tools/file_ops → voidx-3.6.0/src/voidx/tools/file}/write.py +65 -31
  136. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/lsp.py +1 -1
  137. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/registry.py +9 -9
  138. voidx-3.6.0/src/voidx/tools/retry.py +43 -0
  139. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/shell/common.py +1 -1
  140. voidx-3.6.0/src/voidx/tools/web/__init__.py +13 -0
  141. voidx-3.5.1/src/voidx/tools/webfetch.py → voidx-3.6.0/src/voidx/tools/web/fetch.py +29 -5
  142. voidx-3.5.1/src/voidx/tools/websearch.py → voidx-3.6.0/src/voidx/tools/web/search.py +2 -2
  143. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/workflow.py +84 -31
  144. voidx-3.6.0/src/voidx/ui/gateway/__init__.py +13 -0
  145. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/adapter.py +1 -0
  146. voidx-3.6.0/src/voidx/ui/gateway/frontend.py +206 -0
  147. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/run_manager.py +10 -0
  148. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/core.py +85 -14
  149. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/method/sessions.py +22 -4
  150. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/method/settings.py +9 -0
  151. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/console/streaming.py +9 -2
  152. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/app.py +5 -0
  153. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/stream.py +21 -6
  154. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/events/bus.py +5 -1
  155. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/events/consumers.py +42 -12
  156. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/types.py +0 -3
  157. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/requests.py +1 -0
  158. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/nodes.py +2 -2
  159. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/runtime.py +1 -0
  160. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/types.py +3 -0
  161. {voidx-3.5.1 → voidx-3.6.0/src/voidx.egg-info}/PKG-INFO +1 -1
  162. {voidx-3.5.1 → voidx-3.6.0}/src/voidx.egg-info/SOURCES.txt +66 -37
  163. voidx-3.5.1/src/tests/test_selfupdate/test_selfupdate.py +0 -103
  164. voidx-3.5.1/src/tests/test_tools/test_load_doc_template.py +0 -68
  165. voidx-3.5.1/src/tests/test_tools/test_webfetch.py +0 -157
  166. voidx-3.5.1/src/voidx/data/templates/readme.md +0 -55
  167. voidx-3.5.1/src/voidx/tools/file_ops/file.py +0 -187
  168. voidx-3.5.1/src/voidx/tools/load_doc_template.py +0 -67
  169. voidx-3.5.1/src/voidx/tools/load_skills.py +0 -12
  170. voidx-3.5.1/src/voidx/ui/gateway/__init__.py +0 -6
  171. {voidx-3.5.1 → voidx-3.6.0}/LICENSE +0 -0
  172. {voidx-3.5.1 → voidx-3.6.0}/README.md +0 -0
  173. {voidx-3.5.1 → voidx-3.6.0}/setup.cfg +0 -0
  174. {voidx-3.5.1 → voidx-3.6.0}/src/tests/__init__.py +0 -0
  175. {voidx-3.5.1 → voidx-3.6.0}/src/tests/conftest.py +0 -0
  176. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/__init__.py +0 -0
  177. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/conftest.py +0 -0
  178. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/__init__.py +0 -0
  179. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/run_loop_helpers.py +0 -0
  180. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/stream_llm_helpers.py +0 -0
  181. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_call_llm_compaction.py +0 -0
  182. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_call_llm_compaction_advanced.py +0 -0
  183. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_call_llm_tools.py +0 -0
  184. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_compaction_flow.py +0 -0
  185. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_compaction_flow_run_once.py +0 -0
  186. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_convergence.py +0 -0
  187. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_execute_tools_todo.py +0 -0
  188. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_graph_setup_prompts.py +0 -0
  189. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_guards_tool_op.py +0 -0
  190. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_parallel_subagents.py +0 -0
  191. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_parallel_subagents_dedup.py +0 -0
  192. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_run_loop_title_lsp.py +0 -0
  193. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_run_loop_title_misc.py +0 -0
  194. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_run_loop_workflow_advanced.py +0 -0
  195. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_runtime_guards.py +0 -0
  196. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_context_frames.py +0 -0
  197. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_crud.py +0 -0
  198. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_messages.py +0 -0
  199. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_runtime_state.py +0 -0
  200. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_session_transcript.py +0 -0
  201. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_stream_llm_sanitization.py +0 -0
  202. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_subagent_persistence.py +0 -0
  203. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_subagent_step_budget.py +0 -0
  204. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_subagent_step_budget_convergence.py +0 -0
  205. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_subagent_step_budget_final.py +0 -0
  206. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_todo_events.py +0 -0
  207. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_tool_result_preview.py +0 -0
  208. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/graph/test_workflow_transactions.py +0 -0
  209. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/__init__.py +0 -0
  210. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_init.py +0 -0
  211. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_mcp.py +0 -0
  212. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_model_advanced.py +0 -0
  213. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_session.py +0 -0
  214. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_skills.py +0 -0
  215. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_tavily.py +0 -0
  216. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/slash/test_slash_upgrade.py +0 -0
  217. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_attachments.py +0 -0
  218. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_message_trimming_parsers.py +0 -0
  219. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_message_trimming_rules.py +0 -0
  220. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_module_boundaries.py +0 -0
  221. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_permission_append.py +0 -0
  222. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_prompts.py +0 -0
  223. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_runtime_context_builder.py +0 -0
  224. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_runtime_context_prompts.py +0 -0
  225. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_runtime_context_skill_stripping.py +0 -0
  226. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_task_state_rendering.py +0 -0
  227. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_todo_replay_sanitization.py +0 -0
  228. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_tool_exchange_sanitizer.py +0 -0
  229. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_tool_filters_gemini.py +0 -0
  230. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_tool_messages.py +0 -0
  231. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_agent/test_tool_result_storage.py +0 -0
  232. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_config/__init__.py +0 -0
  233. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_config/test_config.py +0 -0
  234. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_config/test_config_advanced.py +0 -0
  235. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/conftest.py +0 -0
  236. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_compaction_retry.py +0 -0
  237. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_fallback_summary.py +0 -0
  238. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_gemini_provider.py +0 -0
  239. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_instruction_cache.py +0 -0
  240. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_llm_catalog.py +0 -0
  241. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_llm_provider_advanced.py +0 -0
  242. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_llm_usage.py +0 -0
  243. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_overflow_threshold.py +0 -0
  244. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_prune_args.py +0 -0
  245. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_request_log.py +0 -0
  246. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_streaming_sanitize.py +0 -0
  247. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_llm/test_token_counting.py +0 -0
  248. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_logging/test_internal_error.py +0 -0
  249. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_logging/test_tool_log.py +0 -0
  250. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_lsp/__init__.py +0 -0
  251. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_lsp/test_lsp.py +0 -0
  252. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_lsp/test_lsp_advanced.py +0 -0
  253. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_mcp/__init__.py +0 -0
  254. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_memory/__init__.py +0 -0
  255. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_memory/test_main.py +0 -0
  256. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_memory/test_main_startup.py +0 -0
  257. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_memory/test_schema_migration.py +0 -0
  258. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_permission/__init__.py +0 -0
  259. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_runtime/__init__.py +0 -0
  260. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_runtime/test_goal_resolution_refactor.py +0 -0
  261. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_selfupdate/__init__.py +0 -0
  262. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_skills/__init__.py +0 -0
  263. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_skills/conftest.py +0 -0
  264. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_skills/test_create_skill.py +0 -0
  265. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_skills/test_skill_parsing.py +0 -0
  266. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_skills/test_skill_references.py +0 -0
  267. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_skills/test_workflow_advance.py +0 -0
  268. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/__init__.py +0 -0
  269. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/bash/__init__.py +0 -0
  270. {voidx-3.5.1/src/tests/test_tools/file_ops → voidx-3.6.0/src/tests/test_tools/file}/__init__.py +0 -0
  271. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_git_tool_destructive.py +0 -0
  272. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_git_tool_raw_permissions.py +0 -0
  273. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_git_tool_schema_errors.py +0 -0
  274. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_git_tool_structured.py +0 -0
  275. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_powershell_tool.py +0 -0
  276. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_resolve_safe.py +0 -0
  277. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_skills_tool.py +0 -0
  278. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_tools/test_todo_tool.py +0 -0
  279. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/__init__.py +0 -0
  280. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/conftest.py +0 -0
  281. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/helpers.py +0 -0
  282. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_adapter.py +0 -0
  283. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_diff_review.py +0 -0
  284. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_gateway_v2_crud_diff.py +0 -0
  285. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_gateway_v2_server.py +0 -0
  286. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_run_manager.py +0 -0
  287. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_terminal.py +0 -0
  288. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_events_dock_bus.py +0 -0
  289. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_events_dock_prompts.py +0 -0
  290. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_events_subagent.py +0 -0
  291. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/gateway/test_ui_events_todo.py +0 -0
  292. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/__init__.py +0 -0
  293. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_dock_formatting.py +0 -0
  294. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_fmt_args.py +0 -0
  295. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_output_browse.py +0 -0
  296. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_scrollback_flush.py +0 -0
  297. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_tree_smoke.py +0 -0
  298. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_ui_diff.py +0 -0
  299. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/output/test_ui_session_changes.py +0 -0
  300. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/protocol/__init__.py +0 -0
  301. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/protocol/test_dto.py +0 -0
  302. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/protocol/test_v2_envelope.py +0 -0
  303. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/protocol/test_v2_methods.py +0 -0
  304. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/protocol/test_v2_snapshot.py +0 -0
  305. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/protocol/test_v2_threads.py +0 -0
  306. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/test_display_policy.py +0 -0
  307. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/test_file_picker.py +0 -0
  308. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/tools/__init__.py +0 -0
  309. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/tools/test_clipboard_image.py +0 -0
  310. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/tools/test_clipboard_image_windows.py +0 -0
  311. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/tools/test_clipboard_text.py +0 -0
  312. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/tools/test_clipboard_text_windows.py +0 -0
  313. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_ui/tools/test_code_ide.py +0 -0
  314. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_workflow/__init__.py +0 -0
  315. {voidx-3.5.1 → voidx-3.6.0}/src/tests/test_workflow/test_workflow_reconcile.py +0 -0
  316. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/__init__.py +0 -0
  317. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/agents.py +0 -0
  318. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/attachments.py +0 -0
  319. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/__init__.py +0 -0
  320. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/compaction.py +0 -0
  321. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/compaction_coordinator.py +0 -0
  322. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/contracts.py +0 -0
  323. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/convergence.py +0 -0
  324. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/core/__init__.py +0 -0
  325. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/core/llm.py +0 -0
  326. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/runtime.py +0 -0
  327. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/runtime_guards.py +0 -0
  328. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/session_mixin.py +0 -0
  329. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/session_runtime.py +0 -0
  330. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/streaming.py +0 -0
  331. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/thread_context.py +0 -0
  332. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/title_mixin.py +0 -0
  333. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/todo_events.py +0 -0
  334. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_execution.py +0 -0
  335. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/__init__.py +0 -0
  336. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/guards.py +0 -0
  337. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/types.py +0 -0
  338. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/ui.py +0 -0
  339. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/tool_executor/workflow.py +0 -0
  340. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/topology.py +0 -0
  341. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/transcript_mixin.py +0 -0
  342. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/turn_mixin.py +0 -0
  343. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/wiring.py +0 -0
  344. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/graph/workflow_utils.py +0 -0
  345. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/message_rows.py +0 -0
  346. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/prompts.py +0 -0
  347. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/runtime_context.py +0 -0
  348. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/__init__.py +0 -0
  349. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/code_ide.py +0 -0
  350. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/guide.py +0 -0
  351. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/host.py +0 -0
  352. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/init.py +0 -0
  353. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/lsp.py +0 -0
  354. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/mcp.py +0 -0
  355. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/profile.py +0 -0
  356. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/runtime.py +0 -0
  357. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/session.py +0 -0
  358. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/skills.py +0 -0
  359. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/slash/upgrade.py +0 -0
  360. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/state.py +0 -0
  361. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/task_state.py +0 -0
  362. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/todo_state.py +0 -0
  363. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/tool_call_ids.py +0 -0
  364. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/tool_exchange_sanitizer.py +0 -0
  365. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/tool_filters.py +0 -0
  366. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/tool_messages.py +0 -0
  367. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/agent/tool_result_storage.py +0 -0
  368. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/defaults.py +0 -0
  369. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/enums.py +0 -0
  370. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/permissions.py +0 -0
  371. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_agent.py +0 -0
  372. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_api_keys.py +0 -0
  373. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_code_ide.py +0 -0
  374. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_custom.py +0 -0
  375. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_mcp.py +0 -0
  376. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_permissions.py +0 -0
  377. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_skills.py +0 -0
  378. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_update.py +0 -0
  379. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_utils.py +0 -0
  380. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/config/settings_web.py +0 -0
  381. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/data/__init__.py +0 -0
  382. {voidx-3.5.1/src/voidx/data → voidx-3.6.0/src/voidx/data/documents}/templates/api-doc.md +0 -0
  383. {voidx-3.5.1/src/voidx/data → voidx-3.6.0/src/voidx/data/documents}/templates/prd.md +0 -0
  384. {voidx-3.5.1/src/voidx/data → voidx-3.6.0/src/voidx/data/documents}/templates/rfc.md +0 -0
  385. {voidx-3.5.1/src/voidx/data → voidx-3.6.0/src/voidx/data/documents}/templates/tech-design.md +0 -0
  386. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/__init__.py +0 -0
  387. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/catalog.py +0 -0
  388. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/compaction.py +0 -0
  389. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/context.py +0 -0
  390. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/instruction.py +0 -0
  391. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/message_markers.py +0 -0
  392. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/message_status.py +0 -0
  393. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/service.py +0 -0
  394. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/llm/usage.py +0 -0
  395. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/logging/__init__.py +0 -0
  396. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/logging/internal_error.py +0 -0
  397. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/logging/request_log.py +0 -0
  398. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/logging/tool_log.py +0 -0
  399. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/__init__.py +0 -0
  400. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/client.py +0 -0
  401. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/config.py +0 -0
  402. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/detector.py +0 -0
  403. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/detector_data.py +0 -0
  404. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/errors.py +0 -0
  405. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/manager.py +0 -0
  406. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/schema.py +0 -0
  407. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/lsp/service.py +0 -0
  408. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/main.py +0 -0
  409. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/__init__.py +0 -0
  410. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/client/__init__.py +0 -0
  411. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/client/errors.py +0 -0
  412. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/client/http_transport.py +0 -0
  413. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/client/sse_transport.py +0 -0
  414. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/schema.py +0 -0
  415. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp/tool.py +0 -0
  416. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/mcp_servers/__init__.py +0 -0
  417. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/__init__.py +0 -0
  418. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/cleanup.py +0 -0
  419. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/context_frames.py +0 -0
  420. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/jsonl_store.py +0 -0
  421. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/model_profiles.py +0 -0
  422. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/runtime_state.py +0 -0
  423. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/service.py +0 -0
  424. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/session.py +0 -0
  425. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/store.py +0 -0
  426. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/subagents.py +0 -0
  427. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/memory/transcript.py +0 -0
  428. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/paths.py +0 -0
  429. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/__init__.py +0 -0
  430. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/context.py +0 -0
  431. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/evaluate.py +0 -0
  432. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/sandbox.py +0 -0
  433. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/schema.py +0 -0
  434. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/service.py +0 -0
  435. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/permission/wildcard.py +0 -0
  436. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/__init__.py +0 -0
  437. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/attachments.py +0 -0
  438. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/intent.py +0 -0
  439. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/reference_tokens.py +0 -0
  440. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/todo.py +0 -0
  441. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/runtime/ui_port.py +0 -0
  442. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/skills/__init__.py +0 -0
  443. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/skills/context.py +0 -0
  444. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/skills/references.py +0 -0
  445. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/skills/registry.py +0 -0
  446. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/skills/schema.py +0 -0
  447. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/skills/service.py +0 -0
  448. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/__init__.py +0 -0
  449. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/agent.py +0 -0
  450. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/base.py +0 -0
  451. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/__init__.py +0 -0
  452. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/core.py +0 -0
  453. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/hint/__init__.py +0 -0
  454. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/hint/git.py +0 -0
  455. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/hint/search.py +0 -0
  456. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/router.py +0 -0
  457. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/safety.py +0 -0
  458. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/bash/tool.py +0 -0
  459. /voidx-3.5.1/src/voidx/tools/plan_checkpoint.py → /voidx-3.6.0/src/voidx/tools/checkpoint.py +0 -0
  460. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/clarify.py +0 -0
  461. /voidx-3.5.1/src/voidx/tools/compact_context.py → /voidx-3.6.0/src/voidx/tools/compact.py +0 -0
  462. /voidx-3.5.1/src/voidx/tools/file_state.py → /voidx-3.6.0/src/voidx/tools/file/state.py +0 -0
  463. {voidx-3.5.1/src/voidx/tools/file_ops → voidx-3.6.0/src/voidx/tools/file}/types.py +0 -0
  464. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/git.py +0 -0
  465. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/__init__.py +0 -0
  466. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/core.py +0 -0
  467. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/hint/__init__.py +0 -0
  468. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/hint/file.py +0 -0
  469. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/hint/search.py +0 -0
  470. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/router.py +0 -0
  471. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/safety.py +0 -0
  472. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/sandbox.py +0 -0
  473. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/powershell/tool.py +0 -0
  474. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/search.py +0 -0
  475. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/service.py +0 -0
  476. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/shell/__init__.py +0 -0
  477. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/shell/hint/__init__.py +0 -0
  478. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/shell/hint/git.py +0 -0
  479. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/skills.py +0 -0
  480. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/task_status.py +0 -0
  481. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/task_tracker.py +0 -0
  482. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/tools/todo.py +0 -0
  483. /voidx-3.5.1/src/voidx/tools/web_content.py → /voidx-3.6.0/src/voidx/tools/web/content.py +0 -0
  484. /voidx-3.5.1/src/voidx/tools/web_mcp.py → /voidx-3.6.0/src/voidx/tools/web/mcp.py +0 -0
  485. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/__init__.py +0 -0
  486. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/command_catalog.py +0 -0
  487. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/commands.py +0 -0
  488. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/frontend.py +0 -0
  489. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/bootstrap.py +0 -0
  490. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/diff_review.py +0 -0
  491. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/server.py +0 -0
  492. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/__init__.py +0 -0
  493. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/consumer.py +0 -0
  494. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/method/__init__.py +0 -0
  495. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/method/diff.py +0 -0
  496. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/method/integrations.py +0 -0
  497. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/session/method/terminal.py +0 -0
  498. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/gateway/terminal.py +0 -0
  499. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/__init__.py +0 -0
  500. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/agent_display.py +0 -0
  501. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/ansi_marker.py +0 -0
  502. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/browse.py +0 -0
  503. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/capture.py +0 -0
  504. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/console/__init__.py +0 -0
  505. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/console/app.py +0 -0
  506. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/console/formatting.py +0 -0
  507. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/diff.py +0 -0
  508. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/display_policy.py +0 -0
  509. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/__init__.py +0 -0
  510. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/agent_placeholder.py +0 -0
  511. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/formatting.py +0 -0
  512. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/nodes.py +0 -0
  513. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/nodes_checkpoint.py +0 -0
  514. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/nodes_clarify.py +0 -0
  515. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/nodes_permission.py +0 -0
  516. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/nodes_startup.py +0 -0
  517. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/nodes_status.py +0 -0
  518. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/state.py +0 -0
  519. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/status.py +0 -0
  520. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/dock/todo.py +0 -0
  521. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/events/__init__.py +0 -0
  522. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/events/schema.py +0 -0
  523. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/output/tree.py +0 -0
  524. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/__init__.py +0 -0
  525. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/commands.py +0 -0
  526. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/schema.py +0 -0
  527. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/transcript.py +0 -0
  528. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/v2/__init__.py +0 -0
  529. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/v2/envelope.py +0 -0
  530. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/v2/methods.py +0 -0
  531. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/v2/snapshot.py +0 -0
  532. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/protocol/v2/threads.py +0 -0
  533. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/session.py +0 -0
  534. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/__init__.py +0 -0
  535. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/attachment_tokens.py +0 -0
  536. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/clipboard_image.py +0 -0
  537. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/clipboard_text.py +0 -0
  538. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/code_ide.py +0 -0
  539. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/file_picker.py +0 -0
  540. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/tools/skill_picker.py +0 -0
  541. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/ui/transcript.py +0 -0
  542. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/__init__.py +0 -0
  543. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/auto_advance.py +0 -0
  544. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/context.py +0 -0
  545. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/dag.py +0 -0
  546. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/policy.py +0 -0
  547. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/reconcile.py +0 -0
  548. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/render.py +0 -0
  549. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/route.py +0 -0
  550. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/schema.py +0 -0
  551. {voidx-3.5.1 → voidx-3.6.0}/src/voidx/workflow/service.py +0 -0
  552. {voidx-3.5.1 → voidx-3.6.0}/src/voidx.egg-info/dependency_links.txt +0 -0
  553. {voidx-3.5.1 → voidx-3.6.0}/src/voidx.egg-info/entry_points.txt +0 -0
  554. {voidx-3.5.1 → voidx-3.6.0}/src/voidx.egg-info/requires.txt +0 -0
  555. {voidx-3.5.1 → voidx-3.6.0}/src/voidx.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: voidx
3
- Version: 3.5.1
3
+ Version: 3.6.0
4
4
  Summary: A coding agent that quantifies everything and solves with tools, not fuzzy prompts.
5
5
  Author: chikhamx
6
6
  License: MIT
@@ -55,7 +55,7 @@ where = ["src"]
55
55
  "bundled/*/SKILL.md",
56
56
  ]
57
57
  "voidx.data" = [
58
- "templates/*.md",
58
+ "documents/**/*.md",
59
59
  ]
60
60
 
61
61
  [tool.pytest.ini_options]
@@ -49,7 +49,7 @@ from voidx.tools.base import ToolContext, ToolResult
49
49
  from voidx.tools.agent import AgentResultContract, AgentTool
50
50
  from voidx.tools.registry import ToolRegistry
51
51
  from voidx.ui.output.dock import BottomInputDock, set_dock
52
- from voidx.ui.output.events import DockEventConsumer, TurnStarted, ui_events
52
+ from voidx.ui.output.events import DockEventConsumer, StatusUpdated, ToolResultAppended, TurnStarted, ui_events
53
53
 
54
54
 
55
55
  def _graph(tmp_path):
@@ -669,3 +669,130 @@ async def test_execute_tools_terminates_turn_when_tool_started_notification_time
669
669
  and "UI event bus timed out" in str(message.content)
670
670
  for message in result["messages"]
671
671
  )
672
+
673
+
674
+ @pytest.mark.asyncio
675
+ async def test_execute_tools_returns_tool_error_when_result_rendering_fails(tmp_path, monkeypatch):
676
+ graph = _graph(tmp_path)
677
+
678
+ class FakeReadTool:
679
+ id = "read"
680
+ description = "fake read"
681
+
682
+ def parameters_schema(self):
683
+ return {"type": "object", "properties": {}}
684
+
685
+ async def execute(self, args: dict, ctx: ToolContext) -> ToolResult:
686
+ return ToolResult(output="File not found: missing.py", metadata={"error": True})
687
+
688
+ class FailingResultConsumer:
689
+ def handle(self, event):
690
+ if isinstance(event, ToolResultAppended):
691
+ raise RuntimeError("render exploded")
692
+ return None
693
+
694
+ graph.tools.register("read", FakeReadTool(), "fake read", {"type": "object", "properties": {}})
695
+
696
+ async def allow_all(
697
+ tool_calls,
698
+ plan_mode: bool,
699
+ session_id: str,
700
+ interaction_mode=None,
701
+ workflow_runs=None,
702
+ runtime_persona=None,
703
+ ):
704
+ return tool_calls, []
705
+
706
+ graph._authorize_tool_calls = allow_all
707
+ monkeypatch.setattr(graph._ui, "via_events", lambda: True)
708
+ graph._ui.events.start(FailingResultConsumer())
709
+
710
+ parent = AIMessage(
711
+ content="",
712
+ tool_calls=[{"name": "read", "args": {"file_path": "missing.py"}, "id": "call_read", "type": "tool_call"}],
713
+ )
714
+
715
+ try:
716
+ result = await graph._execute_tools({
717
+ "messages": [parent],
718
+ "workspace": str(tmp_path),
719
+ "persona": "voidx",
720
+ "plan_mode": False,
721
+ })
722
+ finally:
723
+ await graph._ui.events.stop()
724
+
725
+ assert result["messages"][0].tool_call_id == "call_read"
726
+ assert result["messages"][0].status == "error"
727
+ assert result["messages"][0].content == "File not found: missing.py"
728
+
729
+
730
+ @pytest.mark.asyncio
731
+ async def test_execute_tools_emits_heartbeat_while_tool_is_still_running(tmp_path, monkeypatch):
732
+ from voidx.agent.graph.tool_executor import executor as executor_module
733
+
734
+ graph = _graph(tmp_path)
735
+ emitted: list = []
736
+
737
+ class SlowReadTool:
738
+ id = "read"
739
+ description = "slow read"
740
+
741
+ def parameters_schema(self):
742
+ return {"type": "object", "properties": {}}
743
+
744
+ async def execute(self, args: dict, ctx: ToolContext) -> ToolResult:
745
+ await asyncio.sleep(0.03)
746
+ return ToolResult(output="read output")
747
+
748
+ graph.tools.register("read", SlowReadTool(), "slow read", {"type": "object", "properties": {}})
749
+
750
+ async def allow_all(
751
+ tool_calls,
752
+ plan_mode: bool,
753
+ session_id: str,
754
+ interaction_mode=None,
755
+ workflow_runs=None,
756
+ runtime_persona=None,
757
+ ):
758
+ return tool_calls, []
759
+
760
+ async def fake_request(event):
761
+ emitted.append(event)
762
+ return None
763
+
764
+ async def fake_emit(event):
765
+ emitted.append(event)
766
+ return True
767
+
768
+ async def fake_drain():
769
+ return None
770
+
771
+ graph._authorize_tool_calls = allow_all
772
+ monkeypatch.setattr(graph._ui, "via_events", lambda: True)
773
+ monkeypatch.setattr(graph._ui.events, "request", fake_request)
774
+ monkeypatch.setattr(graph._ui.events, "emit", fake_emit)
775
+ monkeypatch.setattr(graph._ui.events, "drain", fake_drain)
776
+ monkeypatch.setattr(executor_module, "TOOL_HEARTBEAT_INITIAL_SECONDS", 0.01)
777
+ monkeypatch.setattr(executor_module, "TOOL_HEARTBEAT_INTERVAL_SECONDS", 0.01)
778
+
779
+ parent = AIMessage(
780
+ content="",
781
+ tool_calls=[{"name": "read", "args": {}, "id": "call_read", "type": "tool_call"}],
782
+ )
783
+
784
+ result = await graph._execute_tools({
785
+ "messages": [parent],
786
+ "workspace": str(tmp_path),
787
+ "persona": "voidx",
788
+ "plan_mode": False,
789
+ })
790
+
791
+ heartbeats = [
792
+ event for event in emitted
793
+ if isinstance(event, StatusUpdated)
794
+ and event.status_id == "tool-heartbeat:call_read"
795
+ ]
796
+ assert heartbeats
797
+ assert "read still running" in heartbeats[0].detail
798
+ assert result["messages"][0].content == "read output"
@@ -459,19 +459,23 @@ async def test_permission_prompt_uses_dock_details_when_events_are_active(tmp_pa
459
459
  choice = await graph._ask_tool_permission([
460
460
  {
461
461
  "name": "bash",
462
- "args": {"command": "npm test"},
462
+ "args": {"command": "npm install lodash"},
463
463
  "id": "call_1",
464
464
  }
465
465
  ])
466
466
  await graph._ui.events.drain()
467
467
 
468
468
  assert choice == "y"
469
- assert received_details is None
469
+ assert received_details == [{
470
+ "name": "bash",
471
+ "pattern": "npm install lodash",
472
+ "args": {"command": "npm install lodash"},
473
+ }]
470
474
  record = test_dock.status_record("permission:request")
471
475
  assert record is not None
472
476
  assert record.label == "Requesting"
473
477
  assert "bash" in record.detail
474
- assert "npm test" in record.detail
478
+ assert "npm install lodash" in record.detail
475
479
  finally:
476
480
  await graph._ui.events.stop()
477
481
  test_dock.deactivate()
@@ -352,3 +352,49 @@ async def test_implement_subagent_injects_workflow_nodes(tmp_path, monkeypatch):
352
352
  not (isinstance(message, HumanMessage) and "## Runtime State" in str(message.content))
353
353
  for message in captured["messages"]
354
354
  )
355
+
356
+
357
+
358
+ @pytest.mark.asyncio
359
+ async def test_prepare_does_not_reactivate_satisfied_workflow_via_stale_route(tmp_path):
360
+ """When a workflow tool advanced feedback->tdd, task_state.workflow_runs
361
+ has feedback=SATISFIED and tdd=ACTIVE. But workflow_route.join still
362
+ points at the old node (feedback) because workflow enter/advance does
363
+ not update the route. The LLM prepare step must not use the stale
364
+ route to reactivate feedback and overwrite its SATISFIED status."""
365
+ graph = VoidXGraph(
366
+ Config(workspace=str(tmp_path)),
367
+ api_key=None,
368
+ settings=Settings(str(tmp_path)),
369
+ )
370
+ result = await graph._prepare_with_stream({
371
+ "messages": [HumanMessage(content="继续实现")],
372
+ "workspace": str(tmp_path),
373
+ "persona": "implement",
374
+ "plan_mode": False,
375
+ "interaction_mode": "auto",
376
+ "task_state": TaskState(
377
+ current_intent=TaskIntent.CODING,
378
+ current_goal=GoalSpec(desc="实现 feature X"),
379
+ workflow_route=WorkflowRoute(join="feedback", leave=None),
380
+ workflow_runs={
381
+ "feedback": WorkflowRunState(
382
+ name="feedback",
383
+ status=WorkflowRunStatus.SATISFIED,
384
+ reason="transition from feedback via nontrivial_fix",
385
+ ),
386
+ "tdd": WorkflowRunState(
387
+ name="tdd",
388
+ status=WorkflowRunStatus.ACTIVE,
389
+ reason="transition from feedback via nontrivial_fix",
390
+ ),
391
+ },
392
+ ).model_dump(mode="json"),
393
+ "tool_results": {},
394
+ "step_count": 0,
395
+ "should_continue": True,
396
+ })
397
+
398
+ result_task_state = TaskState.model_validate(result["task_state"])
399
+ assert result_task_state.workflow_runs["tdd"].status == WorkflowRunStatus.ACTIVE
400
+ assert result_task_state.workflow_runs["feedback"].status == WorkflowRunStatus.SATISFIED
@@ -138,6 +138,162 @@ async def test_quiet_slash_command_dispatches_without_turn(monkeypatch):
138
138
  assert dispatched == ["/model reasoning"]
139
139
 
140
140
 
141
+ @pytest.mark.asyncio
142
+ async def test_web_headless_uses_gateway_frontend_without_default_tui_factory(monkeypatch, tmp_path):
143
+ graph = _graph(workspace=str(tmp_path))
144
+ _disable_external_managers(graph)
145
+ monkeypatch.setattr(runtime_ui_port, "show_startup", lambda **_: None)
146
+
147
+ def fail_create_frontend(*_args, **_kwargs):
148
+ raise AssertionError("web_headless must not create the default TUI frontend")
149
+
150
+ class ExitHeadlessFrontend:
151
+ instances = []
152
+
153
+ def __init__(self, status, commands):
154
+ self.status = status
155
+ self.commands = commands
156
+ self.request_handler = None
157
+ ExitHeadlessFrontend.instances.append(self)
158
+
159
+ async def run_headless(self, on_submit):
160
+ return
161
+
162
+ def set_external_command_handler(self, handler):
163
+ self.command_handler = handler
164
+
165
+ def set_external_request_handler(self, handler):
166
+ self.request_handler = handler
167
+
168
+ monkeypatch.setattr("voidx.agent.graph.run_loop.create_frontend", fail_create_frontend)
169
+ monkeypatch.setattr("voidx.agent.graph.run_loop.GatewayHeadlessFrontend", ExitHeadlessFrontend)
170
+ monkeypatch.setattr("voidx.agent.graph.run_loop.emit_web_gateway_bootstrap", lambda _url: None)
171
+
172
+ test_dock = BottomInputDock()
173
+ set_dock(test_dock)
174
+ test_dock.begin_capture()
175
+ try:
176
+ await graph.run(web=True, web_headless=True)
177
+ finally:
178
+ test_dock.deactivate()
179
+ test_dock.reset()
180
+ set_dock(None)
181
+
182
+ assert len(ExitHeadlessFrontend.instances) == 1
183
+ assert ExitHeadlessFrontend.instances[0].request_handler is not None
184
+
185
+
186
+ @pytest.mark.asyncio
187
+ async def test_web_non_headless_falls_back_to_gateway_frontend_when_tui_unavailable(monkeypatch, tmp_path):
188
+ """--web without --web-headless should fall back to GatewayHeadlessFrontend
189
+ when voidx_cli is not installed, instead of crashing."""
190
+ graph = _graph(workspace=str(tmp_path))
191
+ _disable_external_managers(graph)
192
+ monkeypatch.setattr(runtime_ui_port, "show_startup", lambda **_: None)
193
+
194
+ class ExitHeadlessFrontend:
195
+ instances = []
196
+
197
+ def __init__(self, status, commands):
198
+ self.status = status
199
+ self.commands = commands
200
+ self.request_handler = None
201
+ ExitHeadlessFrontend.instances.append(self)
202
+
203
+ async def run(self, on_submit):
204
+ return
205
+
206
+ async def run_headless(self, on_submit):
207
+ return
208
+
209
+ def set_external_command_handler(self, handler):
210
+ self.command_handler = handler
211
+
212
+ def set_external_request_handler(self, handler):
213
+ self.request_handler = handler
214
+
215
+ def fail_create_frontend(*_args, **_kwargs):
216
+ raise RuntimeError("voidx_cli is required for terminal UI mode.")
217
+
218
+ monkeypatch.setattr("voidx.agent.graph.run_loop.create_frontend", fail_create_frontend)
219
+ monkeypatch.setattr("voidx.agent.graph.run_loop.GatewayHeadlessFrontend", ExitHeadlessFrontend)
220
+ monkeypatch.setattr("voidx.agent.graph.run_loop.emit_web_gateway_bootstrap", lambda _url: None)
221
+
222
+ test_dock = BottomInputDock()
223
+ set_dock(test_dock)
224
+ test_dock.begin_capture()
225
+ try:
226
+ await graph.run(web=True, web_headless=False)
227
+ finally:
228
+ test_dock.deactivate()
229
+ test_dock.reset()
230
+ set_dock(None)
231
+
232
+ assert len(ExitHeadlessFrontend.instances) == 1
233
+ assert ExitHeadlessFrontend.instances[0].request_handler is not None
234
+
235
+
236
+ @pytest.mark.asyncio
237
+ async def test_apply_settings_update_refreshes_live_model(monkeypatch, tmp_path):
238
+ from voidx.config import Profile, Settings
239
+
240
+ created_models: list[tuple[str | None, str, str, str | None]] = []
241
+
242
+ def fake_create_chat_model(api_key, model_config):
243
+ marker = SimpleNamespace(
244
+ api_key=api_key,
245
+ provider=model_config.provider,
246
+ model=model_config.model,
247
+ base_url=model_config.base_url,
248
+ )
249
+ created_models.append((api_key, model_config.provider, model_config.model, model_config.base_url))
250
+ return marker
251
+
252
+ monkeypatch.setattr("voidx.agent.graph.core.voidx_graph.create_chat_model", fake_create_chat_model)
253
+
254
+ settings = await Settings.create(str(tmp_path))
255
+ await settings.save_profile(
256
+ Profile(
257
+ name="deepseek/deepseek-v4-pro",
258
+ api_key="sk-deepseek",
259
+ base_url="https://api.deepseek.com",
260
+ protocol="openai",
261
+ )
262
+ )
263
+ graph = VoidXGraph(
264
+ Config(workspace=str(tmp_path), model=ModelConfig(provider="openai", model="gpt-4.1")),
265
+ api_key="sk-openai",
266
+ settings=settings,
267
+ )
268
+
269
+ graph._app = SimpleNamespace(
270
+ status=SimpleNamespace(
271
+ provider="openai",
272
+ model="gpt-4.1",
273
+ context_limit=0,
274
+ reasoning_effort="xhigh",
275
+ )
276
+ )
277
+
278
+ await graph._apply_settings_update(settings)
279
+
280
+ assert graph.config.workspace == str(tmp_path)
281
+ assert graph.config.model.provider == "deepseek"
282
+ assert graph.config.model.model == "deepseek-v4-pro"
283
+ assert graph.config.model.base_url == "https://api.deepseek.com"
284
+ assert graph.api_key == "sk-deepseek"
285
+ assert graph.model.provider == "deepseek"
286
+ assert graph.model.model == "deepseek-v4-pro"
287
+ assert created_models[-1] == (
288
+ "sk-deepseek",
289
+ "deepseek",
290
+ "deepseek-v4-pro",
291
+ "https://api.deepseek.com",
292
+ )
293
+ assert graph._app.status.provider == "deepseek"
294
+ assert graph._app.status.model == "deepseek-v4-pro"
295
+
296
+
141
297
  @pytest.mark.asyncio
142
298
  async def test_web_guide_submit_records_guidance_without_starting_turn():
143
299
  graph = _graph()
@@ -117,7 +117,7 @@ async def test_run_once_uses_general_fallback_when_structured_resolver_fails(tmp
117
117
 
118
118
  initial = captured["initial"]
119
119
  assert initial["task_state"]["current_intent"] == "general"
120
- assert initial["task_state"]["current_goal"] is None
120
+ assert initial["task_state"]["current_goal"] is not None
121
121
  assert initial["task_state"]["recent_exchanges"] == []
122
122
  rows = await load_messages(graph._session.id)
123
123
  assert [row.role for row in rows] == ["user", "assistant"]
@@ -261,6 +261,104 @@ async def test_run_once_loads_execution_context_runtime_state(tmp_path):
261
261
  await delete_session(active.id)
262
262
  await delete_session(target.id)
263
263
 
264
+
265
+ @pytest.mark.asyncio
266
+ async def test_run_once_model_enabled_first_turn_syncs_default_task_state(tmp_path):
267
+ from voidx.agent.runtime_context import InteractionMode
268
+
269
+ graph = VoidXGraph(Config(workspace=str(tmp_path)), api_key="test", session=None)
270
+ graph._interaction_mode = InteractionMode.GOAL
271
+ ready = asyncio.Event()
272
+ proceed = asyncio.Event()
273
+ seen: list[str | None] = []
274
+
275
+ class FakeGraph:
276
+ async def ainvoke(self, initial, _config):
277
+ ready.set()
278
+ await asyncio.wait_for(proceed.wait(), timeout=1)
279
+ return {"messages": list(initial["messages"]) + [AIMessage(content="first answer")], "task_state": initial["task_state"]}
280
+
281
+ async def external_reader():
282
+ await asyncio.wait_for(ready.wait(), timeout=1)
283
+ seen.append(graph._task_state.current_goal.desc if graph._task_state.current_goal else None)
284
+ proceed.set()
285
+
286
+ graph.graph = FakeGraph()
287
+ reader_task = asyncio.create_task(external_reader())
288
+
289
+ test_dock = BottomInputDock()
290
+ set_dock(test_dock)
291
+ test_dock.begin_capture()
292
+ try:
293
+ await graph._run_once("first question")
294
+ finally:
295
+ test_dock.deactivate()
296
+ test_dock.reset()
297
+ set_dock(None)
298
+
299
+ await reader_task
300
+ assert seen == ["first question"]
301
+
302
+
303
+ @pytest.mark.asyncio
304
+ async def test_run_once_model_enabled_borrowed_context_does_not_leak_task_state(tmp_path):
305
+ from voidx.agent.runtime_context import InteractionMode
306
+ from voidx.memory.runtime_state import RuntimeStateSnapshot, load_runtime_state, save_runtime_state
307
+ from voidx.ui.output.types import ThreadExecutionContext
308
+
309
+ active = await create_session(workspace=str(tmp_path), title="Active")
310
+ target = await create_session(workspace=str(tmp_path), title="Target")
311
+ try:
312
+ active_state = TaskState(current_goal=GoalSpec(desc="active goal"))
313
+ target_state = TaskState(current_goal=GoalSpec(desc="target goal"))
314
+ await save_runtime_state(active.id, RuntimeStateSnapshot(interaction_mode=InteractionMode.GOAL, task_state=active_state))
315
+ await save_runtime_state(target.id, RuntimeStateSnapshot(interaction_mode=InteractionMode.PLAN, task_state=target_state))
316
+
317
+ graph = VoidXGraph(Config(workspace=str(tmp_path)), api_key="test", session=active)
318
+ await graph._restore_runtime_state()
319
+ captured: dict[str, str] = {}
320
+
321
+ class FakeGraph:
322
+ async def ainvoke(self, initial, _config):
323
+ state = TaskState.model_validate(initial["task_state"])
324
+ captured["goal"] = state.current_goal.desc if state.current_goal else ""
325
+ captured["interaction_mode"] = initial["interaction_mode"]
326
+ updated_state = state.model_copy(update={"current_goal": GoalSpec(desc="target mutated goal")})
327
+ return {
328
+ "messages": list(initial["messages"]) + [AIMessage(content="target answer")],
329
+ "task_state": updated_state.model_dump(mode="json"),
330
+ }
331
+
332
+ graph.graph = FakeGraph()
333
+
334
+ test_dock = BottomInputDock()
335
+ set_dock(test_dock)
336
+ test_dock.begin_capture()
337
+ try:
338
+ await graph._run_once(
339
+ "target question",
340
+ context=ThreadExecutionContext(thread_id=target.id, session_id=target.id),
341
+ )
342
+ finally:
343
+ test_dock.deactivate()
344
+ test_dock.reset()
345
+ set_dock(None)
346
+
347
+ assert captured == {"goal": "target goal", "interaction_mode": "plan"}
348
+ assert graph._session.id == active.id
349
+ assert graph._task_state.current_goal is not None
350
+ assert graph._task_state.current_goal.desc == "active goal"
351
+ assert graph._interaction_mode == InteractionMode.GOAL
352
+
353
+ active_snapshot = await load_runtime_state(active.id)
354
+ target_snapshot = await load_runtime_state(target.id)
355
+ assert active_snapshot.task_state.current_goal is not None
356
+ assert active_snapshot.task_state.current_goal.desc == "active goal"
357
+ assert target_snapshot.task_state.current_goal is not None
358
+ assert target_snapshot.task_state.current_goal.desc == "target mutated goal"
359
+ finally:
360
+ await delete_session(active.id)
361
+ await delete_session(target.id)
264
362
  @pytest.mark.asyncio
265
363
  async def test_run_once_isolates_concurrent_execution_context_state(tmp_path):
266
364
  from voidx.agent.runtime_context import InteractionMode
@@ -49,7 +49,13 @@ from voidx.tools.base import ToolContext, ToolResult
49
49
  from voidx.tools.agent import AgentResultContract, AgentTool
50
50
  from voidx.tools.registry import ToolRegistry
51
51
  from voidx.ui.output.dock import BottomInputDock, set_dock
52
- from voidx.ui.output.events import DockEventConsumer, TurnStarted, ui_events
52
+ from voidx.ui.output.events import (
53
+ DockEventConsumer,
54
+ TurnCompleted,
55
+ TurnFailed,
56
+ TurnStarted,
57
+ ui_events,
58
+ )
53
59
 
54
60
 
55
61
  def _graph(tmp_path):
@@ -189,6 +195,89 @@ async def test_run_once_persists_and_restores_transcript_snapshot(tmp_path):
189
195
  await delete_session(session.id)
190
196
 
191
197
 
198
+ @pytest.mark.asyncio
199
+ async def test_run_once_emits_turn_completed_event(tmp_path):
200
+ session = await create_session(workspace=str(tmp_path))
201
+ events: list[object] = []
202
+
203
+ class RecordingConsumer:
204
+ def handle(self, event):
205
+ events.append(event)
206
+ if isinstance(event, TurnStarted):
207
+ return object()
208
+ return None
209
+
210
+ try:
211
+ graph = VoidXGraph(Config(workspace=str(tmp_path)), api_key=None, session=session)
212
+
213
+ class FakeGraph:
214
+ async def ainvoke(self, initial, _config):
215
+ return {"messages": list(initial["messages"]) + [AIMessage(content="done")]}
216
+
217
+ graph.graph = FakeGraph()
218
+
219
+ test_dock = BottomInputDock()
220
+ set_dock(test_dock)
221
+ test_dock.begin_capture()
222
+ ui_events.start(RecordingConsumer())
223
+ try:
224
+ await graph._run_once("hello")
225
+ await ui_events.drain()
226
+ finally:
227
+ await ui_events.stop()
228
+ test_dock.deactivate()
229
+ test_dock.reset()
230
+ set_dock(None)
231
+
232
+ assert any(isinstance(event, TurnCompleted) for event in events)
233
+ assert not any(isinstance(event, TurnFailed) for event in events)
234
+ finally:
235
+ await delete_session(session.id)
236
+
237
+
238
+ @pytest.mark.asyncio
239
+ async def test_run_once_emits_turn_failed_event_on_exception(tmp_path):
240
+ session = await create_session(workspace=str(tmp_path))
241
+ events: list[object] = []
242
+
243
+ class RecordingConsumer:
244
+ def handle(self, event):
245
+ events.append(event)
246
+ if isinstance(event, TurnStarted):
247
+ return object()
248
+ return None
249
+
250
+ try:
251
+ graph = VoidXGraph(Config(workspace=str(tmp_path)), api_key=None, session=session)
252
+
253
+ class FakeGraph:
254
+ async def ainvoke(self, initial, _config):
255
+ raise RuntimeError("provider failed")
256
+
257
+ graph.graph = FakeGraph()
258
+
259
+ test_dock = BottomInputDock()
260
+ set_dock(test_dock)
261
+ test_dock.begin_capture()
262
+ ui_events.start(RecordingConsumer())
263
+ try:
264
+ with pytest.raises(RuntimeError, match="provider failed"):
265
+ await graph._run_once("hello")
266
+ await ui_events.drain()
267
+ finally:
268
+ await ui_events.stop()
269
+ test_dock.deactivate()
270
+ test_dock.reset()
271
+ set_dock(None)
272
+
273
+ failures = [event for event in events if isinstance(event, TurnFailed)]
274
+ assert len(failures) == 1
275
+ assert failures[0].message == "provider failed"
276
+ assert not any(isinstance(event, TurnCompleted) for event in events)
277
+ finally:
278
+ await delete_session(session.id)
279
+
280
+
192
281
  @pytest.mark.asyncio
193
282
  async def test_run_once_commits_event_todo_at_turn_end(tmp_path):
194
283
  session = await create_session(workspace=str(tmp_path))
@@ -338,4 +427,3 @@ async def test_run_once_persists_user_decision_tool_replay_rows(tmp_path):
338
427
  finally:
339
428
  await delete_session(session.id)
340
429
 
341
-