voidx 1.0.1__tar.gz → 2.0.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.
- {voidx-1.0.1 → voidx-2.0.0}/PKG-INFO +30 -6
- voidx-2.0.0/README.md +61 -0
- {voidx-1.0.1 → voidx-2.0.0}/pyproject.toml +6 -3
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/__init__.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/agents.py +28 -24
- voidx-2.0.0/src/voidx/agent/graph/__init__.py +5 -0
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/compaction.py +112 -69
- voidx-2.0.0/src/voidx/agent/graph/contracts.py +141 -0
- voidx-1.0.1/src/voidx/agent/graph.py → voidx-2.0.0/src/voidx/agent/graph/core.py +90 -79
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/permissions.py +17 -22
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/run_loop.py +211 -126
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/runtime.py +1 -1
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/streaming.py +6 -7
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/subagent.py +25 -16
- {voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/tool_execution.py +141 -23
- voidx-2.0.0/src/voidx/agent/intent_refinement.py +241 -0
- voidx-2.0.0/src/voidx/agent/message_rows.py +36 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/runtime_context.py +46 -17
- voidx-2.0.0/src/voidx/agent/slash/__init__.py +5 -0
- {voidx-1.0.1/src/voidx/agent/slash_components → voidx-2.0.0/src/voidx/agent/slash}/code_ide.py +2 -2
- voidx-1.0.1/src/voidx/agent/slash.py → voidx-2.0.0/src/voidx/agent/slash/handler.py +124 -106
- {voidx-1.0.1/src/voidx/agent/slash_components → voidx-2.0.0/src/voidx/agent/slash}/lsp.py +1 -1
- {voidx-1.0.1/src/voidx/agent/slash_components → voidx-2.0.0/src/voidx/agent/slash}/mcp.py +74 -10
- {voidx-1.0.1/src/voidx/agent/slash_components → voidx-2.0.0/src/voidx/agent/slash}/model.py +52 -30
- {voidx-1.0.1/src/voidx/agent/slash_components → voidx-2.0.0/src/voidx/agent/slash}/runtime.py +3 -5
- {voidx-1.0.1/src/voidx/agent/slash_components → voidx-2.0.0/src/voidx/agent/slash}/skills.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/state.py +16 -10
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/task_state.py +79 -50
- voidx-2.0.0/src/voidx/agent/tool_messages.py +42 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/config.py +53 -31
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/catalog.py +4 -4
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/compaction.py +33 -9
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/instruction.py +28 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/service.py +3 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/main.py +6 -19
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/mcp/__init__.py +2 -1
- voidx-2.0.0/src/voidx/mcp/client.py +723 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/mcp/manager.py +104 -50
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/mcp/schema.py +51 -3
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/mcp/tool.py +7 -54
- voidx-2.0.0/src/voidx/memory/__init__.py +18 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/memory/context_frames.py +1 -2
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/memory/model_profiles.py +36 -41
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/memory/runtime_state.py +140 -31
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/memory/session.py +46 -55
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/memory/store.py +33 -9
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/memory/transcript.py +1 -6
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/engine.py +168 -31
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/sandbox.py +27 -3
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/service.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/skills/__init__.py +5 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/brainstorming/SKILL.md +51 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/receiving-code-review/SKILL.md +60 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/requesting-code-review/SKILL.md +59 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/systematic-debugging/SKILL.md +64 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/test-driven-development/SKILL.md +61 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/verification-before-completion/SKILL.md +69 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-design-docs/SKILL.md +87 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-design-docs/templates/api-doc.md +64 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-design-docs/templates/prd.md +117 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-design-docs/templates/readme.md +55 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-design-docs/templates/rfc.md +38 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-design-docs/templates/tech-design.md +68 -0
- voidx-2.0.0/src/voidx/skills/bundled/superpowers/writing-plans/SKILL.md +54 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/skills/policy.py +7 -2
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/skills/registry.py +50 -11
- voidx-2.0.0/src/voidx/skills/runtime.py +90 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/skills/service.py +37 -2
- voidx-2.0.0/src/voidx/tools/__init__.py +12 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/base.py +64 -8
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/bash.py +61 -7
- voidx-2.0.0/src/voidx/tools/clarify.py +139 -0
- voidx-2.0.0/src/voidx/tools/doc_template.py +96 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/file_ops.py +20 -5
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/lsp.py +4 -4
- voidx-2.0.0/src/voidx/tools/on_intent.py +122 -0
- voidx-2.0.0/src/voidx/tools/plan_checkpoint.py +161 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/registry.py +19 -3
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/repomap.py +1 -13
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/search.py +6 -17
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/task_status.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/task_tracker.py +34 -13
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/todo.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/web_mcp.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/webfetch.py +1 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/websearch.py +1 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/commands.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/frontend.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/gateway/session.py +2 -2
- voidx-2.0.0/src/voidx/ui/output/__init__.py +23 -0
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/output}/browse.py +4 -4
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/output}/capture.py +12 -12
- voidx-2.0.0/src/voidx/ui/output/console/__init__.py +5 -0
- voidx-1.0.1/src/voidx/ui/console.py → voidx-2.0.0/src/voidx/ui/output/console/app.py +18 -79
- {voidx-1.0.1/src/voidx/ui/console_components → voidx-2.0.0/src/voidx/ui/output/console}/formatting.py +6 -4
- {voidx-1.0.1/src/voidx/ui/console_components → voidx-2.0.0/src/voidx/ui/output/console}/streaming.py +12 -12
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/output}/diff.py +1 -1
- voidx-2.0.0/src/voidx/ui/output/dock/__init__.py +13 -0
- voidx-1.0.1/src/voidx/ui/dock.py → voidx-2.0.0/src/voidx/ui/output/dock/app.py +97 -10
- {voidx-1.0.1/src/voidx/ui/dock_components → voidx-2.0.0/src/voidx/ui/output/dock}/nodes.py +57 -22
- {voidx-1.0.1/src/voidx/ui/dock_components → voidx-2.0.0/src/voidx/ui/output/dock}/state.py +2 -0
- voidx-2.0.0/src/voidx/ui/output/events/__init__.py +409 -0
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/output}/tree.py +191 -18
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/protocol/envelope.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/protocol/requests.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/protocol/transcript.py +1 -1
- voidx-2.0.0/src/voidx/ui/session.py +347 -0
- voidx-2.0.0/src/voidx/ui/tools/__init__.py +24 -0
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/tools}/clipboard_image.py +32 -31
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/tools}/file_picker.py +50 -55
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/transcript.py +1 -1
- voidx-2.0.0/src/voidx/ui/tui/__init__.py +4 -0
- voidx-2.0.0/src/voidx/ui/tui/app.py +628 -0
- voidx-2.0.0/src/voidx/ui/tui/helpers.py +147 -0
- voidx-2.0.0/src/voidx/ui/tui/input.py +226 -0
- voidx-2.0.0/src/voidx/ui/tui/panels.py +215 -0
- voidx-2.0.0/src/voidx/ui/tui/parser.py +395 -0
- voidx-2.0.0/src/voidx/ui/tui/renderer.py +592 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx.egg-info/PKG-INFO +30 -6
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx.egg-info/SOURCES.txt +65 -41
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx.egg-info/requires.txt +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_clipboard_image.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_code_ide.py +1 -1
- voidx-2.0.0/tests/test_compaction.py +386 -0
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_config.py +52 -18
- voidx-2.0.0/tests/test_main.py +77 -0
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_mcp.py +107 -0
- voidx-2.0.0/tests/test_npm_package.py +327 -0
- voidx-2.0.0/tests/test_pure_tui.py +1816 -0
- voidx-2.0.0/tests/test_scrollback_flush.py +151 -0
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_skills.py +157 -2
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_startup.py +3 -3
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_tree_smoke.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_ui_diff.py +1 -1
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_ui_events.py +5 -6
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_ui_frontend_protocol.py +2 -2
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_ui_gateway.py +3 -3
- voidx-2.0.0/tests/test_ui_session_changes.py +95 -0
- voidx-1.0.1/README.md +0 -37
- voidx-1.0.1/src/voidx/agent/graph_components/__init__.py +0 -1
- voidx-1.0.1/src/voidx/agent/slash_components/__init__.py +0 -1
- voidx-1.0.1/src/voidx/mcp/client.py +0 -458
- voidx-1.0.1/src/voidx/skills/bundled/superpowers/receiving-code-review/SKILL.md +0 -30
- voidx-1.0.1/src/voidx/skills/bundled/superpowers/requesting-code-review/SKILL.md +0 -27
- voidx-1.0.1/src/voidx/skills/bundled/superpowers/systematic-debugging/SKILL.md +0 -36
- voidx-1.0.1/src/voidx/skills/bundled/superpowers/test-driven-development/SKILL.md +0 -33
- voidx-1.0.1/src/voidx/skills/bundled/superpowers/verification-before-completion/SKILL.md +0 -31
- voidx-1.0.1/src/voidx/skills/bundled/superpowers/writing-plans/SKILL.md +0 -27
- voidx-1.0.1/src/voidx/tools/__init__.py +0 -0
- voidx-1.0.1/src/voidx/ui/__init__.py +0 -0
- voidx-1.0.1/src/voidx/ui/console_components/__init__.py +0 -1
- voidx-1.0.1/src/voidx/ui/dock_components/__init__.py +0 -1
- voidx-1.0.1/src/voidx/ui/event_components/__init__.py +0 -1
- voidx-1.0.1/src/voidx/ui/events.py +0 -378
- voidx-1.0.1/src/voidx/ui/session_changes.py +0 -163
- voidx-1.0.1/src/voidx/ui/startup.py +0 -162
- voidx-1.0.1/src/voidx/ui/tui.py +0 -1603
- voidx-1.0.1/tests/test_main.py +0 -91
- voidx-1.0.1/tests/test_npm_package.py +0 -101
- voidx-1.0.1/tests/test_pure_tui.py +0 -742
- voidx-1.0.1/tests/test_ui_session_changes.py +0 -31
- {voidx-1.0.1 → voidx-2.0.0}/setup.cfg +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/attachments.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/agent/tool_filters.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/context.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/provider.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/llm/usage.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/client.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/config.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/detector.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/errors.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/manager.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/lsp/schema.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/mcp_servers/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/mcp_servers/web.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/evaluate.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/schema.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/permission/wildcard.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/skills/schema.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/agent.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/tools/web_content.py +0 -0
- {voidx-1.0.1/src/voidx/memory → voidx-2.0.0/src/voidx/ui}/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/gateway/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/gateway/bootstrap.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/gateway/server.py +0 -0
- {voidx-1.0.1/src/voidx/ui/dock_components → voidx-2.0.0/src/voidx/ui/output/dock}/formatting.py +0 -0
- {voidx-1.0.1/src/voidx/ui/event_components → voidx-2.0.0/src/voidx/ui/output/events}/schema.py +0 -0
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/output}/types.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/protocol/__init__.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/protocol/commands.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx/ui/protocol/schema.py +0 -0
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/tools}/attachment_tokens.py +0 -0
- {voidx-1.0.1/src/voidx/ui → voidx-2.0.0/src/voidx/ui/tools}/code_ide.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx.egg-info/dependency_links.txt +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx.egg-info/entry_points.txt +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/src/voidx.egg-info/top_level.txt +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_llm_provider.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_llm_usage.py +0 -0
- {voidx-1.0.1 → voidx-2.0.0}/tests/test_lsp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: voidx
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: A coding agent that quantifies everything and solves with tools, not fuzzy prompts.
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -14,7 +14,7 @@ Requires-Dist: typer>=0.15.0
|
|
|
14
14
|
Requires-Dist: rich>=13.9.0
|
|
15
15
|
Requires-Dist: tiktoken>=0.8.0
|
|
16
16
|
Requires-Dist: httpx>=0.28.0
|
|
17
|
-
Requires-Dist: websockets>=
|
|
17
|
+
Requires-Dist: websockets>=14
|
|
18
18
|
Provides-Extra: dev
|
|
19
19
|
Requires-Dist: build>=1.2.0; extra == "dev"
|
|
20
20
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
@@ -26,22 +26,46 @@ voidx is a terminal AI coding agent built in Python.
|
|
|
26
26
|
|
|
27
27
|
## Install
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
### One-line install (no Python or npm required)
|
|
30
|
+
|
|
31
|
+
macOS / Linux:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
curl -fsSL https://raw.githubusercontent.com/chikhamx/voidx/main/scripts/install.sh | bash
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Windows (PowerShell):
|
|
38
|
+
|
|
39
|
+
```powershell
|
|
40
|
+
irm https://raw.githubusercontent.com/chikhamx/voidx/main/scripts/install.ps1 | iex
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The installer downloads a standalone Python runtime and sets up voidx in an
|
|
44
|
+
isolated environment — nothing else is needed on your machine.
|
|
45
|
+
|
|
46
|
+
### pip
|
|
30
47
|
|
|
31
48
|
```bash
|
|
32
49
|
pip install voidx
|
|
33
50
|
voidx
|
|
34
51
|
```
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
on the machine and installs the matching Python package into an isolated
|
|
38
|
-
user-local virtual environment on first run:
|
|
53
|
+
### npm
|
|
39
54
|
|
|
40
55
|
```bash
|
|
41
56
|
npm install -g @chikhamx/voidx
|
|
42
57
|
voidx
|
|
43
58
|
```
|
|
44
59
|
|
|
60
|
+
### China / slow network
|
|
61
|
+
|
|
62
|
+
Set mirror environment variables before running any install method:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export VOIDX_PYTHON_MIRROR=https://npmmirror.com/mirrors/python-standalone
|
|
66
|
+
export VOIDX_PIP_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple
|
|
67
|
+
```
|
|
68
|
+
|
|
45
69
|
## Useful Commands
|
|
46
70
|
|
|
47
71
|
```bash
|
voidx-2.0.0/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# voidx
|
|
2
|
+
|
|
3
|
+
voidx is a terminal AI coding agent built in Python.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
### One-line install (no Python or npm required)
|
|
8
|
+
|
|
9
|
+
macOS / Linux:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
curl -fsSL https://raw.githubusercontent.com/chikhamx/voidx/main/scripts/install.sh | bash
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Windows (PowerShell):
|
|
16
|
+
|
|
17
|
+
```powershell
|
|
18
|
+
irm https://raw.githubusercontent.com/chikhamx/voidx/main/scripts/install.ps1 | iex
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The installer downloads a standalone Python runtime and sets up voidx in an
|
|
22
|
+
isolated environment — nothing else is needed on your machine.
|
|
23
|
+
|
|
24
|
+
### pip
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install voidx
|
|
28
|
+
voidx
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### npm
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g @chikhamx/voidx
|
|
35
|
+
voidx
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### China / slow network
|
|
39
|
+
|
|
40
|
+
Set mirror environment variables before running any install method:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
export VOIDX_PYTHON_MIRROR=https://npmmirror.com/mirrors/python-standalone
|
|
44
|
+
export VOIDX_PIP_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Useful Commands
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
voidx version
|
|
51
|
+
voidx sessions
|
|
52
|
+
voidx -w /path/to/project
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Development
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
.venv/bin/python -m pytest
|
|
59
|
+
.venv/bin/python scripts/package.py --format all --clean
|
|
60
|
+
npm --prefix npm run check
|
|
61
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "voidx"
|
|
3
|
-
version = "
|
|
3
|
+
version = "2.0.0"
|
|
4
4
|
description = "A coding agent that quantifies everything and solves with tools, not fuzzy prompts."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -15,7 +15,7 @@ dependencies = [
|
|
|
15
15
|
"rich>=13.9.0",
|
|
16
16
|
"tiktoken>=0.8.0",
|
|
17
17
|
"httpx>=0.28.0",
|
|
18
|
-
"websockets>=
|
|
18
|
+
"websockets>=14",
|
|
19
19
|
]
|
|
20
20
|
|
|
21
21
|
[project.scripts]
|
|
@@ -43,7 +43,10 @@ build-backend = "setuptools.build_meta"
|
|
|
43
43
|
where = ["src"]
|
|
44
44
|
|
|
45
45
|
[tool.setuptools.package-data]
|
|
46
|
-
"voidx.skills" = [
|
|
46
|
+
"voidx.skills" = [
|
|
47
|
+
"bundled/superpowers/*/SKILL.md",
|
|
48
|
+
"bundled/superpowers/*/templates/*.md",
|
|
49
|
+
]
|
|
47
50
|
|
|
48
51
|
[tool.pytest.ini_options]
|
|
49
52
|
asyncio_mode = "auto"
|
|
@@ -83,8 +83,8 @@ surgical edits directly when that is the shortest safe path.
|
|
|
83
83
|
the user explicitly approves.
|
|
84
84
|
- Fix/implement/modify → edit directly for small scoped changes, or delegate
|
|
85
85
|
broad/isolated work to implement.
|
|
86
|
-
- Ambiguous → continue with read-only investigation when useful.
|
|
87
|
-
|
|
86
|
+
- Ambiguous → continue with read-only investigation when useful. Use clarify
|
|
87
|
+
for one structured question before edits, unsafe bash, or implement delegation.
|
|
88
88
|
|
|
89
89
|
Words like "看看", "分析", "梳理", "有什么建议", "如何设计", "优化方案",
|
|
90
90
|
"look at", "analyze", "suggest", and "proposal" do NOT imply permission
|
|
@@ -92,11 +92,15 @@ surgical edits directly when that is the shortest safe path.
|
|
|
92
92
|
says to modify code.
|
|
93
93
|
|
|
94
94
|
1. **Chat / explain** — just answer. No tools unless you need to look something up.
|
|
95
|
+
If Current Task State says intent is chat or ambiguous, but the user request
|
|
96
|
+
appears to require workspace action, call on_intent before other workspace tools.
|
|
95
97
|
|
|
96
98
|
2. **Simple search** — grab read/glob/grep and find it yourself. Only send explore
|
|
97
99
|
for broad searches across many files.
|
|
98
100
|
|
|
99
|
-
3. **Design / plan** — hand off to plan for architecture questions.
|
|
101
|
+
3. **Design / plan** — hand off to plan for architecture questions. For
|
|
102
|
+
non-trivial implementation plans, call plan_checkpoint before changing files,
|
|
103
|
+
running write-capable commands, or delegating implement.
|
|
100
104
|
|
|
101
105
|
4. **Code changes**
|
|
102
106
|
- Small, local, or mechanical changes → read first, then call write/edit
|
|
@@ -109,9 +113,9 @@ surgical edits directly when that is the shortest safe path.
|
|
|
109
113
|
reporting completion.
|
|
110
114
|
- If review says FAIL or NEEDS_CHANGE → fix, review again.
|
|
111
115
|
|
|
112
|
-
5. **Unclear intent** — ask. One specific clarifying question is
|
|
113
|
-
assumptions. "When you say 'broken', do you mean it crashes,
|
|
114
|
-
or something else?"
|
|
116
|
+
5. **Unclear intent** — ask through clarify. One specific clarifying question is
|
|
117
|
+
better than five assumptions. "When you say 'broken', do you mean it crashes,
|
|
118
|
+
returns wrong data, or something else?"
|
|
115
119
|
|
|
116
120
|
## Rules
|
|
117
121
|
|
|
@@ -119,6 +123,8 @@ surgical edits directly when that is the shortest safe path.
|
|
|
119
123
|
- In plan mode, do not call write/edit/lsp_format, unsafe bash, or implement.
|
|
120
124
|
- Ambiguous implementation intent is not enough for write/edit/lsp_format,
|
|
121
125
|
unsafe bash, or implement delegation.
|
|
126
|
+
- Child agents do not interact with the user. If a child plan result needs user
|
|
127
|
+
approval or clarification, call plan_checkpoint or clarify yourself.
|
|
122
128
|
- Don't tell the user "done" until changes are verified.
|
|
123
129
|
- Child agents have isolated context — give them complete, self-contained briefs.
|
|
124
130
|
|
|
@@ -257,14 +263,12 @@ class AgentDef(BaseModel):
|
|
|
257
263
|
|
|
258
264
|
@property
|
|
259
265
|
def role_prompt(self) -> str:
|
|
260
|
-
|
|
261
|
-
"
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
"
|
|
266
|
-
}
|
|
267
|
-
return prompts.get(self.name, "")
|
|
266
|
+
if self.name in PROMPTLESS_AGENTS:
|
|
267
|
+
return ""
|
|
268
|
+
try:
|
|
269
|
+
return ROLE_PROMPTS[self.name]
|
|
270
|
+
except KeyError as exc:
|
|
271
|
+
raise ValueError(f"No role prompt registered for agent: {self.name}") from exc
|
|
268
272
|
|
|
269
273
|
@property
|
|
270
274
|
def tool_contract(self) -> str:
|
|
@@ -284,9 +288,14 @@ class AgentDef(BaseModel):
|
|
|
284
288
|
lines.append("- Constraint: this role must not start another child agent.")
|
|
285
289
|
return "\n".join(lines)
|
|
286
290
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
291
|
+
ROLE_PROMPTS = {
|
|
292
|
+
"orchestrator": ORCHESTRATOR_PROMPT,
|
|
293
|
+
"explore": EXPLORE_PROMPT,
|
|
294
|
+
"plan": PLAN_PROMPT,
|
|
295
|
+
"implement": IMPLEMENT_PROMPT,
|
|
296
|
+
"review": REVIEW_PROMPT,
|
|
297
|
+
}
|
|
298
|
+
PROMPTLESS_AGENTS = {"compaction", "title"}
|
|
290
299
|
|
|
291
300
|
|
|
292
301
|
# ── built-in agents ────────────────────────────────────────────────────────
|
|
@@ -298,6 +307,7 @@ BUILTIN_AGENTS: dict[str, AgentDef] = {
|
|
|
298
307
|
"delegates broad work to specialists, reviews results.",
|
|
299
308
|
when_to_use="Default agent for all user interactions. Always use first.",
|
|
300
309
|
tools=[
|
|
310
|
+
"on_intent", "clarify", "plan_checkpoint",
|
|
301
311
|
"read", "glob", "grep", "bash", "agent", "task_status", "todo",
|
|
302
312
|
"webfetch", "websearch", "repo_map",
|
|
303
313
|
"lsp_diagnostics", "lsp_symbols", "lsp_definition", "lsp_references",
|
|
@@ -397,9 +407,7 @@ COMPACTION_PROMPT = """You are voidx compaction agent. Your job is to generate a
|
|
|
397
407
|
structured summary of the conversation history to free context space.
|
|
398
408
|
|
|
399
409
|
You have NO tools. Just read the conversation history below and output the
|
|
400
|
-
summary in the exact format specified.
|
|
401
|
-
|
|
402
|
-
""" + "Use template defined in CompactionService."
|
|
410
|
+
summary in the exact format specified."""
|
|
403
411
|
|
|
404
412
|
TITLE_PROMPT = """You are voidx title agent. Generate a short, descriptive
|
|
405
413
|
title (max 80 chars) for this conversation based on the first user message.
|
|
@@ -433,7 +441,3 @@ def child_agent_descriptions_for_llm() -> str:
|
|
|
433
441
|
f" Write access: {agent.can_write}"
|
|
434
442
|
)
|
|
435
443
|
return "\n".join(lines)
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
def subagent_descriptions_for_llm() -> str:
|
|
439
|
-
return child_agent_descriptions_for_llm()
|
{voidx-1.0.1/src/voidx/agent/graph_components → voidx-2.0.0/src/voidx/agent/graph}/compaction.py
RENAMED
|
@@ -2,28 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
|
|
7
|
+
from langchain_core.messages import AIMessage, SystemMessage
|
|
8
|
+
|
|
9
|
+
from voidx.agent.message_rows import messages_from_rows
|
|
10
|
+
from voidx.agent.graph.runtime import console, ui
|
|
11
|
+
from voidx.agent.graph.streaming import extract_text, stream_llm
|
|
12
|
+
from voidx.llm.compaction import COMPACTION_MAX_RETRIES, CompactionService
|
|
9
13
|
from voidx.llm.provider import resolve_protocol
|
|
10
14
|
from voidx.llm.usage import estimate_context_tokens, estimate_message_tokens, extract_token_usage
|
|
11
15
|
from voidx.memory.context_frames import save_context_frame_from_messages
|
|
12
|
-
from voidx.ui.console import StreamingRenderer
|
|
13
|
-
from voidx.ui.dock import dock
|
|
14
|
-
from voidx.ui.events import StatusFinished, StatusUpdated, ui_events, via_events
|
|
16
|
+
from voidx.ui.output.console import StreamingRenderer
|
|
17
|
+
from voidx.ui.output.dock import dock
|
|
18
|
+
from voidx.ui.output.events import StatusFinished, StatusUpdated, ui_events, via_events
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from voidx.agent.graph.contracts import GraphCompactionHost
|
|
15
22
|
|
|
16
23
|
|
|
17
24
|
class GraphCompactionMixin:
|
|
18
25
|
async def _maybe_compact(
|
|
19
|
-
self,
|
|
26
|
+
self: GraphCompactionHost,
|
|
20
27
|
messages: list,
|
|
21
|
-
session_msgs: list,
|
|
28
|
+
session_msgs: list | None = None,
|
|
22
29
|
*,
|
|
23
30
|
force: bool = False,
|
|
24
31
|
ask: bool = True,
|
|
25
32
|
) -> tuple[list | None, str | None]:
|
|
26
|
-
"""Check overflow and compact if needed.
|
|
33
|
+
"""Check overflow and compact if needed.
|
|
34
|
+
|
|
35
|
+
Returns the messages removed from the live context and the persisted
|
|
36
|
+
tail anchor id when one is available. Fallback truncation has no stable
|
|
37
|
+
tail anchor, so it returns None for the second value.
|
|
38
|
+
"""
|
|
27
39
|
total_tokens = estimate_context_tokens(messages, self.config.model.model)
|
|
28
40
|
tokens = {"total": total_tokens, "input": total_tokens, "output": 0, "reasoning": 0}
|
|
29
41
|
|
|
@@ -73,56 +85,83 @@ class GraphCompactionMixin:
|
|
|
73
85
|
detail=f"fallback truncation, keeping last {keep} messages",
|
|
74
86
|
stage="compacting",
|
|
75
87
|
))
|
|
76
|
-
await ui_events.emit(StatusFinished(
|
|
77
|
-
status_id="compaction",
|
|
78
|
-
label=f"Compaction fallback kept last {keep} messages",
|
|
79
|
-
remove=False,
|
|
80
|
-
))
|
|
81
88
|
else:
|
|
82
89
|
ui.print(f"[dim]Aggressive truncation: keeping last {keep} messages[/dim]")
|
|
83
|
-
# Remove old messages, keep system + last N
|
|
84
|
-
system_msgs = [m for m in messages if isinstance(m, SystemMessage)]
|
|
85
|
-
other_msgs = [m for m in messages if not isinstance(m, SystemMessage)]
|
|
86
|
-
messages.clear()
|
|
87
|
-
messages.extend(system_msgs)
|
|
88
|
-
messages.extend(other_msgs[-keep:])
|
|
89
|
-
return messages[:max(0, len(messages) - keep)], None
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
removed = _truncate_to_recent_messages(messages, keep)
|
|
92
|
+
# Generate a basic summary from the removed messages
|
|
93
|
+
fallback = CompactionService.fallback_summary(removed)
|
|
94
|
+
self._pending_summary = fallback
|
|
95
|
+
self._compaction_summary = fallback
|
|
96
|
+
self._compaction.compaction_count += 1
|
|
97
|
+
|
|
93
98
|
if via_events():
|
|
94
|
-
await ui_events.emit(
|
|
99
|
+
await ui_events.emit(StatusFinished(
|
|
95
100
|
status_id="compaction",
|
|
96
|
-
label="
|
|
97
|
-
|
|
98
|
-
stage="compacting",
|
|
101
|
+
label=f"Compaction fallback kept last {keep} messages (with extracted summary)",
|
|
102
|
+
remove=False,
|
|
99
103
|
))
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
return removed, None
|
|
105
|
+
|
|
106
|
+
# Run compaction agent with retries
|
|
107
|
+
summary = None
|
|
108
|
+
previous_summary = getattr(self, "_compaction_summary", "") or None
|
|
109
|
+
last_error: Exception | None = None
|
|
110
|
+
|
|
111
|
+
for attempt in range(1, COMPACTION_MAX_RETRIES + 2): # 1 initial + N retries
|
|
112
|
+
try:
|
|
113
|
+
if via_events():
|
|
114
|
+
retry_label = f" (attempt {attempt})" if attempt > 1 else ""
|
|
115
|
+
await ui_events.emit(StatusUpdated(
|
|
116
|
+
status_id="compaction",
|
|
117
|
+
label="Compacting context",
|
|
118
|
+
detail=f"summarizing {len(head_msgs)} old messages{retry_label}",
|
|
119
|
+
stage="compacting",
|
|
120
|
+
))
|
|
121
|
+
summary = await self._run_compaction_agent(head_msgs, previous_summary)
|
|
122
|
+
if summary:
|
|
123
|
+
break
|
|
124
|
+
except Exception as e:
|
|
125
|
+
last_error = e
|
|
126
|
+
if attempt <= COMPACTION_MAX_RETRIES:
|
|
127
|
+
if via_events():
|
|
128
|
+
await ui_events.emit(StatusUpdated(
|
|
129
|
+
status_id="compaction",
|
|
130
|
+
label="Compaction agent failed",
|
|
131
|
+
detail=f"{e}; retrying ({attempt}/{COMPACTION_MAX_RETRIES})",
|
|
132
|
+
stage="compacting",
|
|
133
|
+
))
|
|
134
|
+
else:
|
|
135
|
+
ui.print(f"[dim]Compaction agent failed ({e}) — retrying ({attempt}/{COMPACTION_MAX_RETRIES})[/dim]")
|
|
136
|
+
|
|
137
|
+
if not summary:
|
|
138
|
+
# All retries exhausted — fallback truncation with basic summary
|
|
103
139
|
if via_events():
|
|
140
|
+
err_detail = f"{last_error}; " if last_error else ""
|
|
104
141
|
await ui_events.emit(StatusUpdated(
|
|
105
142
|
status_id="compaction",
|
|
106
143
|
label="Compaction agent failed",
|
|
107
|
-
detail=f"{
|
|
144
|
+
detail=f"{err_detail}falling back to truncation with extracted summary",
|
|
108
145
|
stage="compacting",
|
|
109
146
|
))
|
|
110
147
|
else:
|
|
111
|
-
|
|
148
|
+
err_msg = f" ({last_error})" if last_error else ""
|
|
149
|
+
ui.print(f"[dim]Compaction agent failed{err_msg} — aggressive truncation with summary[/dim]")
|
|
112
150
|
keep = min(6, len(messages))
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
151
|
+
removed = _truncate_to_recent_messages(messages, keep)
|
|
152
|
+
# Generate a basic summary from the removed messages
|
|
153
|
+
fallback = CompactionService.fallback_summary(head_msgs if head_msgs else removed)
|
|
154
|
+
self._pending_summary = fallback
|
|
155
|
+
self._compaction_summary = fallback
|
|
156
|
+
self._compaction.compaction_count += 1
|
|
118
157
|
if via_events():
|
|
119
158
|
await ui_events.emit(StatusFinished(
|
|
120
159
|
status_id="compaction",
|
|
121
|
-
label=f"Compaction fallback kept last {keep} messages",
|
|
160
|
+
label=f"Compaction fallback kept last {keep} messages (with extracted summary)",
|
|
122
161
|
ok=False,
|
|
123
162
|
remove=False,
|
|
124
163
|
))
|
|
125
|
-
return
|
|
164
|
+
return removed, None
|
|
126
165
|
|
|
127
166
|
if summary:
|
|
128
167
|
keep_from = len(head_msgs)
|
|
@@ -154,7 +193,7 @@ class GraphCompactionMixin:
|
|
|
154
193
|
|
|
155
194
|
return head_msgs, tail_id
|
|
156
195
|
|
|
157
|
-
async def _ask_compact(self, total_tokens: int) -> bool:
|
|
196
|
+
async def _ask_compact(self: GraphCompactionHost, total_tokens: int) -> bool:
|
|
158
197
|
choices = [
|
|
159
198
|
("Compact", "compact", "Summarize older context and continue"),
|
|
160
199
|
("Skip once", "skip", "Continue without compacting this turn"),
|
|
@@ -167,7 +206,7 @@ class GraphCompactionMixin:
|
|
|
167
206
|
ui.print(f" [yellow]Context is large ({total_tokens} tokens); compacting automatically.[/yellow]")
|
|
168
207
|
return True
|
|
169
208
|
|
|
170
|
-
async def _persist_compaction(self, head_messages: list) -> None:
|
|
209
|
+
async def _persist_compaction(self: GraphCompactionHost, head_messages: list) -> None:
|
|
171
210
|
if getattr(self, "_session", None) is None:
|
|
172
211
|
return
|
|
173
212
|
if hasattr(self, "_persist_runtime_state"):
|
|
@@ -179,42 +218,33 @@ class GraphCompactionMixin:
|
|
|
179
218
|
|
|
180
219
|
await delete_messages_through(self._session.id, last_message_id)
|
|
181
220
|
|
|
182
|
-
|
|
221
|
+
# Sync in-memory cache: drop compacted rows
|
|
222
|
+
cache = getattr(self, "_session_msg_cache", None)
|
|
223
|
+
if cache is not None:
|
|
224
|
+
self._session_msg_cache = [r for r in cache if r.id is not None and r.id > last_message_id]
|
|
225
|
+
|
|
226
|
+
async def _compact_session_history(self: GraphCompactionHost, *, force: bool = True) -> bool:
|
|
183
227
|
if getattr(self, "_session", None) is None:
|
|
184
228
|
ui.print("[dim]No active session to compact.[/dim]")
|
|
185
229
|
return False
|
|
186
230
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
messages.append(SystemMessage(content=row.content, id=msg_id))
|
|
196
|
-
elif row.role == "user":
|
|
197
|
-
messages.append(HumanMessage(
|
|
198
|
-
content=parse_structured_content(row.content, row.content_format),
|
|
199
|
-
id=msg_id,
|
|
200
|
-
))
|
|
201
|
-
elif row.role == "assistant":
|
|
202
|
-
messages.append(AIMessage(
|
|
203
|
-
content=parse_structured_content(row.content, row.content_format),
|
|
204
|
-
tool_calls=row.tool_calls or [],
|
|
205
|
-
id=msg_id,
|
|
206
|
-
))
|
|
207
|
-
elif row.role == "tool":
|
|
208
|
-
messages.append(ToolMessage(
|
|
209
|
-
content=row.content,
|
|
210
|
-
tool_call_id=row.tool_call_id or "",
|
|
211
|
-
id=msg_id,
|
|
212
|
-
))
|
|
231
|
+
cache = getattr(self, "_session_msg_cache", None)
|
|
232
|
+
if cache is not None:
|
|
233
|
+
rows = list(cache)
|
|
234
|
+
else:
|
|
235
|
+
from voidx.memory.session import load_messages
|
|
236
|
+
rows = await load_messages(self._session.id)
|
|
237
|
+
|
|
238
|
+
messages = messages_from_rows(rows)
|
|
213
239
|
|
|
214
240
|
head, _tail_id = await self._maybe_compact(messages, rows, force=force, ask=False)
|
|
215
241
|
return bool(head)
|
|
216
242
|
|
|
217
|
-
async def _run_compaction_agent(
|
|
243
|
+
async def _run_compaction_agent(
|
|
244
|
+
self: GraphCompactionHost,
|
|
245
|
+
head_messages: list,
|
|
246
|
+
previous_summary: str | None,
|
|
247
|
+
) -> str | None:
|
|
218
248
|
"""Run the compaction agent to generate a structured summary."""
|
|
219
249
|
from voidx.agent.agents import COMPACTION_PROMPT
|
|
220
250
|
|
|
@@ -266,3 +296,16 @@ def _max_persisted_message_id(messages: list) -> int | None:
|
|
|
266
296
|
except (TypeError, ValueError):
|
|
267
297
|
continue
|
|
268
298
|
return max(ids) if ids else None
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _truncate_to_recent_messages(messages: list, keep: int) -> list:
|
|
302
|
+
original = list(messages)
|
|
303
|
+
system_msgs = [m for m in original if isinstance(m, SystemMessage)]
|
|
304
|
+
other_msgs = [m for m in original if not isinstance(m, SystemMessage)]
|
|
305
|
+
tail_msgs = other_msgs[-keep:] if keep > 0 else []
|
|
306
|
+
retained_ids = {id(m) for m in [*system_msgs, *tail_msgs]}
|
|
307
|
+
removed = [m for m in original if id(m) not in retained_ids]
|
|
308
|
+
messages.clear()
|
|
309
|
+
messages.extend(system_msgs)
|
|
310
|
+
messages.extend(tail_msgs)
|
|
311
|
+
return removed
|