@scemoon/cdh 1.0.4 → 1.0.6
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.
- package/ai-dlc-skill/SKILL.md +4 -2
- package/ai-dlc-skill/agents/master.md +6 -0
- package/ai-dlc-skill/agents/plan-agent.md +2 -2
- package/ai-dlc-skill/agents/understand-agent.md +4 -4
- package/ai-dlc-skill/agents/verify-agent.md +1 -1
- package/ai-dlc-skill/architecture/project-structure.md +10 -10
- package/ai-dlc-skill/brownfield/README.md +2 -2
- package/ai-dlc-skill/brownfield/generate-context.sh +3 -3
- package/ai-dlc-skill/brownfield/scripts/extract-api.sh +5 -5
- package/ai-dlc-skill/components/backend.md +1 -1
- package/ai-dlc-skill/components/web.md +2 -2
- package/ai-dlc-skill/contracts/README.md +3 -3
- package/ai-dlc-skill/cross-tool/cline/export.sh +1 -1
- package/ai-dlc-skill/cross-tool/copilot/export.sh +1 -1
- package/ai-dlc-skill/cross-tool/onecode/export-skills.sh +7 -3
- package/ai-dlc-skill/cross-tool/onecode/export.sh +14 -8
- package/ai-dlc-skill/phases/deliver/lifecycle.md +6 -6
- package/ai-dlc-skill/phases/deliver/prompt.md +2 -2
- package/ai-dlc-skill/phases/deliver/rules.md +1 -1
- package/ai-dlc-skill/phases/plan/lifecycle.md +11 -11
- package/ai-dlc-skill/phases/plan/prompt.md +6 -6
- package/ai-dlc-skill/phases/plan/rules.md +1 -1
- package/ai-dlc-skill/phases/understand/entry.md +1 -1
- package/ai-dlc-skill/phases/understand/lifecycle.md +7 -7
- package/ai-dlc-skill/phases/understand/prompt.md +8 -8
- package/ai-dlc-skill/phases/understand/rules.md +5 -5
- package/ai-dlc-skill/phases/verify/lifecycle.md +24 -24
- package/ai-dlc-skill/phases/verify/prompt.md +8 -8
- package/ai-dlc-skill/phases/verify/rules.md +9 -9
- package/ai-dlc-skill/providers/README.md +2 -2
- package/ai-dlc-skill/providers/aliyun/preview.yaml +2 -2
- package/ai-dlc-skill/providers/tcb/preview.yaml +2 -2
- package/ai-dlc-skill/requirements.md +7 -7
- package/ai-dlc-skill/skill.yaml +4 -4
- package/ai-dlc-skill/templates/integration/CHANGELOG.md +2 -2
- package/ai-dlc-skill/templates/integration/contract-diff.md +7 -7
- package/ai-dlc-skill/templates/integration/contract-spec.md +7 -7
- package/ai-dlc-skill/templates/integration/runtime-contract.yaml +1 -1
- package/ai-dlc-skill/templates/project/README.md +18 -19
- package/ai-dlc-skill/templates/project/template.md +21 -21
- package/ai-dlc-skill/walkthrough/collect.sh +1 -1
- package/ai-dlc-skill/walkthrough/template.md +2 -2
- package/ai-dlc-skill/workflows/ai-dlc.yaml +12 -12
- package/ai-dlc-skill/workflows/deployment.yaml +4 -4
- package/cdh/__pycache__/cdh_mcp_injector.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_mcp_loader.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_mcp_manager.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_session_aggregator.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_skill_loader.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_skill_manager.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cli.cpython-313.pyc +0 -0
- package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
- package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
- package/cdh/cdh_mcp_injector.py +115 -0
- package/cdh/cdh_mcp_loader.py +67 -0
- package/cdh/cdh_mcp_manager.py +73 -0
- package/cdh/cdh_session_aggregator.py +258 -0
- package/cdh/cdh_skill_manager.py +105 -0
- package/cdh/cli.py +64 -4
- package/cdh/scaffold.py +192 -41
- package/onecode/__init__.py +1 -1
- package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
- package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config_screen.cpython-314.pyc +0 -0
- package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
- package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
- package/onecode/agent/agents/types.py +47 -164
- package/onecode/agent/attachments.py +0 -1
- package/onecode/agent/cdh_loader.py +17 -25
- package/onecode/agent/context.py +8 -3
- package/onecode/agent/engine.py +835 -220
- package/onecode/agent/hooks.py +1 -1
- package/onecode/agent/onecode_agent_acp.py +460 -47
- package/onecode/agent/onecode_agent_acp.py.bak +2447 -0
- package/onecode/agent/permissions.py +0 -1
- package/onecode/agent/project_doc.py +19 -0
- package/onecode/agent/session.py +17 -3
- package/onecode/agent/snapshot.py +3 -4
- package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/agent_tools.py +4 -6
- package/onecode/agent/tools/apply_patch_tool.py +2 -8
- package/onecode/agent/tools/bash_tool.py +32 -12
- package/onecode/agent/tools/communication_tools.py +4 -5
- package/onecode/agent/tools/config_tool.py +3 -3
- package/onecode/agent/tools/cron_tools.py +4 -5
- package/onecode/agent/tools/file_ops.py +37 -3
- package/onecode/agent/tools/file_tools.py +10 -11
- package/onecode/agent/tools/git_tools.py +2 -2
- package/onecode/agent/tools/lsp_tools.py +2 -2
- package/onecode/agent/tools/mcp_tools.py +3 -5
- package/onecode/agent/tools/permission_handler.py +1 -1
- package/onecode/agent/tools/protocol.py +1 -1
- package/onecode/agent/tools/registry.py +69 -2
- package/onecode/agent/tools/sandbox.py +110 -16
- package/onecode/agent/tools/skill_tools.py +2 -2
- package/onecode/agent/tools/todo_tools.py +38 -19
- package/onecode/agent/tools/web_tools.py +6 -7
- package/onecode/builtin_skills/agent-browser/SKILL.md +212 -0
- package/onecode/builtin_skills/agent-browser/skill.yaml +8 -0
- package/onecode/builtin_skills/skill-creator/SKILL.md +106 -0
- package/onecode/builtin_skills/skill-creator/skill.yaml +8 -0
- package/onecode/cli.py +186 -6
- package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
- package/onecode/codebase/chunker.py +0 -5
- package/onecode/codebase/indexer.py +14 -1
- package/onecode/codebase/retriever.py +13 -2
- package/onecode/codebase/storage.py +5 -4
- package/onecode/commands.py +81 -6
- package/onecode/config.py +41 -12
- package/onecode/config_screen.py +7 -3
- package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
- package/onecode/mcp/manager.py +2 -3
- package/onecode/memory/__init__.py +7 -53
- package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/offload.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
- package/onecode/memory/backend.py +13 -39
- package/onecode/memory/pyramid.py +2 -71
- package/onecode/memory/recall.py +38 -3
- package/onecode/migrate.py +122 -0
- package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
- package/onecode/models/messages.py +58 -0
- package/onecode/models/provider.py +20 -2
- package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/anthropic_provider.py +59 -12
- package/onecode/models/providers/glm_provider.py +40 -0
- package/onecode/models/providers/minimax_provider.py +3 -0
- package/onecode/models/providers/minimaxi_provider.py +3 -0
- package/onecode/models/providers/ollama_provider.py +3 -0
- package/onecode/server/app.py +1 -1
- package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/manager.cpython-314.pyc +0 -0
- package/onecode/skills/argument_substitution.py +0 -1
- package/onecode/skills/bootstrap.py +124 -0
- package/onecode/skills/loader.py +35 -53
- package/onecode/skills/manager.py +2 -2
- package/onecode/storage/activity.py +3 -4
- package/onecode/storage/session.py +3 -4
- package/onecode/tasks/manager.py +23 -10
- package/onecode/trace/tracer.py +2 -3
- package/package.json +1 -1
- package/pyproject.toml +5 -1
- package/run.js +68 -14
- package/tui/__pycache__/about.cpython-314.pyc +0 -0
- package/tui/__pycache__/app.cpython-313.pyc +0 -0
- package/tui/__pycache__/app.cpython-314.pyc +0 -0
- package/tui/__pycache__/danger.cpython-314.pyc +0 -0
- package/tui/__pycache__/directory_suggester.cpython-314.pyc +0 -0
- package/tui/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
- package/tui/__pycache__/paths.cpython-314.pyc +0 -0
- package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
- package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
- package/tui/acp/agent.py +125 -58
- package/tui/acp/api.py +12 -0
- package/tui/acp/messages.py +3 -1
- package/tui/acp/prompt.py +0 -57
- package/tui/acp/protocol.py +6 -0
- package/tui/app.py +11 -33
- package/tui/messages.py +2 -0
- package/tui/path_complete.py +1 -1
- package/tui/paths.py +16 -0
- package/tui/screens/__pycache__/agent_modal.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/component_picker.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/log.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/main.cpython-313.pyc +0 -0
- package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/permissions.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/projects_app.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/projects_screen.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/store.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/tool_content_screen.cpython-314.pyc +0 -0
- package/tui/screens/component_picker.py +35 -15
- package/tui/screens/diff_screen.py +84 -0
- package/tui/screens/log.py +25 -25
- package/tui/screens/main.py +48 -26
- package/tui/screens/projects.tcss +5 -1
- package/tui/screens/projects_app.py +6 -6
- package/tui/screens/projects_screen.py +19 -39
- package/tui/screens/sessions.py +3 -5
- package/tui/session_tracker.py +3 -0
- package/tui/settings_schema.py +1 -1
- package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
- package/tui/visuals/columns.py +1 -2
- package/tui/widgets/__pycache__/acp_content.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/directory_input.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/mandelbrot.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/markdown_note.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/project_grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/project_summary.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/shell_result.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/subagent.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/subagent_screen.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
- package/tui/widgets/agent_response.py +0 -1
- package/tui/widgets/agent_thought.py +0 -1
- package/tui/widgets/conversation.py +157 -14
- package/tui/widgets/diff_view.py +10 -0
- package/tui/widgets/load_more.py +24 -0
- package/tui/widgets/modified_files.py +86 -12
- package/tui/widgets/plan.py +1 -1
- package/tui/widgets/project_grid_select.py +9 -2
- package/tui/widgets/session_grid_select.py +6 -0
- package/tui/widgets/side_bar.py +10 -0
- package/tui/widgets/subagent.py +92 -58
- package/tui/widgets/subagent_screen.py +638 -115
- package/tui/widgets/terminal.py +1 -2
- package/tui/widgets/terminal_tool.py +11 -2
- package/tui/widgets/tool_call.py +35 -2
- package/onecode/memory/offload.py +0 -114
- package/onecode/memory/symbolic.py +0 -164
package/tui/widgets/terminal.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
|
|
3
3
|
from time import monotonic
|
|
4
|
-
from typing import Awaitable, Callable
|
|
4
|
+
from typing import Awaitable, Callable
|
|
5
5
|
|
|
6
6
|
from textual.cache import LRUCache
|
|
7
7
|
|
|
@@ -18,7 +18,6 @@ from textual.strip import Strip
|
|
|
18
18
|
from textual.timer import Timer
|
|
19
19
|
|
|
20
20
|
from tui import ansi
|
|
21
|
-
from tui.menus import MenuItem
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
# Time required to double tab escape
|
|
@@ -11,14 +11,13 @@ from collections import deque
|
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
import struct
|
|
13
13
|
import termios
|
|
14
|
-
from typing import
|
|
14
|
+
from typing import Mapping
|
|
15
15
|
|
|
16
16
|
from textual.content import Content
|
|
17
17
|
from textual.reactive import var
|
|
18
18
|
|
|
19
19
|
from tui.shell_read import shell_read
|
|
20
20
|
from tui.widgets.terminal import Terminal
|
|
21
|
-
from tui.menus import MenuItem
|
|
22
21
|
|
|
23
22
|
|
|
24
23
|
@dataclass
|
|
@@ -249,6 +248,16 @@ class TerminalTool(Terminal):
|
|
|
249
248
|
break
|
|
250
249
|
finally:
|
|
251
250
|
transport.close()
|
|
251
|
+
try:
|
|
252
|
+
write_transport.close()
|
|
253
|
+
except Exception:
|
|
254
|
+
pass
|
|
255
|
+
if self._shell_fd is not None:
|
|
256
|
+
try:
|
|
257
|
+
os.close(self._shell_fd)
|
|
258
|
+
except OSError:
|
|
259
|
+
pass
|
|
260
|
+
self._shell_fd = None
|
|
252
261
|
|
|
253
262
|
self.finalize()
|
|
254
263
|
return_code = self._return_code = await process.wait()
|
package/tui/widgets/tool_call.py
CHANGED
|
@@ -136,7 +136,26 @@ class ToolCall(containers.VerticalGroup):
|
|
|
136
136
|
super().__init__(id=id, classes=classes)
|
|
137
137
|
|
|
138
138
|
async def update_tool_call(self, tool_call: protocol.ToolCall) -> None:
|
|
139
|
+
old_call = self.tool_call
|
|
140
|
+
old_status = old_call.get("status") if old_call else None
|
|
141
|
+
old_content_len = len(old_call.get("content", [])) if old_call else 0
|
|
142
|
+
new_status = tool_call.get("status")
|
|
143
|
+
new_content = tool_call.get("content", [])
|
|
144
|
+
|
|
139
145
|
self.tool_call = tool_call
|
|
146
|
+
|
|
147
|
+
# Update header immediately (cheap)
|
|
148
|
+
try:
|
|
149
|
+
self.query_one(ToolCallHeader).update(self.tool_call_header_content)
|
|
150
|
+
except NoMatches:
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
if old_status != new_status:
|
|
154
|
+
self.check_expand()
|
|
155
|
+
|
|
156
|
+
# Skip full recompose if nothing material changed
|
|
157
|
+
if old_status == new_status and old_content_len == len(new_content):
|
|
158
|
+
return
|
|
140
159
|
await self.recompose()
|
|
141
160
|
|
|
142
161
|
def get_block_menu(self) -> Iterable[MenuItem]:
|
|
@@ -192,10 +211,18 @@ class ToolCall(containers.VerticalGroup):
|
|
|
192
211
|
return
|
|
193
212
|
tool_call = self.tool_call
|
|
194
213
|
assert tool_call is not None
|
|
195
|
-
|
|
214
|
+
kind = tool_call.get("kind", "")
|
|
215
|
+
if kind == "read":
|
|
196
216
|
return
|
|
197
|
-
|
|
217
|
+
|
|
198
218
|
status = tool_call.get("status")
|
|
219
|
+
|
|
220
|
+
# write/edit: always expanded
|
|
221
|
+
if kind == "edit":
|
|
222
|
+
self.expanded = True
|
|
223
|
+
return
|
|
224
|
+
|
|
225
|
+
tool_call_expand = self.app.settings.get("tools.expand", str, expand=False)
|
|
199
226
|
if tool_call_expand == "always":
|
|
200
227
|
self.expanded = True
|
|
201
228
|
elif tool_call_expand != "never" and status is not None:
|
|
@@ -303,6 +330,12 @@ class ToolCall(containers.VerticalGroup):
|
|
|
303
330
|
def _compose_content(
|
|
304
331
|
self, tool_call_content: list[protocol.ToolCallContent]
|
|
305
332
|
) -> ComposeResult:
|
|
333
|
+
# TodoCreate/TodoList/TodoUpdate return trivial "updated" text - skip display
|
|
334
|
+
title = self.tool_call.get("title", "") if self.tool_call else ""
|
|
335
|
+
tool_name = title.split(":")[0] if ":" in title else title
|
|
336
|
+
if tool_name in ("TodoCreate", "TodoList", "TodoUpdate"):
|
|
337
|
+
return
|
|
338
|
+
|
|
306
339
|
found = False
|
|
307
340
|
for widget in compose_tool_content(tool_call_content, self.app):
|
|
308
341
|
yield widget
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
import fnmatch
|
|
5
|
-
from dataclasses import dataclass
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from typing import Optional
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@dataclass
|
|
11
|
-
class OffloadConfig:
|
|
12
|
-
enabled: bool = True
|
|
13
|
-
mild_ratio: float = 0.5
|
|
14
|
-
aggressive_ratio: float = 0.85
|
|
15
|
-
mmd_max_token_ratio: float = 0.2
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ContextOffloader:
|
|
19
|
-
def __init__(
|
|
20
|
-
self,
|
|
21
|
-
refs_dir: Optional[Path] = None,
|
|
22
|
-
config: Optional[OffloadConfig] = None,
|
|
23
|
-
):
|
|
24
|
-
from onecode.config import CLOUD_DEV_HARNESS_DIR
|
|
25
|
-
self.refs_dir = refs_dir or (CLOUD_DEV_HARNESS_DIR / "memory" / "refs")
|
|
26
|
-
self.refs_dir.mkdir(parents=True, exist_ok=True)
|
|
27
|
-
self.config = config or OffloadConfig()
|
|
28
|
-
self._offloaded_refs: dict[str, Path] = {}
|
|
29
|
-
|
|
30
|
-
def should_offload(self, context_length: int, max_tokens: int) -> tuple[bool, str]:
|
|
31
|
-
if not self.config.enabled:
|
|
32
|
-
return False, "disabled"
|
|
33
|
-
|
|
34
|
-
ratio = context_length / max_tokens if max_tokens > 0 else 0
|
|
35
|
-
|
|
36
|
-
if ratio >= self.config.aggressive_ratio:
|
|
37
|
-
return True, "aggressive"
|
|
38
|
-
elif ratio >= self.config.mild_ratio:
|
|
39
|
-
return True, "mild"
|
|
40
|
-
return False, "none"
|
|
41
|
-
|
|
42
|
-
def offload_content(
|
|
43
|
-
self,
|
|
44
|
-
content: str,
|
|
45
|
-
node_id: str,
|
|
46
|
-
file_pattern: str = "*.md",
|
|
47
|
-
) -> str:
|
|
48
|
-
ext = file_pattern.replace("*", "md")
|
|
49
|
-
ref_file = self.refs_dir / f"{node_id}.{ext}"
|
|
50
|
-
ref_file.write_text(content, encoding="utf-8")
|
|
51
|
-
self._offloaded_refs[node_id] = ref_file
|
|
52
|
-
return f"See refs/{node_id}.{ext}"
|
|
53
|
-
|
|
54
|
-
def recall_ref(self, node_id: str) -> Optional[str]:
|
|
55
|
-
ref_file = self._offloaded_refs.get(node_id)
|
|
56
|
-
if ref_file and ref_file.exists():
|
|
57
|
-
return ref_file.read_text(encoding="utf-8")
|
|
58
|
-
for ext in ["md", "txt", "log"]:
|
|
59
|
-
alt_path = self.refs_dir / f"{node_id}.{ext}"
|
|
60
|
-
if alt_path.exists():
|
|
61
|
-
return alt_path.read_text(encoding="utf-8")
|
|
62
|
-
return None
|
|
63
|
-
|
|
64
|
-
def list_offloaded(self) -> list[str]:
|
|
65
|
-
return list(self._offloaded_refs.keys())
|
|
66
|
-
|
|
67
|
-
def cleanup_old_refs(self, max_age_hours: int = 24) -> int:
|
|
68
|
-
import time
|
|
69
|
-
from datetime import datetime, timezone
|
|
70
|
-
removed = 0
|
|
71
|
-
for ref_file in self.refs_dir.iterdir():
|
|
72
|
-
if ref_file.is_file():
|
|
73
|
-
age_hours = (time.time() - ref_file.stat().st_mtime) / 3600
|
|
74
|
-
if age_hours > max_age_hours:
|
|
75
|
-
ref_file.unlink()
|
|
76
|
-
node_id = ref_file.stem
|
|
77
|
-
if node_id in self._offloaded_refs:
|
|
78
|
-
del self._offloaded_refs[node_id]
|
|
79
|
-
removed += 1
|
|
80
|
-
return removed
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
class ToolCallExtractor:
|
|
84
|
-
PATTERNS = [
|
|
85
|
-
re.compile(r'\[TOOL_CALL\]\s*(\w+)\s*:\s*(.+)', re.DOTALL),
|
|
86
|
-
re.compile(r'"tool":\s*"(\w+)"[^}]*"args":\s*({.+?})', re.DOTALL),
|
|
87
|
-
re.compile(r'(\w+)\((.*?)\)\s*=>\s*(.+)', re.DOTALL),
|
|
88
|
-
]
|
|
89
|
-
|
|
90
|
-
@classmethod
|
|
91
|
-
def extract_calls(cls, text: str) -> list[dict]:
|
|
92
|
-
calls = []
|
|
93
|
-
for pattern in cls.PATTERNS:
|
|
94
|
-
matches = pattern.finditer(text)
|
|
95
|
-
for match in matches:
|
|
96
|
-
if pattern == cls.PATTERNS[0]:
|
|
97
|
-
calls.append({"tool": match.group(1), "args": match.group(2)})
|
|
98
|
-
elif pattern == cls.PATTERNS[1]:
|
|
99
|
-
calls.append({"tool": match.group(1), "args": match.group(2)})
|
|
100
|
-
else:
|
|
101
|
-
calls.append({"tool": match.group(1), "args": match.group(2), "result": match.group(3)})
|
|
102
|
-
return calls
|
|
103
|
-
|
|
104
|
-
@classmethod
|
|
105
|
-
def format_as_mermaid(cls, calls: list[dict]) -> str:
|
|
106
|
-
lines = ["graph LR"]
|
|
107
|
-
for i, call in enumerate(calls):
|
|
108
|
-
node_id = f"C{i:03d}"
|
|
109
|
-
tool_name = call.get("tool", "unknown")
|
|
110
|
-
lines.append(f" {node_id}[{tool_name}]")
|
|
111
|
-
if i > 0:
|
|
112
|
-
prev_id = f"C{i-1:03d}"
|
|
113
|
-
lines.append(f" {prev_id} --> {node_id}")
|
|
114
|
-
return "\n".join(lines)
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import re
|
|
4
|
-
import uuid
|
|
5
|
-
from dataclasses import dataclass, field
|
|
6
|
-
from datetime import datetime, timezone
|
|
7
|
-
from enum import Enum
|
|
8
|
-
from typing import Optional
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class NodeType(Enum):
|
|
12
|
-
TASK = "task"
|
|
13
|
-
ACTION = "action"
|
|
14
|
-
RESULT = "result"
|
|
15
|
-
ERROR = "error"
|
|
16
|
-
CHECKPOINT = "checkpoint"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass
|
|
20
|
-
class MermaidNode:
|
|
21
|
-
node_id: str
|
|
22
|
-
node_type: NodeType
|
|
23
|
-
label: str
|
|
24
|
-
metadata: dict = field(default_factory=dict)
|
|
25
|
-
|
|
26
|
-
def to_mermaid(self) -> str:
|
|
27
|
-
type_styles = {
|
|
28
|
-
NodeType.TASK: "([,shape=ellipse",
|
|
29
|
-
NodeType.ACTION: "[,shape=box",
|
|
30
|
-
NodeType.RESULT: "[(,shape=cylinder",
|
|
31
|
-
NodeType.ERROR: "([,shape=ellipse,color=red",
|
|
32
|
-
NodeType.CHECKPOINT: "[,shape=diamond",
|
|
33
|
-
}
|
|
34
|
-
style = type_styles.get(self.node_type, "[")
|
|
35
|
-
return f" {self.node_id}{style} {self.label}])"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@dataclass
|
|
39
|
-
class MermaidEdge:
|
|
40
|
-
from_node: str
|
|
41
|
-
to_node: str
|
|
42
|
-
label: Optional[str] = None
|
|
43
|
-
style: str = ""
|
|
44
|
-
|
|
45
|
-
def to_mermaid(self) -> str:
|
|
46
|
-
edge_str = f" {self.from_node} --> {self.to_node}"
|
|
47
|
-
if self.label:
|
|
48
|
-
edge_str = f" {self.from_node} -->|{self.label}| {self.to_node}"
|
|
49
|
-
if self.style:
|
|
50
|
-
edge_str += f" -. {self.style} .-> {self.to_node}"
|
|
51
|
-
return edge_str
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class MermaidCanvas:
|
|
55
|
-
def __init__(self, task_id: Optional[str] = None):
|
|
56
|
-
self.task_id = task_id or str(uuid.uuid4())[:8]
|
|
57
|
-
self.nodes: list[MermaidNode] = []
|
|
58
|
-
self.edges: list[MermaidEdge] = []
|
|
59
|
-
self.refs: dict[str, str] = {}
|
|
60
|
-
|
|
61
|
-
def add_node(
|
|
62
|
-
self,
|
|
63
|
-
node_type: NodeType,
|
|
64
|
-
label: str,
|
|
65
|
-
metadata: Optional[dict] = None,
|
|
66
|
-
) -> str:
|
|
67
|
-
node_id = f"N{len(self.nodes):03d}"
|
|
68
|
-
node = MermaidNode(node_id, node_type, label, metadata or {})
|
|
69
|
-
self.nodes.append(node)
|
|
70
|
-
return node_id
|
|
71
|
-
|
|
72
|
-
def add_edge(
|
|
73
|
-
self,
|
|
74
|
-
from_node: str,
|
|
75
|
-
to_node: str,
|
|
76
|
-
label: Optional[str] = None,
|
|
77
|
-
style: str = "",
|
|
78
|
-
) -> None:
|
|
79
|
-
edge = MermaidEdge(from_node, to_node, label, style)
|
|
80
|
-
self.edges.append(edge)
|
|
81
|
-
|
|
82
|
-
def add_ref(self, node_id: str, content: str) -> None:
|
|
83
|
-
self.refs[node_id] = content
|
|
84
|
-
|
|
85
|
-
def get_ref(self, node_id: str) -> Optional[str]:
|
|
86
|
-
return self.refs.get(node_id)
|
|
87
|
-
|
|
88
|
-
def to_mermaid(self) -> str:
|
|
89
|
-
if not self.nodes:
|
|
90
|
-
return "graph LR\n empty((empty))"
|
|
91
|
-
|
|
92
|
-
lines = ["graph LR"]
|
|
93
|
-
for node in self.nodes:
|
|
94
|
-
lines.append(node.to_mermaid())
|
|
95
|
-
for edge in self.edges:
|
|
96
|
-
lines.append(edge.to_mermaid())
|
|
97
|
-
return "\n".join(lines)
|
|
98
|
-
|
|
99
|
-
def to_markdown(self) -> str:
|
|
100
|
-
lines = [f"## Task Canvas: {self.task_id}\n"]
|
|
101
|
-
lines.append(f"Generated: {datetime.now(timezone.utc).isoformat()}\n")
|
|
102
|
-
lines.append("### Mermaid Diagram\n```mermaid")
|
|
103
|
-
lines.append(self.to_mermaid())
|
|
104
|
-
lines.append("```\n")
|
|
105
|
-
if self.refs:
|
|
106
|
-
lines.append("### References\n")
|
|
107
|
-
for node_id, content in self.refs.items():
|
|
108
|
-
lines.append(f"**{node_id}**: {content[:200]}...\n")
|
|
109
|
-
return "\n".join(lines)
|
|
110
|
-
|
|
111
|
-
@classmethod
|
|
112
|
-
def from_mermaid(cls, mermaid_text: str) -> Optional["MermaidCanvas"]:
|
|
113
|
-
try:
|
|
114
|
-
canvas = cls()
|
|
115
|
-
node_pattern = re.compile(r"(\w+)\[(.*?)\]")
|
|
116
|
-
for match in node_pattern.finditer(mermaid_text):
|
|
117
|
-
node_id, label = match.groups()
|
|
118
|
-
if node_id.startswith("N"):
|
|
119
|
-
canvas.add_node(NodeType.ACTION, label)
|
|
120
|
-
return canvas
|
|
121
|
-
except Exception:
|
|
122
|
-
return None
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class SymbolicMemory:
|
|
126
|
-
def __init__(self, canvas: Optional[MermaidCanvas] = None):
|
|
127
|
-
self.canvas = canvas or MermaidCanvas()
|
|
128
|
-
self._verbose_cache: dict[str, str] = {}
|
|
129
|
-
|
|
130
|
-
def offload_log(self, node_id: str, verbose_content: str) -> str:
|
|
131
|
-
self._verbose_cache[node_id] = verbose_content
|
|
132
|
-
self.canvas.add_ref(node_id, f"See ref: {node_id}")
|
|
133
|
-
return f"[{node_id}]"
|
|
134
|
-
|
|
135
|
-
def recall_log(self, node_id: str) -> Optional[str]:
|
|
136
|
-
return self._verbose_cache.get(node_id)
|
|
137
|
-
|
|
138
|
-
def create_task_node(self, label: str, metadata: Optional[dict] = None) -> str:
|
|
139
|
-
return self.canvas.add_node(NodeType.TASK, label, metadata)
|
|
140
|
-
|
|
141
|
-
def create_action_node(self, label: str, metadata: Optional[dict] = None) -> str:
|
|
142
|
-
return self.canvas.add_node(NodeType.ACTION, label, metadata)
|
|
143
|
-
|
|
144
|
-
def create_result_node(self, label: str, result_content: str, metadata: Optional[dict] = None) -> str:
|
|
145
|
-
node_id = self.canvas.add_node(NodeType.RESULT, label, metadata)
|
|
146
|
-
self.offload_log(node_id, result_content)
|
|
147
|
-
return node_id
|
|
148
|
-
|
|
149
|
-
def create_error_node(self, label: str, error_content: str, metadata: Optional[dict] = None) -> str:
|
|
150
|
-
node_id = self.canvas.add_node(NodeType.ERROR, label, metadata)
|
|
151
|
-
self.offload_log(node_id, error_content)
|
|
152
|
-
return node_id
|
|
153
|
-
|
|
154
|
-
def link(self, from_id: str, to_id: str, label: Optional[str] = None) -> None:
|
|
155
|
-
self.canvas.add_edge(from_id, to_id, label)
|
|
156
|
-
|
|
157
|
-
def get_canvas_markdown(self) -> str:
|
|
158
|
-
return self.canvas.to_markdown()
|
|
159
|
-
|
|
160
|
-
def get_canvas_mermaid(self) -> str:
|
|
161
|
-
return self.canvas.to_mermaid()
|
|
162
|
-
|
|
163
|
-
def get_ref_content(self, node_id: str) -> Optional[str]:
|
|
164
|
-
return self._verbose_cache.get(node_id)
|