voidx 3.1.0__tar.gz → 3.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {voidx-3.1.0 → voidx-3.1.1}/PKG-INFO +1 -1
- {voidx-3.1.0 → voidx-3.1.1}/pyproject.toml +1 -1
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/__init__.py +1 -1
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/goal_resolver.py +45 -41
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/compaction.py +20 -12
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/compaction_coordinator.py +194 -20
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/contracts.py +13 -4
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/core/_voidx_graph.py +0 -1
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/core/llm.py +123 -19
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/streaming.py +65 -26
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/subagent.py +14 -11
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/executor.py +2 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/guards.py +2 -2
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/helpers.py +1 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/turn_runner.py +10 -2
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/wiring.py +2 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/workflow_utils.py +1 -1
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/message_rows.py +3 -0
- voidx-3.1.1/src/voidx/agent/tool_call_ids.py +33 -0
- voidx-3.1.1/src/voidx/agent/tool_exchange_sanitizer.py +158 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/models.py +3 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/compaction.py +144 -8
- voidx-3.1.1/src/voidx/llm/message_status.py +12 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/session.py +5 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/base.py +42 -5
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/edit_execute.py +22 -1
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/edit_resolve.py +72 -4
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/file.py +7 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/render.py +0 -23
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx.egg-info/PKG-INFO +1 -1
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx.egg-info/SOURCES.txt +3 -0
- {voidx-3.1.0 → voidx-3.1.1}/README.md +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/setup.cfg +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/agents.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/attachments.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/convergence.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/core/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/core/helpers.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/permissions.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/run_loop.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/runtime.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/runtime_guards.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/session_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/session_runtime.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/title_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/todo_events.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_execution.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/types.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/ui.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/tool_executor/workflow.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/topology.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/transcript_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/graph/turn_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/prompts.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/runtime_context.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/code_ide.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/guide.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/handler.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/host.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/init.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/lsp.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/mcp.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/model.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/profile.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/runtime.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/session.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/skills.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/slash/upgrade.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/task_state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/todo_state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/tool_filters.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/tool_messages.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/agent/tool_result_storage.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/enums.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/permissions.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_agent.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_api_keys.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_code_ide.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_custom.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_mcp.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_permissions.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_skills.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_update.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_utils.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/config/settings_web.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/data/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/data/templates/api-doc.md +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/data/templates/prd.md +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/data/templates/readme.md +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/data/templates/rfc.md +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/data/templates/tech-design.md +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/diffing.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/catalog.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/context.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/instruction.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/message_markers.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/provider.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/llm/usage.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/logging/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/logging/request_log.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/logging/tool_log.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/client.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/config.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/detector.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/detector_data.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/errors.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/manager.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/lsp/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/main.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/client/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/client/base.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/client/errors.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/client/http_transport.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/client/sse_transport.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/client/stdio_transport.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/manager.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp/tool.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp_servers/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/mcp_servers/web.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/cleanup.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/context_frames.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/jsonl_store.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/model_profiles.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/runtime_state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/store.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/subagents.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/memory/transcript.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/context.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/engine.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/evaluate.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/rules.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/sandbox.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/permission/wildcard.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/attachments.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/intent.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/reference_tokens.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/task_state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/todo.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/ui.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/runtime/ui_port.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/selfupdate.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/skills/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/skills/context.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/skills/references.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/skills/registry.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/skills/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/skills/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/agent.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/bash.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/bash_router.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/clarify.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/compact_context.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/line.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/read.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/types.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_ops/write.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/file_state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/git.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/load_doc_template.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/load_skills.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/lsp.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/plan_checkpoint.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/registry.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/repomap.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/search.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/task_status.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/task_tracker.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/todo.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/web_content.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/web_mcp.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/webfetch.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/websearch.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/tools/workflow.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/commands.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/frontend.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/gateway/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/gateway/bootstrap.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/gateway/server.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/gateway/session.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/agent_display.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/browse.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/capture.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/console/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/console/app.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/console/formatting.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/console/streaming.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/diff.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/display_policy.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/agent_placeholder.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/app.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/formatting.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/nodes.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/nodes_permission.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/nodes_startup.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/nodes_status.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/status.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/stream.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/dock/todo.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/events/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/events/bus.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/events/consumers.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/events/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/tree.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/output/types.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/protocol/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/protocol/commands.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/protocol/envelope.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/protocol/requests.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/protocol/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/protocol/transcript.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/session.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/attachment_tokens.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/clipboard_image.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/clipboard_text.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/code_ide.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/file_picker.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tools/skill_picker.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/transcript.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/activity.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/app.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/choice_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/clipboard_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/helpers.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/input.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/overlays.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/panels.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/parser.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/render_activity.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/render_frame.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/render_input.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/render_status.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/render_todo.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/renderer.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/state.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/terminal_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/ui/tui/text_prompt_mixin.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/__init__.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/auto_advance.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/context.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/dag.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/nodes.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/policy.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/reconcile.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/route.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/runtime.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/schema.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/service.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx/workflow/types.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx.egg-info/dependency_links.txt +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx.egg-info/entry_points.txt +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx.egg-info/requires.txt +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/src/voidx.egg-info/top_level.txt +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/tests/test_install_sh.py +0 -0
- {voidx-3.1.0 → voidx-3.1.1}/tests/test_npm_package.py +0 -0
|
@@ -230,8 +230,36 @@ def _truncate_error_text(value: str, limit: int = 2000) -> str:
|
|
|
230
230
|
|
|
231
231
|
def _resolver_system_prompt() -> str:
|
|
232
232
|
return (
|
|
233
|
-
"
|
|
234
|
-
"
|
|
233
|
+
"You are a goal resolver. Classify the user's current turn into intent, goal, workflow, and kind_hint.\n"
|
|
234
|
+
"\n"
|
|
235
|
+
"## Output Schema\n"
|
|
236
|
+
"\n"
|
|
237
|
+
"Return a JSON object matching this template:\n"
|
|
238
|
+
"\n"
|
|
239
|
+
"{\n"
|
|
240
|
+
' "intent": "coding" or "general",\n'
|
|
241
|
+
' "goal": null or "<short summary of the user\'s request in their language, 1-2 sentences>",\n'
|
|
242
|
+
' "workflow": null or "<one of the workflows listed below>",\n'
|
|
243
|
+
' "kind_hint": null or "<semantic hint: review | debug | feature | inspect | refactor | test | docs>"\n'
|
|
244
|
+
"}\n"
|
|
245
|
+
"\n"
|
|
246
|
+
"## Field Rules\n"
|
|
247
|
+
"\n"
|
|
248
|
+
'- **intent**: "coding" for codebase/workspace work; "general" for non-code conversation.\n'
|
|
249
|
+
"- **goal**: Short user-language summary when a workflow should start; null otherwise. Must be set exactly when workflow is set, and null exactly when workflow is null.\n"
|
|
250
|
+
"- **workflow**: The workflow to start, or null. Must be set exactly when goal is set.\n"
|
|
251
|
+
"- **kind_hint**: Optional semantic hint. Advisory only; never overrides workflow selection.\n"
|
|
252
|
+
"\n"
|
|
253
|
+
"## Available Workflows\n"
|
|
254
|
+
"\n"
|
|
255
|
+
"- brainstorm: Confirm requirements and design, get user approval\n"
|
|
256
|
+
"- debug: Locate root cause and confirm fix direction\n"
|
|
257
|
+
"- design: Produce a structured document that passes the reader test\n"
|
|
258
|
+
"- feedback: Verify and implement valid review feedback\n"
|
|
259
|
+
"- plan: Produce an executable implementation plan, get user approval\n"
|
|
260
|
+
"- review: Initiate structured code review request and collect verdict\n"
|
|
261
|
+
"- tdd: Complete implementation via TDD cycle, all tests green\n"
|
|
262
|
+
"- verify: Prove changes reach expected state with reproducible evidence\n"
|
|
235
263
|
)
|
|
236
264
|
|
|
237
265
|
|
|
@@ -239,52 +267,22 @@ def _resolver_request_markdown(user_text: str, task_state: TaskState) -> str:
|
|
|
239
267
|
recent_content = _recent_exchanges_content(task_state)
|
|
240
268
|
active = ", ".join(_active_workflow_names(task_state)) or "none"
|
|
241
269
|
goal = task_state.current_goal.label if task_state.current_goal is not None else "none"
|
|
242
|
-
|
|
243
|
-
"#
|
|
244
|
-
"",
|
|
245
|
-
"## Current State",
|
|
270
|
+
sections = [
|
|
271
|
+
"# Context",
|
|
246
272
|
"",
|
|
247
273
|
f"- intent: {task_state.current_intent.value}",
|
|
248
274
|
f"- goal: {goal}",
|
|
249
275
|
f"- active workflows: {active}",
|
|
250
276
|
"",
|
|
251
|
-
"
|
|
277
|
+
"# Recent Conversation",
|
|
252
278
|
"",
|
|
253
|
-
"```text",
|
|
254
279
|
recent_content,
|
|
255
|
-
"```",
|
|
256
280
|
"",
|
|
257
|
-
"
|
|
281
|
+
"# Current User Question",
|
|
258
282
|
"",
|
|
259
|
-
"```text",
|
|
260
283
|
user_text,
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
"## Available Workflows",
|
|
264
|
-
"",
|
|
265
|
-
"- brainstorm: Confirm requirements and design, get user approval",
|
|
266
|
-
"- debug: Locate root cause and confirm fix direction",
|
|
267
|
-
"- design: Produce a structured document that passes the reader test",
|
|
268
|
-
"- feedback: Verify and implement valid review feedback",
|
|
269
|
-
"- plan: Produce an executable implementation plan, get user approval",
|
|
270
|
-
"- review: Initiate structured code review request and collect verdict",
|
|
271
|
-
"- tdd: Complete implementation via TDD cycle, all tests green",
|
|
272
|
-
"- verify: Prove changes reach expected state with reproducible evidence",
|
|
273
|
-
"",
|
|
274
|
-
"## Return Fields",
|
|
275
|
-
"",
|
|
276
|
-
'- intent: "coding" for codebase/workspace work; "general" for non-code conversation.',
|
|
277
|
-
"- goal: short user-language summary, or null when no workflow should start.",
|
|
278
|
-
"- workflow: workflow to start, or null. Must be set exactly when goal is set.",
|
|
279
|
-
"- kind_hint: optional semantic hint such as review/debug/feature/inspect. Advisory only; never overrides workflow.",
|
|
280
|
-
"",
|
|
281
|
-
"## ResolverGoal Schema",
|
|
282
|
-
"",
|
|
283
|
-
"- intent: 'coding' | 'general'",
|
|
284
|
-
"- goal: null or string (short summary of the user's request in their language, 1-2 sentences)",
|
|
285
|
-
"- workflow: null or one of [brainstorm, debug, design, feedback, plan, review, tdd, verify]",
|
|
286
|
-
"- kind_hint: null or string (non-authoritative semantic hint; not used for routing)",
|
|
287
|
-
])
|
|
284
|
+
]
|
|
285
|
+
return "\n".join(sections)
|
|
288
286
|
|
|
289
287
|
|
|
290
288
|
_ALLOWED_JOIN_NODES = {"debug", "brainstorm", "design", "plan", "tdd", "review", "feedback", "verify"}
|
|
@@ -405,10 +403,16 @@ def _normalize_resolution(
|
|
|
405
403
|
def _recent_exchanges_content(task_state: TaskState) -> str:
|
|
406
404
|
blocks: list[str] = []
|
|
407
405
|
for index, exchange in enumerate(task_state.recent_exchanges, start=1):
|
|
408
|
-
|
|
409
|
-
|
|
406
|
+
lines: list[str] = [f"## Turn {index}", ""]
|
|
407
|
+
user_text = exchange.user_text.strip()
|
|
408
|
+
assistant_text = exchange.assistant_text.strip()
|
|
409
|
+
if user_text:
|
|
410
|
+
lines.append(f"**Human**: {user_text}")
|
|
411
|
+
if assistant_text:
|
|
412
|
+
lines.append(f"**Assistant**: {assistant_text}")
|
|
413
|
+
if len(lines) <= 2:
|
|
410
414
|
continue
|
|
411
|
-
blocks.append(
|
|
415
|
+
blocks.append("\n".join(lines))
|
|
412
416
|
return "\n\n".join(blocks)
|
|
413
417
|
|
|
414
418
|
|
|
@@ -4,7 +4,11 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
|
-
from voidx.agent.graph.compaction_coordinator import
|
|
7
|
+
from voidx.agent.graph.compaction_coordinator import (
|
|
8
|
+
CompactionResult,
|
|
9
|
+
GraphCompactionCoordinator,
|
|
10
|
+
PreflightCompactionResult,
|
|
11
|
+
)
|
|
8
12
|
|
|
9
13
|
if TYPE_CHECKING:
|
|
10
14
|
from voidx.agent.graph.contracts import GraphCompactionHost
|
|
@@ -30,36 +34,40 @@ class GraphCompactionMixin:
|
|
|
30
34
|
*,
|
|
31
35
|
force: bool = False,
|
|
32
36
|
ask: bool = True,
|
|
37
|
+
preflight: bool = False,
|
|
33
38
|
) -> tuple[list | None, str | None]:
|
|
34
39
|
return await _compaction_component_for(self).maybe_compact(
|
|
35
40
|
messages,
|
|
36
41
|
session_msgs,
|
|
37
42
|
force=force,
|
|
38
43
|
ask=ask,
|
|
44
|
+
preflight=preflight,
|
|
39
45
|
run_compaction_agent=self._run_compaction_agent,
|
|
40
46
|
persist_compaction=self._persist_compaction,
|
|
41
47
|
)
|
|
42
48
|
|
|
43
|
-
async def
|
|
49
|
+
async def _preflight_compact_if_needed(
|
|
44
50
|
self: GraphCompactionHost,
|
|
45
51
|
messages: list,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
session_msgs: list | None = None,
|
|
53
|
+
*,
|
|
54
|
+
force: bool = False,
|
|
55
|
+
reason: str = "threshold",
|
|
56
|
+
ask: bool = False,
|
|
57
|
+
) -> tuple[CompactionResult | None, PreflightCompactionResult]:
|
|
58
|
+
result, preflight_result = await _compaction_component_for(self).preflight_compact_if_needed(
|
|
52
59
|
messages,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
session_msgs,
|
|
61
|
+
force=force,
|
|
62
|
+
reason=reason,
|
|
63
|
+
ask=ask,
|
|
56
64
|
run_compaction_agent=self._run_compaction_agent,
|
|
57
65
|
persist_compaction=self._persist_compaction,
|
|
58
66
|
)
|
|
59
67
|
if result is not None:
|
|
60
68
|
self._file_read_coverage.clear()
|
|
61
69
|
self._file_mtimes.clear()
|
|
62
|
-
return result
|
|
70
|
+
return result, preflight_result
|
|
63
71
|
|
|
64
72
|
async def _ask_compact(self: GraphCompactionHost, total_tokens: int) -> bool:
|
|
65
73
|
return await _compaction_component_for(self).ask_compact(total_tokens)
|
|
@@ -4,9 +4,11 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
6
|
from collections.abc import Awaitable, Callable
|
|
7
|
-
from dataclasses import dataclass
|
|
7
|
+
from dataclasses import dataclass, field
|
|
8
8
|
from typing import TYPE_CHECKING
|
|
9
9
|
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
10
12
|
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
|
|
11
13
|
|
|
12
14
|
from voidx.agent.graph.streaming import extract_text, stream_llm
|
|
@@ -47,6 +49,38 @@ class CompactionResult:
|
|
|
47
49
|
live_messages: list[BaseMessage]
|
|
48
50
|
tail_id: str | None
|
|
49
51
|
fallback: bool = False
|
|
52
|
+
metadata: dict[str, object] = field(default_factory=dict)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class PreflightCompactionResult(BaseModel):
|
|
56
|
+
compacted: bool
|
|
57
|
+
summary: str = ""
|
|
58
|
+
removed_message_count: int = 0
|
|
59
|
+
retained_turn_count: int = 0
|
|
60
|
+
pre_tokens: int = 0
|
|
61
|
+
post_tokens: int = 0
|
|
62
|
+
post_target_tokens: int = 0
|
|
63
|
+
tail_anchor_id: str = ""
|
|
64
|
+
fallback: bool = False
|
|
65
|
+
reason: str = ""
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def from_compaction_result(cls, result: CompactionResult | None) -> "PreflightCompactionResult":
|
|
69
|
+
if result is None:
|
|
70
|
+
return cls(compacted=False)
|
|
71
|
+
metadata = result.metadata or {}
|
|
72
|
+
return cls(
|
|
73
|
+
compacted=True,
|
|
74
|
+
summary=result.summary,
|
|
75
|
+
removed_message_count=int(metadata.get("removed_message_count") or len(result.removed_messages)),
|
|
76
|
+
retained_turn_count=int(metadata.get("retained_turn_count") or 0),
|
|
77
|
+
pre_tokens=int(metadata.get("pre_tokens") or 0),
|
|
78
|
+
post_tokens=int(metadata.get("post_tokens") or 0),
|
|
79
|
+
post_target_tokens=int(metadata.get("post_compaction_target") or 0),
|
|
80
|
+
tail_anchor_id=str(metadata.get("tail_anchor_id") or result.tail_id or ""),
|
|
81
|
+
fallback=bool(metadata.get("fallback") or result.fallback),
|
|
82
|
+
reason=str(metadata.get("compaction_reason") or ""),
|
|
83
|
+
)
|
|
50
84
|
|
|
51
85
|
|
|
52
86
|
class GraphCompactionCoordinator:
|
|
@@ -62,6 +96,7 @@ class GraphCompactionCoordinator:
|
|
|
62
96
|
*,
|
|
63
97
|
force: bool = False,
|
|
64
98
|
ask: bool = True,
|
|
99
|
+
preflight: bool = False,
|
|
65
100
|
run_compaction_agent: RunCompactionAgent | None = None,
|
|
66
101
|
persist_compaction: PersistCompaction | None = None,
|
|
67
102
|
) -> tuple[list | None, str | None]:
|
|
@@ -75,6 +110,7 @@ class GraphCompactionCoordinator:
|
|
|
75
110
|
session_msgs,
|
|
76
111
|
force=force,
|
|
77
112
|
ask=ask,
|
|
113
|
+
preflight=preflight,
|
|
78
114
|
run_compaction_agent=run_compaction_agent,
|
|
79
115
|
persist_compaction=persist_compaction,
|
|
80
116
|
)
|
|
@@ -85,6 +121,34 @@ class GraphCompactionCoordinator:
|
|
|
85
121
|
messages.extend(result.live_messages)
|
|
86
122
|
return result.removed_messages, result.tail_id
|
|
87
123
|
|
|
124
|
+
async def preflight_compact_if_needed(
|
|
125
|
+
self,
|
|
126
|
+
messages: list[BaseMessage],
|
|
127
|
+
session_msgs: list | None = None,
|
|
128
|
+
*,
|
|
129
|
+
force: bool = False,
|
|
130
|
+
reason: str = "threshold",
|
|
131
|
+
ask: bool = False,
|
|
132
|
+
run_compaction_agent: RunCompactionAgent | None = None,
|
|
133
|
+
persist_compaction: PersistCompaction | None = None,
|
|
134
|
+
) -> tuple[CompactionResult | None, PreflightCompactionResult]:
|
|
135
|
+
result = await self.compact_for_live_state(
|
|
136
|
+
messages,
|
|
137
|
+
session_msgs,
|
|
138
|
+
force=force,
|
|
139
|
+
ask=ask,
|
|
140
|
+
preflight=True,
|
|
141
|
+
include_summary_message=False,
|
|
142
|
+
run_compaction_agent=run_compaction_agent,
|
|
143
|
+
persist_compaction=persist_compaction,
|
|
144
|
+
)
|
|
145
|
+
preflight_result = PreflightCompactionResult.from_compaction_result(result)
|
|
146
|
+
if preflight_result.compacted and reason and preflight_result.reason in {"", "threshold", "force"}:
|
|
147
|
+
preflight_result.reason = reason
|
|
148
|
+
if result is not None:
|
|
149
|
+
result.metadata["compaction_reason"] = reason
|
|
150
|
+
return result, preflight_result
|
|
151
|
+
|
|
88
152
|
async def compact_for_live_state(
|
|
89
153
|
self,
|
|
90
154
|
messages: list[BaseMessage],
|
|
@@ -92,6 +156,7 @@ class GraphCompactionCoordinator:
|
|
|
92
156
|
*,
|
|
93
157
|
force: bool = False,
|
|
94
158
|
ask: bool = True,
|
|
159
|
+
preflight: bool = False,
|
|
95
160
|
include_summary_message: bool = False,
|
|
96
161
|
run_compaction_agent: RunCompactionAgent | None = None,
|
|
97
162
|
persist_compaction: PersistCompaction | None = None,
|
|
@@ -103,7 +168,9 @@ class GraphCompactionCoordinator:
|
|
|
103
168
|
total_tokens = estimate_context_tokens(messages, host.config.model.model)
|
|
104
169
|
tokens = {"total": total_tokens, "input": total_tokens, "output": 0, "reasoning": 0}
|
|
105
170
|
|
|
106
|
-
|
|
171
|
+
over_hard = host._compaction.is_overflow(tokens)
|
|
172
|
+
over_soft = preflight and host._compaction.is_soft_overflow(tokens)
|
|
173
|
+
if not force and not over_hard and not over_soft:
|
|
107
174
|
return None
|
|
108
175
|
|
|
109
176
|
if not force and ask and getattr(host.config, "ask_compact", False):
|
|
@@ -123,11 +190,7 @@ class GraphCompactionCoordinator:
|
|
|
123
190
|
await host._ui.events.emit(StatusUpdated(
|
|
124
191
|
status_id="compaction",
|
|
125
192
|
label="Compacting context",
|
|
126
|
-
detail=(
|
|
127
|
-
f"{total_tokens} tokens exceed the active context budget"
|
|
128
|
-
if not force
|
|
129
|
-
else f"manual compaction of {len(messages)} messages"
|
|
130
|
-
),
|
|
193
|
+
detail=_compaction_status_detail(total_tokens, force=force, preflight=preflight),
|
|
131
194
|
stage="compacting",
|
|
132
195
|
))
|
|
133
196
|
else:
|
|
@@ -142,7 +205,15 @@ class GraphCompactionCoordinator:
|
|
|
142
205
|
raw_semantic_messages(messages),
|
|
143
206
|
preserve_trailing_ai_tool_calls=True,
|
|
144
207
|
)
|
|
145
|
-
|
|
208
|
+
if preflight:
|
|
209
|
+
selection = host._compaction.select_preflight_details(
|
|
210
|
+
semantic_messages,
|
|
211
|
+
model=host.config.model.model,
|
|
212
|
+
)
|
|
213
|
+
if not selection.should_compact and (force or over_hard):
|
|
214
|
+
selection = host._compaction.select_details(semantic_messages)
|
|
215
|
+
else:
|
|
216
|
+
selection = host._compaction.select_details(semantic_messages)
|
|
146
217
|
head_msgs, tail_id = selection.head, selection.tail_id
|
|
147
218
|
semantic_tail = semantic_messages[selection.keep_from:]
|
|
148
219
|
|
|
@@ -155,6 +226,18 @@ class GraphCompactionCoordinator:
|
|
|
155
226
|
))
|
|
156
227
|
return None
|
|
157
228
|
|
|
229
|
+
base_metadata = _compaction_metadata(
|
|
230
|
+
host,
|
|
231
|
+
semantic_messages=semantic_messages,
|
|
232
|
+
semantic_tail=semantic_tail,
|
|
233
|
+
total_tokens=total_tokens,
|
|
234
|
+
force=force,
|
|
235
|
+
preflight=preflight,
|
|
236
|
+
over_soft=over_soft,
|
|
237
|
+
over_hard=over_hard,
|
|
238
|
+
removed_message_count=len(head_msgs),
|
|
239
|
+
tail_id=tail_id,
|
|
240
|
+
)
|
|
158
241
|
summary = None
|
|
159
242
|
previous_summary = getattr(host, "_compaction_summary", "") or None
|
|
160
243
|
last_error: Exception | None = None
|
|
@@ -213,6 +296,18 @@ class GraphCompactionCoordinator:
|
|
|
213
296
|
host._compaction_summary = fallback
|
|
214
297
|
host._compaction.compaction_count += 1
|
|
215
298
|
await persist(head_msgs)
|
|
299
|
+
live_messages = _live_messages(
|
|
300
|
+
runtime_prefix,
|
|
301
|
+
semantic_tail,
|
|
302
|
+
fallback,
|
|
303
|
+
include_summary_message=include_summary_message,
|
|
304
|
+
)
|
|
305
|
+
metadata = _finish_compaction_metadata(
|
|
306
|
+
base_metadata,
|
|
307
|
+
live_messages=live_messages,
|
|
308
|
+
model=host.config.model.model,
|
|
309
|
+
fallback=True,
|
|
310
|
+
)
|
|
216
311
|
if host._ui.via_events():
|
|
217
312
|
await host._ui.events.emit(StatusFinished(
|
|
218
313
|
status_id="compaction",
|
|
@@ -224,14 +319,10 @@ class GraphCompactionCoordinator:
|
|
|
224
319
|
return CompactionResult(
|
|
225
320
|
summary=fallback,
|
|
226
321
|
removed_messages=list(head_msgs),
|
|
227
|
-
live_messages=
|
|
228
|
-
runtime_prefix,
|
|
229
|
-
semantic_tail,
|
|
230
|
-
fallback,
|
|
231
|
-
include_summary_message=include_summary_message,
|
|
232
|
-
),
|
|
322
|
+
live_messages=live_messages,
|
|
233
323
|
tail_id=tail_id,
|
|
234
324
|
fallback=True,
|
|
325
|
+
metadata=metadata,
|
|
235
326
|
)
|
|
236
327
|
|
|
237
328
|
if summary:
|
|
@@ -258,17 +349,25 @@ class GraphCompactionCoordinator:
|
|
|
258
349
|
else:
|
|
259
350
|
return None
|
|
260
351
|
|
|
352
|
+
live_messages = _live_messages(
|
|
353
|
+
runtime_prefix,
|
|
354
|
+
semantic_tail,
|
|
355
|
+
summary,
|
|
356
|
+
include_summary_message=include_summary_message,
|
|
357
|
+
)
|
|
358
|
+
metadata = _finish_compaction_metadata(
|
|
359
|
+
base_metadata,
|
|
360
|
+
live_messages=live_messages,
|
|
361
|
+
model=host.config.model.model,
|
|
362
|
+
fallback=False,
|
|
363
|
+
)
|
|
261
364
|
return CompactionResult(
|
|
262
365
|
summary=summary,
|
|
263
366
|
removed_messages=list(head_msgs),
|
|
264
|
-
live_messages=
|
|
265
|
-
runtime_prefix,
|
|
266
|
-
semantic_tail,
|
|
267
|
-
summary,
|
|
268
|
-
include_summary_message=include_summary_message,
|
|
269
|
-
),
|
|
367
|
+
live_messages=live_messages,
|
|
270
368
|
tail_id=tail_id,
|
|
271
369
|
fallback=False,
|
|
370
|
+
metadata=metadata,
|
|
272
371
|
)
|
|
273
372
|
|
|
274
373
|
async def ask_compact(self, total_tokens: int) -> bool:
|
|
@@ -450,6 +549,81 @@ def _content_type_summary(content: object) -> str:
|
|
|
450
549
|
return type(content).__name__
|
|
451
550
|
|
|
452
551
|
|
|
552
|
+
def _compaction_status_detail(total_tokens: int, *, force: bool, preflight: bool) -> str:
|
|
553
|
+
if force:
|
|
554
|
+
return "manual compaction"
|
|
555
|
+
if preflight:
|
|
556
|
+
return f"{total_tokens} tokens reached the preflight compaction threshold"
|
|
557
|
+
return f"{total_tokens} tokens exceed the active context budget"
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
def _compaction_metadata(
|
|
561
|
+
host: GraphCompactionHost,
|
|
562
|
+
*,
|
|
563
|
+
semantic_messages: list[BaseMessage],
|
|
564
|
+
semantic_tail: list[BaseMessage],
|
|
565
|
+
total_tokens: int,
|
|
566
|
+
force: bool,
|
|
567
|
+
preflight: bool,
|
|
568
|
+
over_soft: bool,
|
|
569
|
+
over_hard: bool,
|
|
570
|
+
removed_message_count: int,
|
|
571
|
+
tail_id: str | None,
|
|
572
|
+
) -> dict[str, object]:
|
|
573
|
+
return {
|
|
574
|
+
"compaction_reason": _compaction_reason(
|
|
575
|
+
force=force,
|
|
576
|
+
preflight=preflight,
|
|
577
|
+
over_soft=over_soft,
|
|
578
|
+
over_hard=over_hard,
|
|
579
|
+
),
|
|
580
|
+
"pre_tokens": total_tokens,
|
|
581
|
+
"soft_threshold": host._compaction.soft_threshold(),
|
|
582
|
+
"hard_threshold": int(host._compaction.context_limit * 0.90),
|
|
583
|
+
"post_compaction_target": host._compaction.post_compaction_target(),
|
|
584
|
+
"removed_message_count": removed_message_count,
|
|
585
|
+
"retained_turn_count": len(host._compaction._turns(semantic_tail)),
|
|
586
|
+
"current_user_preserved": _latest_user_preserved(semantic_messages, semantic_tail),
|
|
587
|
+
"tail_anchor_id": tail_id or "",
|
|
588
|
+
"inline_compaction_enabled": bool(getattr(host.config, "inline_compaction_enabled", False)),
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
def _finish_compaction_metadata(
|
|
593
|
+
metadata: dict[str, object],
|
|
594
|
+
*,
|
|
595
|
+
live_messages: list[BaseMessage],
|
|
596
|
+
model: str,
|
|
597
|
+
fallback: bool,
|
|
598
|
+
) -> dict[str, object]:
|
|
599
|
+
return {
|
|
600
|
+
**metadata,
|
|
601
|
+
"post_tokens": estimate_context_tokens(live_messages, model),
|
|
602
|
+
"fallback": fallback,
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def _compaction_reason(*, force: bool, preflight: bool, over_soft: bool, over_hard: bool) -> str:
|
|
607
|
+
if force:
|
|
608
|
+
return "force"
|
|
609
|
+
if over_hard:
|
|
610
|
+
return "hard_threshold"
|
|
611
|
+
if preflight and over_soft:
|
|
612
|
+
return "soft_threshold"
|
|
613
|
+
return "threshold"
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def _latest_user_preserved(
|
|
617
|
+
semantic_messages: list[BaseMessage],
|
|
618
|
+
semantic_tail: list[BaseMessage],
|
|
619
|
+
) -> bool:
|
|
620
|
+
latest_user = next(
|
|
621
|
+
(message for message in reversed(semantic_messages) if isinstance(message, HumanMessage)),
|
|
622
|
+
None,
|
|
623
|
+
)
|
|
624
|
+
return latest_user is None or any(message is latest_user for message in semantic_tail)
|
|
625
|
+
|
|
626
|
+
|
|
453
627
|
def _compaction_request_text(previous_summary: str | None) -> str:
|
|
454
628
|
previous_summary_section = ""
|
|
455
629
|
if previous_summary:
|
|
@@ -20,7 +20,11 @@ from voidx.runtime.ui_port import AgentUiPort
|
|
|
20
20
|
from voidx.tools.service import ToolRegistry, TaskTracker
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
23
|
-
from voidx.agent.graph.compaction_coordinator import
|
|
23
|
+
from voidx.agent.graph.compaction_coordinator import (
|
|
24
|
+
CompactionResult,
|
|
25
|
+
GraphCompactionCoordinator,
|
|
26
|
+
PreflightCompactionResult,
|
|
27
|
+
)
|
|
24
28
|
from voidx.agent.graph.runtime_guards import RuntimeGuardState
|
|
25
29
|
from voidx.agent.graph.session_runtime import GraphSessionRuntime
|
|
26
30
|
from voidx.agent.graph.tool_executor import GraphToolExecutor
|
|
@@ -39,7 +43,6 @@ class GraphCompactionHost(Protocol):
|
|
|
39
43
|
_usage_stats: UsageStats
|
|
40
44
|
_compaction: CompactionService
|
|
41
45
|
_compaction_coordinator: GraphCompactionCoordinator
|
|
42
|
-
_in_turn_compaction_count: int
|
|
43
46
|
_pending_summary: str | None
|
|
44
47
|
_compaction_summary: str
|
|
45
48
|
_session_msg_cache: list[Any] | None
|
|
@@ -53,11 +56,17 @@ class GraphCompactionHost(Protocol):
|
|
|
53
56
|
*,
|
|
54
57
|
force: bool = False,
|
|
55
58
|
ask: bool = True,
|
|
59
|
+
preflight: bool = False,
|
|
56
60
|
) -> tuple[list[BaseMessage] | None, str | None]: ...
|
|
57
|
-
async def
|
|
61
|
+
async def _preflight_compact_if_needed(
|
|
58
62
|
self,
|
|
59
63
|
messages: list[BaseMessage],
|
|
60
|
-
|
|
64
|
+
session_msgs: list[Any] | None = None,
|
|
65
|
+
*,
|
|
66
|
+
force: bool = False,
|
|
67
|
+
reason: str = "threshold",
|
|
68
|
+
ask: bool = False,
|
|
69
|
+
) -> tuple[CompactionResult | None, PreflightCompactionResult]: ...
|
|
61
70
|
async def _ask_compact(self, total_tokens: int) -> bool: ...
|
|
62
71
|
async def _persist_compaction(self, head_messages: list[BaseMessage]) -> None: ...
|
|
63
72
|
async def _compact_session_history(self, *, force: bool = True) -> bool: ...
|
|
@@ -114,7 +114,6 @@ class VoidXGraph(
|
|
|
114
114
|
self._current_messages: list[BaseMessage] | None = None
|
|
115
115
|
self._pending_summary: str | None = None
|
|
116
116
|
self._compaction_summary: str = ""
|
|
117
|
-
self._in_turn_compaction_count: int = 0
|
|
118
117
|
self._session_date: str = session_date(session)
|
|
119
118
|
self._session_msg_cache: list | None = None
|
|
120
119
|
self._context_cache = ContextCompilerCache()
|