@scemoon/cdh 1.0.4 → 1.0.5
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 +14 -3
- 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/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
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
import uuid
|
|
5
4
|
from datetime import datetime, timezone
|
|
6
5
|
from pathlib import Path
|
|
7
6
|
from typing import Optional
|
|
8
7
|
|
|
9
|
-
from sqlalchemy import Column, String,
|
|
8
|
+
from sqlalchemy import Column, String, DateTime, JSON, create_engine
|
|
10
9
|
from sqlalchemy.orm import declarative_base, sessionmaker
|
|
11
10
|
|
|
12
|
-
from onecode.config import
|
|
11
|
+
from onecode.config import ONECODE_DIR
|
|
13
12
|
|
|
14
13
|
Base = declarative_base()
|
|
15
14
|
|
|
@@ -28,7 +27,7 @@ class ActivityRecord(Base):
|
|
|
28
27
|
class ActivityRecorder:
|
|
29
28
|
def __init__(self, db_path: Optional[Path] = None):
|
|
30
29
|
if db_path is None:
|
|
31
|
-
db_path =
|
|
30
|
+
db_path = ONECODE_DIR / "sessions" / "cdh.db"
|
|
32
31
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
33
32
|
self.engine = create_engine(f"sqlite:///{db_path}")
|
|
34
33
|
Base.metadata.create_all(self.engine)
|
|
@@ -9,14 +9,13 @@ from typing import Optional
|
|
|
9
9
|
from sqlalchemy import (
|
|
10
10
|
Column,
|
|
11
11
|
String,
|
|
12
|
-
Text,
|
|
13
12
|
DateTime,
|
|
14
13
|
JSON,
|
|
15
14
|
create_engine,
|
|
16
15
|
)
|
|
17
|
-
from sqlalchemy.orm import declarative_base,
|
|
16
|
+
from sqlalchemy.orm import declarative_base, sessionmaker
|
|
18
17
|
|
|
19
|
-
from onecode.config import
|
|
18
|
+
from onecode.config import ONECODE_DIR
|
|
20
19
|
|
|
21
20
|
Base = declarative_base()
|
|
22
21
|
|
|
@@ -43,7 +42,7 @@ class SessionRecord(Base):
|
|
|
43
42
|
class SessionStore:
|
|
44
43
|
def __init__(self, db_path: Optional[Path] = None):
|
|
45
44
|
if db_path is None:
|
|
46
|
-
db_path =
|
|
45
|
+
db_path = ONECODE_DIR / "sessions" / "cdh.db"
|
|
47
46
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
48
47
|
self.engine = create_engine(f"sqlite:///{db_path}")
|
|
49
48
|
Base.metadata.create_all(self.engine)
|
package/onecode/tasks/manager.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
5
|
import uuid
|
|
6
|
-
from dataclasses import dataclass
|
|
6
|
+
from dataclasses import dataclass
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Any, Callable, Optional
|
|
@@ -16,8 +16,6 @@ from onecode.tasks.models import (
|
|
|
16
16
|
TaskChecklistState,
|
|
17
17
|
TaskGateRecord,
|
|
18
18
|
TaskToolCallSummary,
|
|
19
|
-
TodoItem,
|
|
20
|
-
TodoStatus,
|
|
21
19
|
)
|
|
22
20
|
|
|
23
21
|
|
|
@@ -56,6 +54,8 @@ class TaskManager:
|
|
|
56
54
|
self._storage_path = storage_path or Path.home() / ".cdh" / "tasks"
|
|
57
55
|
self._executor: Optional[TaskExecutor] = None
|
|
58
56
|
self._worker_task: Optional[asyncio.Task] = None
|
|
57
|
+
self._semaphore = asyncio.Semaphore(5)
|
|
58
|
+
self._shutdown: bool = False
|
|
59
59
|
|
|
60
60
|
def set_executor(self, executor: TaskExecutor) -> None:
|
|
61
61
|
self._executor = executor
|
|
@@ -90,11 +90,14 @@ class TaskManager:
|
|
|
90
90
|
self._worker_task = asyncio.create_task(self._worker_loop())
|
|
91
91
|
|
|
92
92
|
async def _worker_loop(self) -> None:
|
|
93
|
-
while
|
|
93
|
+
while not self._shutdown:
|
|
94
94
|
try:
|
|
95
|
-
task = await self._queue.get()
|
|
95
|
+
task = await asyncio.wait_for(self._queue.get(), timeout=30)
|
|
96
96
|
if task.id not in self._running:
|
|
97
|
-
|
|
97
|
+
async with self._semaphore:
|
|
98
|
+
self._running[task.id] = asyncio.create_task(self._run_task(task))
|
|
99
|
+
except asyncio.TimeoutError:
|
|
100
|
+
continue
|
|
98
101
|
except asyncio.CancelledError:
|
|
99
102
|
break
|
|
100
103
|
except Exception as e:
|
|
@@ -112,7 +115,10 @@ class TaskManager:
|
|
|
112
115
|
if self._executor:
|
|
113
116
|
cancel = asyncio.Event()
|
|
114
117
|
events: asyncio.Queue = asyncio.Queue()
|
|
115
|
-
result = await
|
|
118
|
+
result = await asyncio.wait_for(
|
|
119
|
+
self._executor.execute(execution, events, cancel),
|
|
120
|
+
timeout=300,
|
|
121
|
+
)
|
|
116
122
|
task_record.status = TaskStatus.COMPLETED if result.get("success") else TaskStatus.FAILED
|
|
117
123
|
task_record.error = result.get("error")
|
|
118
124
|
else:
|
|
@@ -147,8 +153,7 @@ class TaskManager:
|
|
|
147
153
|
return list(self._tasks.values())
|
|
148
154
|
return [t for t in self._tasks.values() if t.status == status]
|
|
149
155
|
|
|
150
|
-
def add_todo_to_task(self, task_id: str, content: str, status: str = "pending") -> Optional["TaskChecklistItem"]:
|
|
151
|
-
from onecode.tasks.models import TaskChecklistItem
|
|
156
|
+
def add_todo_to_task(self, task_id: str, content: str, status: str = "pending") -> Optional["TaskChecklistItem"]: # noqa: F821
|
|
152
157
|
task = self._tasks.get(task_id)
|
|
153
158
|
if not task:
|
|
154
159
|
return None
|
|
@@ -211,9 +216,17 @@ class TaskManager:
|
|
|
211
216
|
return True
|
|
212
217
|
|
|
213
218
|
async def stop(self) -> None:
|
|
219
|
+
self._shutdown = True
|
|
214
220
|
if self._worker_task:
|
|
215
221
|
self._worker_task.cancel()
|
|
216
222
|
try:
|
|
217
223
|
await self._worker_task
|
|
218
224
|
except asyncio.CancelledError:
|
|
219
|
-
pass
|
|
225
|
+
pass
|
|
226
|
+
if self._running:
|
|
227
|
+
results = await asyncio.gather(
|
|
228
|
+
*self._running.values(), return_exceptions=True,
|
|
229
|
+
)
|
|
230
|
+
for tid, res in zip(list(self._running.keys()), results):
|
|
231
|
+
if isinstance(res, Exception):
|
|
232
|
+
logger.warning("Task %s exited with error: %s", tid, res)
|
package/onecode/trace/tracer.py
CHANGED
|
@@ -5,10 +5,9 @@ import time
|
|
|
5
5
|
import uuid
|
|
6
6
|
from contextlib import contextmanager
|
|
7
7
|
from datetime import datetime, timezone
|
|
8
|
-
from pathlib import Path
|
|
9
8
|
from typing import Any, Optional
|
|
10
9
|
|
|
11
|
-
from onecode.config import
|
|
10
|
+
from onecode.config import ONECODE_DIR
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
class Span:
|
|
@@ -55,7 +54,7 @@ class Tracer:
|
|
|
55
54
|
self.recording: bool = False
|
|
56
55
|
self.spans: list[Span] = []
|
|
57
56
|
self.stack: list[str] = []
|
|
58
|
-
self.trace_dir =
|
|
57
|
+
self.trace_dir = ONECODE_DIR / "traces"
|
|
59
58
|
self.trace_dir.mkdir(parents=True, exist_ok=True)
|
|
60
59
|
self._otlp_endpoint: Optional[str] = None
|
|
61
60
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cloud-dev-harness"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.5"
|
|
4
4
|
description = "Cloud Dev Harness - cloud-native development Agent framework with A2TUI"
|
|
5
5
|
requires-python = ">=3.14.2"
|
|
6
6
|
dependencies = [
|
|
@@ -57,6 +57,9 @@ onecode = [
|
|
|
57
57
|
"builtin_skills/**/*",
|
|
58
58
|
]
|
|
59
59
|
|
|
60
|
+
[tool.ruff]
|
|
61
|
+
exclude = ["tui/", "dist/", ".venv/"]
|
|
62
|
+
|
|
60
63
|
[tool.pytest.ini_options]
|
|
61
64
|
asyncio_mode = "auto"
|
|
62
65
|
|
|
@@ -66,5 +69,6 @@ dev = [
|
|
|
66
69
|
"pyinstrument>=5.1.1",
|
|
67
70
|
"pytest>=9.0.3",
|
|
68
71
|
"pytest-asyncio>=1.4.0",
|
|
72
|
+
"pytest-cov>=6.0.0",
|
|
69
73
|
"textual-dev>=1.8.0",
|
|
70
74
|
]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/tui/acp/agent.py
CHANGED
|
@@ -28,7 +28,6 @@ from tui.acp import messages
|
|
|
28
28
|
from tui.acp.prompt import build as build_prompt
|
|
29
29
|
from tui import messages as tui_messages
|
|
30
30
|
from tui.db import DB
|
|
31
|
-
from tui import paths
|
|
32
31
|
from tui import constants
|
|
33
32
|
from tui.answer import Answer
|
|
34
33
|
|
|
@@ -88,6 +87,7 @@ class Agent(AgentBase):
|
|
|
88
87
|
self._message_target: MessagePump | None = None
|
|
89
88
|
|
|
90
89
|
self._terminal_count: int = 0
|
|
90
|
+
self.session_load_info: dict = {}
|
|
91
91
|
|
|
92
92
|
@property
|
|
93
93
|
def command(self) -> str | None:
|
|
@@ -122,9 +122,14 @@ class Agent(AgentBase):
|
|
|
122
122
|
request: JSONRPC request object.
|
|
123
123
|
|
|
124
124
|
"""
|
|
125
|
-
|
|
125
|
+
if self._process is None:
|
|
126
|
+
logger.warning(
|
|
127
|
+
"Cannot send request %s: agent process is not running",
|
|
128
|
+
request.body,
|
|
129
|
+
)
|
|
130
|
+
return
|
|
126
131
|
|
|
127
|
-
logger.
|
|
132
|
+
logger.info("[client] send: %s", request.body)
|
|
128
133
|
if (stdin := self._process.stdin) is not None:
|
|
129
134
|
stdin.write(b"%s\n" % request.body_json)
|
|
130
135
|
|
|
@@ -542,61 +547,64 @@ class Agent(AgentBase):
|
|
|
542
547
|
if (task := asyncio.current_task()) is not None:
|
|
543
548
|
tasks.discard(task)
|
|
544
549
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
try:
|
|
553
|
-
line_str = line.decode("utf-8")
|
|
554
|
-
except Exception as error:
|
|
555
|
-
logger.error("Unable to decode utf-8 from agent: %s", error)
|
|
556
|
-
continue
|
|
557
|
-
|
|
558
|
-
logger.debug("[agent] %s", line_str.rstrip())
|
|
559
|
-
try:
|
|
560
|
-
agent_data: jsonrpc.JSONType = json.loads(line_str)
|
|
561
|
-
except Exception as error:
|
|
562
|
-
logger.error("Failed to decode JSON from agent: %s", error)
|
|
563
|
-
continue
|
|
564
|
-
|
|
565
|
-
if isinstance(agent_data, dict):
|
|
566
|
-
if "result" in agent_data or "error" in agent_data:
|
|
567
|
-
# Wait for pending notification dispatch tasks so all ACP
|
|
568
|
-
# messages are queued before the response future resolves.
|
|
569
|
-
if tasks:
|
|
570
|
-
await asyncio.gather(*tasks, return_exceptions=True)
|
|
571
|
-
tasks.clear()
|
|
572
|
-
API.process_response(agent_data)
|
|
550
|
+
try:
|
|
551
|
+
while line := await process.stdout.readline():
|
|
552
|
+
# This line should contain JSON, which may be:
|
|
553
|
+
# A) a JSONRPC request
|
|
554
|
+
# B) a JSONRPC response to a previous request
|
|
555
|
+
if not line.strip():
|
|
573
556
|
continue
|
|
574
557
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
558
|
+
try:
|
|
559
|
+
line_str = line.decode("utf-8")
|
|
560
|
+
except Exception as error:
|
|
561
|
+
logger.error("Unable to decode utf-8 from agent: %s", error)
|
|
578
562
|
continue
|
|
579
563
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
564
|
+
logger.debug("[agent] %s", line_str.rstrip())
|
|
565
|
+
try:
|
|
566
|
+
agent_data: jsonrpc.JSONType = json.loads(line_str)
|
|
567
|
+
except Exception as error:
|
|
568
|
+
logger.error("Failed to decode JSON from agent: %s", error)
|
|
569
|
+
continue
|
|
583
570
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
571
|
+
if isinstance(agent_data, dict):
|
|
572
|
+
if "result" in agent_data or "error" in agent_data:
|
|
573
|
+
# Wait for pending notification dispatch tasks so all ACP
|
|
574
|
+
# messages are queued before the response future resolves.
|
|
575
|
+
if tasks:
|
|
576
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
577
|
+
tasks.clear()
|
|
578
|
+
API.process_response(agent_data)
|
|
579
|
+
continue
|
|
580
|
+
|
|
581
|
+
elif isinstance(agent_data, list):
|
|
582
|
+
if not all(isinstance(datum, dict) for datum in agent_data):
|
|
583
|
+
logger.error("Agent sent invalid data: %r", agent_data)
|
|
584
|
+
continue
|
|
585
|
+
|
|
586
|
+
if not isinstance(agent_data, dict):
|
|
587
|
+
logger.error("Invalid JSON from agent: %r", agent_data)
|
|
588
|
+
continue
|
|
587
589
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
await asyncio.sleep(0)
|
|
590
|
+
if not isinstance(agent_data, dict):
|
|
591
|
+
logger.error("Invalid JSON from agent: %r", agent_data)
|
|
592
|
+
continue
|
|
592
593
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
594
|
+
# By this point we know it is a JSON RPC call
|
|
595
|
+
assert isinstance(agent_data, dict)
|
|
596
|
+
tasks.add(asyncio.create_task(call_jsonrpc(agent_data)))
|
|
597
|
+
await asyncio.sleep(0)
|
|
598
|
+
except Exception as e:
|
|
599
|
+
logger.exception("Agent read loop failed: %s", e)
|
|
600
|
+
finally:
|
|
601
|
+
# Cancel all remaining tasks and wait for them to finish
|
|
602
|
+
for task in tasks:
|
|
603
|
+
task.cancel()
|
|
596
604
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
605
|
+
# Wait for all tasks to complete cancellation
|
|
606
|
+
if tasks:
|
|
607
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
600
608
|
|
|
601
609
|
if process.returncode:
|
|
602
610
|
assert process.stderr is not None
|
|
@@ -691,6 +699,7 @@ class Agent(AgentBase):
|
|
|
691
699
|
protocol=data["protocol"],
|
|
692
700
|
meta=data["meta"],
|
|
693
701
|
)
|
|
702
|
+
self.post_message(tui_messages.SessionUpdate(session_pk=self.session_pk))
|
|
694
703
|
self._pending_session_data = None
|
|
695
704
|
await self._save_last_session_to_cdh()
|
|
696
705
|
|
|
@@ -816,8 +825,19 @@ class Agent(AgentBase):
|
|
|
816
825
|
self.post_message(messages.SessionReplay(active=True))
|
|
817
826
|
try:
|
|
818
827
|
response = await session_load_response.wait()
|
|
828
|
+
self.session_load_info = {
|
|
829
|
+
"total_messages": response.get("_total_messages", 0),
|
|
830
|
+
"visible_start": response.get("_visible_start", 0),
|
|
831
|
+
}
|
|
819
832
|
finally:
|
|
820
|
-
self.post_message(messages.SessionReplay(
|
|
833
|
+
self.post_message(messages.SessionReplay(
|
|
834
|
+
active=False,
|
|
835
|
+
total_messages=self.session_load_info.get("total_messages", 0),
|
|
836
|
+
visible_count=self.session_load_info.get("total_messages", 0) - self.session_load_info.get("visible_start", 0),
|
|
837
|
+
))
|
|
838
|
+
|
|
839
|
+
if error := response.get("error"):
|
|
840
|
+
logger.warning("Session load error: %s", error)
|
|
821
841
|
|
|
822
842
|
if (modes := response.get("modes", None)) is not None:
|
|
823
843
|
current_mode = modes["currentModeId"]
|
|
@@ -845,10 +865,20 @@ class Agent(AgentBase):
|
|
|
845
865
|
await self._ensure_db_session()
|
|
846
866
|
|
|
847
867
|
if session_title:
|
|
848
|
-
self.post_message(tui_messages.SessionUpdate(name=session_title))
|
|
868
|
+
self.post_message(tui_messages.SessionUpdate(name=session_title, session_pk=self.session_pk))
|
|
849
869
|
|
|
850
870
|
await self._save_last_session_to_cdh()
|
|
851
871
|
|
|
872
|
+
async def acp_load_earlier_messages(self, offset: int, limit: int) -> None:
|
|
873
|
+
"""Load a range of earlier messages from the current session."""
|
|
874
|
+
assert self.session_id is not None
|
|
875
|
+
with self.request():
|
|
876
|
+
response = api.session_load_earlier(self.session_id, offset, limit)
|
|
877
|
+
try:
|
|
878
|
+
await response.wait()
|
|
879
|
+
except jsonrpc.JSONRPCError:
|
|
880
|
+
pass
|
|
881
|
+
|
|
852
882
|
async def acp_session_prompt(
|
|
853
883
|
self, prompt: list[protocol.ContentBlock]
|
|
854
884
|
) -> str | None:
|
|
@@ -858,6 +888,14 @@ class Agent(AgentBase):
|
|
|
858
888
|
The stop reason.
|
|
859
889
|
|
|
860
890
|
"""
|
|
891
|
+
if self._process is None:
|
|
892
|
+
self.post_message(
|
|
893
|
+
AgentFail(
|
|
894
|
+
"Agent process is not running",
|
|
895
|
+
"The agent subprocess has terminated. Restart the session to continue.",
|
|
896
|
+
)
|
|
897
|
+
)
|
|
898
|
+
return None
|
|
861
899
|
with self.request():
|
|
862
900
|
session_prompt = api.session_prompt(prompt, self.session_id)
|
|
863
901
|
try:
|
|
@@ -908,6 +946,15 @@ class Agent(AgentBase):
|
|
|
908
946
|
async def set_mode(self, mode_id: str) -> str | None:
|
|
909
947
|
return await self.acp_session_set_mode(mode_id)
|
|
910
948
|
|
|
949
|
+
async def acp_session_clear_todos(self) -> dict:
|
|
950
|
+
"""Clear all todos via the session/clear_todos RPC."""
|
|
951
|
+
if self.session_id is None:
|
|
952
|
+
return {"cleared": False}
|
|
953
|
+
with self.request():
|
|
954
|
+
response = api.session_clear_todos(self.session_id)
|
|
955
|
+
result = await response.wait()
|
|
956
|
+
return result or {"cleared": False}
|
|
957
|
+
|
|
911
958
|
async def set_session_name(self, name: str) -> None:
|
|
912
959
|
if self.session_pk is None:
|
|
913
960
|
return
|
|
@@ -919,16 +966,36 @@ class Agent(AgentBase):
|
|
|
919
966
|
if session.load():
|
|
920
967
|
session.name = name
|
|
921
968
|
session.save()
|
|
922
|
-
self.post_message(tui_messages.SessionUpdate(name=name))
|
|
969
|
+
self.post_message(tui_messages.SessionUpdate(name=name, session_pk=self.session_pk))
|
|
923
970
|
|
|
924
971
|
async def acp_session_cancel(self) -> bool:
|
|
925
|
-
|
|
926
|
-
|
|
972
|
+
"""Send session/cancel notification to the agent subprocess.
|
|
973
|
+
|
|
974
|
+
Writes directly to stdin with drain() to ensure the message is
|
|
975
|
+
actually flushed through the pipe, unlike the Request path which
|
|
976
|
+
is synchronous and cannot drain.
|
|
977
|
+
"""
|
|
978
|
+
if not self.session_id:
|
|
979
|
+
logger.info("[client] session/cancel: no session_id, skipping")
|
|
980
|
+
return False
|
|
981
|
+
cancel_msg = {
|
|
982
|
+
"jsonrpc": "2.0",
|
|
983
|
+
"method": "session/cancel",
|
|
984
|
+
"params": {"sessionId": self.session_id, "_meta": {}},
|
|
985
|
+
}
|
|
986
|
+
data = json.dumps(cancel_msg).encode("utf-8") + b"\n"
|
|
987
|
+
logger.info("[client] session/cancel: sending %s", cancel_msg)
|
|
988
|
+
stdin = self._process.stdin if self._process else None
|
|
989
|
+
if stdin is None:
|
|
990
|
+
logger.info("[client] session/cancel: no stdin pipe, skipping")
|
|
991
|
+
return False
|
|
992
|
+
stdin.write(data)
|
|
927
993
|
try:
|
|
928
|
-
await
|
|
929
|
-
except
|
|
930
|
-
|
|
994
|
+
await stdin.drain()
|
|
995
|
+
except OSError:
|
|
996
|
+
logger.info("[client] session/cancel: drain failed", exc_info=True)
|
|
931
997
|
return False
|
|
998
|
+
logger.info("[client] session/cancel: sent successfully")
|
|
932
999
|
return True
|
|
933
1000
|
|
|
934
1001
|
async def cancel(self) -> bool:
|
package/tui/acp/api.py
CHANGED
|
@@ -59,3 +59,15 @@ def session_set_mode(sessionId: str, modeId: str) -> protocol.SetSessionModeResp
|
|
|
59
59
|
def session_save(sessionId: str) -> dict:
|
|
60
60
|
"""Save the session state."""
|
|
61
61
|
...
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@API.method(name="session/clear_todos")
|
|
65
|
+
def session_clear_todos(sessionId: str) -> dict:
|
|
66
|
+
"""Clear all todos in the current session."""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@API.method(name="session/load_earlier")
|
|
71
|
+
def session_load_earlier(sessionId: str, offset: int, limit: int) -> dict:
|
|
72
|
+
"""Load a range of earlier messages from the current session."""
|
|
73
|
+
...
|
package/tui/acp/messages.py
CHANGED
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
|
|
5
5
|
from asyncio import Future
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Mapping, TYPE_CHECKING
|
|
7
7
|
from textual.message import Message
|
|
8
8
|
|
|
9
9
|
import rich.repr
|
|
@@ -38,6 +38,8 @@ class Thinking(AgentMessage):
|
|
|
38
38
|
class SessionReplay(AgentMessage):
|
|
39
39
|
"""Marks the start/end of a session replay (loading historical messages)."""
|
|
40
40
|
active: bool
|
|
41
|
+
total_messages: int = 0
|
|
42
|
+
visible_count: int = 0
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
@dataclass
|
package/tui/acp/prompt.py
CHANGED
|
@@ -6,54 +6,6 @@ from tui.prompt.extract import extract_paths_from_prompt
|
|
|
6
6
|
from tui.prompt.resource import load_resource, ResourceError
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
CLOUD_SPEC_SKILL_PATH = Path(__file__).resolve().parent.parent.parent / "cloud-spec-skill" / "SKILL.md"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def _get_cloud_spec_content() -> str:
|
|
13
|
-
"""Load cloud-spec-skill content."""
|
|
14
|
-
if CLOUD_SPEC_SKILL_PATH.exists():
|
|
15
|
-
return CLOUD_SPEC_SKILL_PATH.read_text(encoding="utf-8")
|
|
16
|
-
return ""
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def cloud_spec_skill_loaded() -> bool:
|
|
20
|
-
"""Check if cloud-spec-skill SKILL.md exists."""
|
|
21
|
-
return CLOUD_SPEC_SKILL_PATH.exists()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def ensure_cloud_spec_skill_installed() -> str | None:
|
|
25
|
-
"""Ensure cloud-spec-skill is accessible to agents.
|
|
26
|
-
|
|
27
|
-
Checks if SKILL.md exists in repo and copies it to ~/.cdh/skills/ if needed,
|
|
28
|
-
or updates if the repo version is newer.
|
|
29
|
-
Returns error message if installation fails, None on success.
|
|
30
|
-
"""
|
|
31
|
-
from onecode.skills.loader import USER_SKILLS_DIR
|
|
32
|
-
|
|
33
|
-
if not CLOUD_SPEC_SKILL_PATH.exists():
|
|
34
|
-
return None
|
|
35
|
-
|
|
36
|
-
skill_dest = USER_SKILLS_DIR / "cloud-spec-skill"
|
|
37
|
-
dest_skills_md = skill_dest / "SKILL.md"
|
|
38
|
-
|
|
39
|
-
if skill_dest.exists() and dest_skills_md.exists():
|
|
40
|
-
repo_mtime = CLOUD_SPEC_SKILL_PATH.stat().st_mtime
|
|
41
|
-
dest_mtime = dest_skills_md.stat().st_mtime
|
|
42
|
-
if dest_mtime >= repo_mtime:
|
|
43
|
-
return None
|
|
44
|
-
|
|
45
|
-
try:
|
|
46
|
-
import shutil
|
|
47
|
-
|
|
48
|
-
if skill_dest.exists():
|
|
49
|
-
shutil.rmtree(skill_dest)
|
|
50
|
-
skill_dest.parent.mkdir(parents=True, exist_ok=True)
|
|
51
|
-
shutil.copytree(CLOUD_SPEC_SKILL_PATH.parent, skill_dest)
|
|
52
|
-
return None
|
|
53
|
-
except Exception as e:
|
|
54
|
-
return str(e)
|
|
55
|
-
|
|
56
|
-
|
|
57
9
|
def build(project_path: Path, prompt: str) -> list[protocol.ContentBlock]:
|
|
58
10
|
"""Build the prompt structure and extract paths with the @ syntax.
|
|
59
11
|
|
|
@@ -66,14 +18,6 @@ def build(project_path: Path, prompt: str) -> list[protocol.ContentBlock]:
|
|
|
66
18
|
"""
|
|
67
19
|
prompt_content: list[protocol.ContentBlock] = []
|
|
68
20
|
|
|
69
|
-
# Prepend cloud-spec-skill as system guidance
|
|
70
|
-
cloud_spec_content = _get_cloud_spec_content()
|
|
71
|
-
if cloud_spec_content:
|
|
72
|
-
prompt_content.append({
|
|
73
|
-
"type": "text",
|
|
74
|
-
"text": f"[System Guidance - Always follow these development standards]\n\n{cloud_spec_content}\n\n---\n\n"
|
|
75
|
-
})
|
|
76
|
-
|
|
77
21
|
prompt_content.append({"type": "text", "text": prompt})
|
|
78
22
|
for path, _, _ in extract_paths_from_prompt(prompt):
|
|
79
23
|
if path.endswith("/"):
|
|
@@ -81,7 +25,6 @@ def build(project_path: Path, prompt: str) -> list[protocol.ContentBlock]:
|
|
|
81
25
|
try:
|
|
82
26
|
resource = load_resource(project_path, Path(path))
|
|
83
27
|
except ResourceError:
|
|
84
|
-
# TODO: How should this be handled?
|
|
85
28
|
continue
|
|
86
29
|
uri = f"file://{resource.path.absolute().resolve()}"
|
|
87
30
|
if resource.text is not None:
|
package/tui/acp/protocol.py
CHANGED
|
@@ -217,6 +217,11 @@ class ToolCall(SchemaDict, total=False, extra_items=Any):
|
|
|
217
217
|
status: ToolCallStatus
|
|
218
218
|
title: Required[str]
|
|
219
219
|
toolCallId: Required[ToolCallId]
|
|
220
|
+
# Custom (non-ACP) field: when set, this tool call was invoked *inside* a
|
|
221
|
+
# subagent and the TUI should mount/update the ToolCall card inside the
|
|
222
|
+
# owning SubAgent widget (subagentId = the parent Spawn toolCallId) rather
|
|
223
|
+
# than in the main conversation.
|
|
224
|
+
subagentId: str
|
|
220
225
|
|
|
221
226
|
|
|
222
227
|
# https://agentclientprotocol.com/protocol/schema#toolcallupdate
|
|
@@ -231,6 +236,7 @@ class ToolCallUpdate(SchemaDict, total=False, extra_items=Any):
|
|
|
231
236
|
status: ToolCallStatus | None
|
|
232
237
|
title: str | None
|
|
233
238
|
toolCallId: Required[ToolCallId]
|
|
239
|
+
subagentId: str
|
|
234
240
|
|
|
235
241
|
|
|
236
242
|
# https://agentclientprotocol.com/protocol/schema#param-tool-call
|