mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-09-20 12:13:38 +08:00
fix: build task dependencies in two phases
This commit is contained in:
@@ -26,7 +26,7 @@ TodoWrite は、こうした依存関係や担当を記録しない。「API を
|
||||
|
||||

|
||||
|
||||
コードは S04 の 5 つの基本ツール、Permission、Hooks、共通の `execute_tool` を保ち、そこへ 5 つのタスクツール、`.tasks/` ディレクトリへの永続化、`blockedBy` の依存チェックを追加する。
|
||||
コードは S04 の 5 つの基本ツール、Permission、Hooks、共通の `execute_tool` を保ち、そこへ 6 つのタスクツール、`.tasks/` ディレクトリへの永続化、`blockedBy` の依存チェックを追加する。
|
||||
|
||||
TodoWrite vs Task System:
|
||||
|
||||
@@ -69,12 +69,22 @@ ID は `task_` と 8 桁のランダムな 16 進文字で生成する。ファ
|
||||
### create_task: タスク作成
|
||||
|
||||
```python
|
||||
def create_task(subject: str, description: str = "",
|
||||
blockedBy: list[str] | None = None) -> Task:
|
||||
return TASKS.create(subject, description, blockedBy)
|
||||
def create_task(subject: str, description: str = "") -> Task:
|
||||
return TASKS.create(subject, description)
|
||||
```
|
||||
|
||||
`TaskStore.create` は subject と依存 ID を確認し、`.tasks/{id}.json` に書き込む。`blockedBy` で依存を宣言し、例えば「API を書く」タスクはデータベースタスクの ID を参照できる。
|
||||
`TaskStore.create` は subject を確認し、ランダム ID を割り当てて `.tasks/{id}.json` に書き込む。新しいタスクの `blockedBy` は常に空で、ツール結果が実行時に生成された ID をモデルへ返す。
|
||||
|
||||
### update_task: 返された ID で依存を追加
|
||||
|
||||
```python
|
||||
def update_task(task_id: str, addBlockedBy: list[str]) -> Task:
|
||||
return TASKS.update_dependencies(task_id, addBlockedBy)
|
||||
```
|
||||
|
||||
タスクグラフは 2 段階で構築する。まず全ノードを作成し、その後 `create_task` が返した ID を使って `update_task` で辺を追加する。モデルが 1 回の応答で複数のツール呼び出しを出す場合、同じ階層の呼び出しはツール結果が返る前にすべて確定するため、ある `create_task` は別の呼び出しで生成されたばかりの ID を利用できない。
|
||||
|
||||
`update_task` は変更全体を検証してから保存する。対象と依存タスクは存在し、対象は pending かつ未所有でなければならず、自己依存や循環も禁止する。既存の辺を再度追加しても重複しない。
|
||||
|
||||
### can_start: 依存チェック
|
||||
|
||||
@@ -159,11 +169,16 @@ pending ──claim──→ in_progress ──complete──→ completed
|
||||
### 組み合わせて実行
|
||||
|
||||
```python
|
||||
# 依存関係のあるタスクを作成
|
||||
# 第 1 段階:全ノードを作成して実行時 ID を受け取る
|
||||
schema = create_task("setup database schema")
|
||||
endpoints = create_task("create API endpoints", blockedBy=[schema.id])
|
||||
tests = create_task("write tests", blockedBy=[endpoints.id])
|
||||
docs = create_task("write docs", blockedBy=[schema.id])
|
||||
endpoints = create_task("create API endpoints")
|
||||
tests = create_task("write tests")
|
||||
docs = create_task("write docs")
|
||||
|
||||
# 第 2 段階:返された ID で依存の辺を追加する
|
||||
update_task(endpoints.id, addBlockedBy=[schema.id])
|
||||
update_task(tests.id, addBlockedBy=[endpoints.id])
|
||||
update_task(docs.id, addBlockedBy=[schema.id])
|
||||
|
||||
# Agent が最初に実行可能なタスクを引き受ける
|
||||
claim_task(schema.id) # ✓ Claimed(依存なし)
|
||||
@@ -179,7 +194,7 @@ claim_task(tests.id) # ✓ Claimed(endpoints 完了済み)
|
||||
complete_task(tests.id) # ✓ Completed
|
||||
```
|
||||
|
||||
各 `create_task` が JSON ファイルを書き込み、各 `claim_task` / `complete_task` がファイルを更新。セッションをまたいでも `.tasks/` ディレクトリが残り、Agent はファイルを読んで進捗を復旧。
|
||||
各 `create_task` が JSON ファイルを書き込み、`update_task`、`claim_task`、`complete_task` がファイルを更新する。セッションをまたいでも `.tasks/` ディレクトリが残り、Agent はファイルを読んで進捗を復旧できる。
|
||||
|
||||
---
|
||||
|
||||
@@ -208,4 +223,4 @@ python s10_task_system/code.py
|
||||
s11 Background Tasks → 遅い操作をバックグラウンドで実行する。Agent は他のタスクの処理を続け、バックグラウンド処理の完了後に通知を受け取る。
|
||||
|
||||
|
||||
<!-- translation-sync: zh@v4, en@v4, ja@v4 -->
|
||||
<!-- translation-sync: zh@v5, en@v5, ja@v5 -->
|
||||
|
||||
@@ -26,7 +26,7 @@ This chapter adds a Task System. Each task has its own ID and status; `blockedBy
|
||||
|
||||

|
||||
|
||||
The code keeps S04's five base tools, Permission, Hooks, and shared `execute_tool`, then adds 5 task tools, persistence in the `.tasks/` directory, and `blockedBy` dependency checks.
|
||||
The code keeps S04's five base tools, Permission, Hooks, and shared `execute_tool`, then adds 6 task tools, persistence in the `.tasks/` directory, and `blockedBy` dependency checks.
|
||||
|
||||
TodoWrite vs Task System:
|
||||
|
||||
@@ -69,12 +69,22 @@ IDs use the `task_` prefix followed by 8 random hexadecimal characters. Files ar
|
||||
### create_task: Create Tasks
|
||||
|
||||
```python
|
||||
def create_task(subject: str, description: str = "",
|
||||
blockedBy: list[str] | None = None) -> Task:
|
||||
return TASKS.create(subject, description, blockedBy)
|
||||
def create_task(subject: str, description: str = "") -> Task:
|
||||
return TASKS.create(subject, description)
|
||||
```
|
||||
|
||||
`TaskStore.create` checks the subject and dependency IDs, then writes `.tasks/{id}.json`. `blockedBy` declares dependencies; for example, "write API" can reference the database task's ID.
|
||||
`TaskStore.create` checks the subject, allocates a random ID, and writes `.tasks/{id}.json`. A new task always starts with an empty `blockedBy` list. The tool result returns the runtime-generated ID to the model.
|
||||
|
||||
### update_task: Add Dependencies with Returned IDs
|
||||
|
||||
```python
|
||||
def update_task(task_id: str, addBlockedBy: list[str]) -> Task:
|
||||
return TASKS.update_dependencies(task_id, addBlockedBy)
|
||||
```
|
||||
|
||||
Task graph construction uses two phases: create every node first, then call `update_task` with the IDs returned by `create_task` to add edges. This matters when the model emits several tool calls in one response: sibling calls are formed before any tool result exists, so one `create_task` call cannot consume another call's newly generated ID.
|
||||
|
||||
`update_task` validates the entire change before saving it. The target and dependencies must exist, the target must still be pending and unowned, and the new edges must not introduce self-dependencies or cycles. Repeating an existing edge is safe and does not duplicate it.
|
||||
|
||||
### can_start: Dependency Check
|
||||
|
||||
@@ -159,11 +169,16 @@ Here `claim` / `complete` are actions, while `pending` / `in_progress` / `comple
|
||||
### Putting It Together
|
||||
|
||||
```python
|
||||
# Create tasks with dependencies
|
||||
# Phase 1: create every node and receive its runtime ID
|
||||
schema = create_task("setup database schema")
|
||||
endpoints = create_task("create API endpoints", blockedBy=[schema.id])
|
||||
tests = create_task("write tests", blockedBy=[endpoints.id])
|
||||
docs = create_task("write docs", blockedBy=[schema.id])
|
||||
endpoints = create_task("create API endpoints")
|
||||
tests = create_task("write tests")
|
||||
docs = create_task("write docs")
|
||||
|
||||
# Phase 2: add edges using those returned IDs
|
||||
update_task(endpoints.id, addBlockedBy=[schema.id])
|
||||
update_task(tests.id, addBlockedBy=[endpoints.id])
|
||||
update_task(docs.id, addBlockedBy=[schema.id])
|
||||
|
||||
# Agent claims the first available task
|
||||
claim_task(schema.id) # ✓ Claimed (no dependencies)
|
||||
@@ -179,7 +194,7 @@ claim_task(tests.id) # ✓ Claimed (endpoints completed)
|
||||
complete_task(tests.id) # ✓ Completed
|
||||
```
|
||||
|
||||
Each `create_task` writes a JSON file, each `claim_task` / `complete_task` updates the file. Across sessions, the `.tasks/` directory persists — the agent reads the files to recover progress.
|
||||
Each `create_task` writes a JSON file; `update_task`, `claim_task`, and `complete_task` update it. Across sessions, the `.tasks/` directory persists — the agent reads the files to recover progress.
|
||||
|
||||
---
|
||||
|
||||
@@ -208,4 +223,4 @@ The task graph is in place, but full test suites, dependency installation, and d
|
||||
s11 Background Tasks → Slow operations run in the background. The Agent Loop can continue processing other tasks and receives a notification when the background work finishes.
|
||||
|
||||
|
||||
<!-- translation-sync: zh@v4, en@v4, ja@v4 -->
|
||||
<!-- translation-sync: zh@v5, en@v5, ja@v5 -->
|
||||
|
||||
@@ -26,7 +26,7 @@ TodoWrite 没有记录这些依赖和分工。它可以显示“编写 API”仍
|
||||
|
||||

|
||||
|
||||
代码保留 S04 的五个基础工具、Permission、Hooks 和统一 `execute_tool`,再加入 5 个任务工具、`.tasks/` 目录持久化和 `blockedBy` 依赖检查。
|
||||
代码保留 S04 的五个基础工具、Permission、Hooks 和统一 `execute_tool`,再加入 6 个任务工具、`.tasks/` 目录持久化和 `blockedBy` 依赖检查。
|
||||
|
||||
TodoWrite vs Task System:
|
||||
|
||||
@@ -69,12 +69,22 @@ ID 使用 `task_` 加 8 位随机十六进制字符生成。创建文件时使
|
||||
### create_task: 创建任务
|
||||
|
||||
```python
|
||||
def create_task(subject: str, description: str = "",
|
||||
blockedBy: list[str] | None = None) -> Task:
|
||||
return TASKS.create(subject, description, blockedBy)
|
||||
def create_task(subject: str, description: str = "") -> Task:
|
||||
return TASKS.create(subject, description)
|
||||
```
|
||||
|
||||
`TaskStore.create` 检查 subject 和依赖 ID,再把任务写入 `.tasks/{id}.json`。`blockedBy` 声明依赖,比如“写 API”的 `blockedBy` 可以指向数据库任务的 ID。
|
||||
`TaskStore.create` 检查 subject,分配随机 ID,再把任务写入 `.tasks/{id}.json`。新任务的 `blockedBy` 固定为空,工具结果会把运行时生成的 ID 返回给模型。
|
||||
|
||||
### update_task: 使用返回的 ID 添加依赖
|
||||
|
||||
```python
|
||||
def update_task(task_id: str, addBlockedBy: list[str]) -> Task:
|
||||
return TASKS.update_dependencies(task_id, addBlockedBy)
|
||||
```
|
||||
|
||||
任务图采用两阶段构建:先创建所有节点,再使用 `create_task` 返回的 ID 调用 `update_task` 添加边。模型可能在一条回复里同时发出多个工具调用,而这些同级调用在任何工具结果产生前就已经确定,因此某个 `create_task` 无法直接使用另一个调用刚生成的 ID。
|
||||
|
||||
`update_task` 会先校验整次修改,再统一保存。目标任务和依赖必须存在,目标必须仍为 pending 且无人认领,并且不能形成自依赖或环。重复添加已有依赖是安全的,不会产生重复边。
|
||||
|
||||
### can_start: 依赖检查
|
||||
|
||||
@@ -159,11 +169,16 @@ pending ──claim──→ in_progress ──complete──→ completed
|
||||
### 合起来跑
|
||||
|
||||
```python
|
||||
# 创建有依赖的任务
|
||||
# 第一阶段:创建所有节点并取得运行时 ID
|
||||
schema = create_task("setup database schema")
|
||||
endpoints = create_task("create API endpoints", blockedBy=[schema.id])
|
||||
tests = create_task("write tests", blockedBy=[endpoints.id])
|
||||
docs = create_task("write docs", blockedBy=[schema.id])
|
||||
endpoints = create_task("create API endpoints")
|
||||
tests = create_task("write tests")
|
||||
docs = create_task("write docs")
|
||||
|
||||
# 第二阶段:使用返回的 ID 建立依赖边
|
||||
update_task(endpoints.id, addBlockedBy=[schema.id])
|
||||
update_task(tests.id, addBlockedBy=[endpoints.id])
|
||||
update_task(docs.id, addBlockedBy=[schema.id])
|
||||
|
||||
# Agent 认领第一个可做的任务
|
||||
claim_task(schema.id) # ✓ Claimed (无依赖)
|
||||
@@ -179,7 +194,7 @@ claim_task(tests.id) # ✓ Claimed (endpoints 已完成)
|
||||
complete_task(tests.id) # ✓ Completed
|
||||
```
|
||||
|
||||
每个 `create_task` 写一个 JSON 文件,每个 `claim_task` / `complete_task` 更新文件。跨会话时,`.tasks/` 目录还在,Agent 读文件就能恢复进度。
|
||||
每个 `create_task` 写一个 JSON 文件,`update_task`、`claim_task` 和 `complete_task` 更新文件。跨会话时,`.tasks/` 目录还在,Agent 读文件就能恢复进度。
|
||||
|
||||
---
|
||||
|
||||
@@ -208,4 +223,4 @@ python s10_task_system/code.py
|
||||
s11 Background Tasks → 把慢操作放到后台。Agent 可以继续处理其他任务,后台执行完成后再接收通知。
|
||||
|
||||
|
||||
<!-- translation-sync: zh@v4, en@v4, ja@v4 -->
|
||||
<!-- translation-sync: zh@v5, en@v5, ja@v5 -->
|
||||
|
||||
@@ -53,7 +53,9 @@ MODEL = os.environ["MODEL_ID"]
|
||||
|
||||
SYSTEM = (
|
||||
f"You are a coding agent at {WORKDIR}. "
|
||||
"Use task tools to track dependencies and progress."
|
||||
"Use task tools to track dependencies and progress. Create all task nodes "
|
||||
"first. After create_task returns runtime-generated IDs, use update_task "
|
||||
"with those exact IDs to add dependencies."
|
||||
)
|
||||
|
||||
|
||||
@@ -97,17 +99,11 @@ class TaskStore:
|
||||
def exists(self, task_id: str) -> bool:
|
||||
return self._path(task_id).is_file()
|
||||
|
||||
def create(self, subject: str, description: str = "",
|
||||
blocked_by: list[str] | None = None) -> Task:
|
||||
def create(self, subject: str, description: str = "") -> Task:
|
||||
subject = subject.strip()
|
||||
if not subject:
|
||||
raise ValueError("Task subject cannot be empty")
|
||||
|
||||
dependencies = list(dict.fromkeys(blocked_by or []))
|
||||
for dependency in dependencies:
|
||||
if not self.exists(dependency):
|
||||
raise ValueError(f"Dependency not found: {dependency}")
|
||||
|
||||
self._root(create=True)
|
||||
for _ in range(100):
|
||||
task = Task(
|
||||
@@ -116,7 +112,7 @@ class TaskStore:
|
||||
description=description,
|
||||
status="pending",
|
||||
owner=None,
|
||||
blockedBy=dependencies,
|
||||
blockedBy=[],
|
||||
)
|
||||
try:
|
||||
with self._path(task.id, create_root=True).open(
|
||||
@@ -128,6 +124,52 @@ class TaskStore:
|
||||
continue
|
||||
raise RuntimeError("Could not allocate a unique task ID")
|
||||
|
||||
def _depends_on(self, task_id: str, target_id: str) -> bool:
|
||||
"""Return whether task_id transitively depends on target_id."""
|
||||
pending = [task_id]
|
||||
visited = set()
|
||||
while pending:
|
||||
current = pending.pop()
|
||||
if current == target_id:
|
||||
return True
|
||||
if current in visited:
|
||||
continue
|
||||
visited.add(current)
|
||||
pending.extend(self.load(current).blockedBy)
|
||||
return False
|
||||
|
||||
def update_dependencies(self, task_id: str,
|
||||
add_blocked_by: list[str]) -> Task:
|
||||
if not isinstance(add_blocked_by, list):
|
||||
raise ValueError("addBlockedBy must be a list of task IDs")
|
||||
|
||||
task = self.load(task_id)
|
||||
if task.status != "pending" or task.owner is not None:
|
||||
raise ValueError(
|
||||
f"Task {task_id} dependencies can only be updated while "
|
||||
"pending and unowned"
|
||||
)
|
||||
|
||||
dependencies = list(dict.fromkeys(add_blocked_by))
|
||||
for dependency in dependencies:
|
||||
if dependency == task_id:
|
||||
raise ValueError("Task cannot depend on itself")
|
||||
if not self.exists(dependency):
|
||||
raise ValueError(f"Dependency not found: {dependency}")
|
||||
if dependency not in task.blockedBy and self._depends_on(
|
||||
dependency, task_id
|
||||
):
|
||||
raise ValueError(
|
||||
f"Dependency cycle detected: {task_id} -> {dependency}"
|
||||
)
|
||||
|
||||
task.blockedBy.extend(
|
||||
dependency for dependency in dependencies
|
||||
if dependency not in task.blockedBy
|
||||
)
|
||||
self.save(task)
|
||||
return task
|
||||
|
||||
def save(self, task: Task) -> None:
|
||||
self._path(task.id, create_root=True).write_text(
|
||||
json.dumps(asdict(task), indent=2),
|
||||
@@ -154,9 +196,12 @@ class TaskStore:
|
||||
TASKS = TaskStore(TASKS_DIR)
|
||||
|
||||
|
||||
def create_task(subject: str, description: str = "",
|
||||
blockedBy: list[str] | None = None) -> Task:
|
||||
return TASKS.create(subject, description, blockedBy)
|
||||
def create_task(subject: str, description: str = "") -> Task:
|
||||
return TASKS.create(subject, description)
|
||||
|
||||
|
||||
def update_task(task_id: str, addBlockedBy: list[str]) -> Task:
|
||||
return TASKS.update_dependencies(task_id, addBlockedBy)
|
||||
|
||||
|
||||
def load_task(task_id: str) -> Task:
|
||||
@@ -290,15 +335,17 @@ def run_glob(pattern: str) -> str:
|
||||
return f"Error: {error}"
|
||||
|
||||
|
||||
def run_create_task(subject: str, description: str = "",
|
||||
blockedBy: list[str] | None = None) -> str:
|
||||
task = create_task(subject, description, blockedBy)
|
||||
dependencies = (
|
||||
f" (blockedBy: {', '.join(task.blockedBy)})"
|
||||
if task.blockedBy else ""
|
||||
)
|
||||
print(f" [create] {task.subject}{dependencies}")
|
||||
return f"Created {task.id}: {task.subject}{dependencies}"
|
||||
def run_create_task(subject: str, description: str = "") -> str:
|
||||
task = create_task(subject, description)
|
||||
print(f" [create] {task.subject}")
|
||||
return f"Created {task.id}: {task.subject}"
|
||||
|
||||
|
||||
def run_update_task(task_id: str, addBlockedBy: list[str]) -> str:
|
||||
task = update_task(task_id, addBlockedBy)
|
||||
dependencies = ", ".join(task.blockedBy) or "(none)"
|
||||
print(f" [update] {task.subject} blockedBy: {dependencies}")
|
||||
return f"Updated {task.id} blockedBy: {dependencies}"
|
||||
|
||||
|
||||
def run_list_tasks() -> str:
|
||||
@@ -347,8 +394,10 @@ TOOLS = [
|
||||
"input_schema": {"type": "object", "properties": {"path": {"type": "string"}, "old_text": {"type": "string"}, "new_text": {"type": "string"}}, "required": ["path", "old_text", "new_text"]}},
|
||||
{"name": "glob", "description": "Find files matching a glob pattern.",
|
||||
"input_schema": {"type": "object", "properties": {"pattern": {"type": "string"}}, "required": ["pattern"]}},
|
||||
{"name": "create_task", "description": "Create a task with optional dependencies.",
|
||||
"input_schema": {"type": "object", "properties": {"subject": {"type": "string"}, "description": {"type": "string"}, "blockedBy": {"type": "array", "items": {"type": "string"}}}, "required": ["subject"]}},
|
||||
{"name": "create_task", "description": "Create a task and return its runtime-generated ID.",
|
||||
"input_schema": {"type": "object", "properties": {"subject": {"type": "string"}, "description": {"type": "string"}}, "required": ["subject"], "additionalProperties": False}},
|
||||
{"name": "update_task", "description": "Add dependencies using IDs returned by create_task.",
|
||||
"input_schema": {"type": "object", "properties": {"task_id": {"type": "string", "pattern": "^task_[0-9a-f]{8}$"}, "addBlockedBy": {"type": "array", "items": {"type": "string", "pattern": "^task_[0-9a-f]{8}$"}, "minItems": 1}}, "required": ["task_id", "addBlockedBy"], "additionalProperties": False}},
|
||||
{"name": "list_tasks", "description": "List tasks with status, owner, and dependencies.",
|
||||
"input_schema": {"type": "object", "properties": {}}},
|
||||
{"name": "get_task", "description": "Get a task by ID.",
|
||||
@@ -366,6 +415,7 @@ TOOL_HANDLERS = {
|
||||
"edit_file": run_edit,
|
||||
"glob": run_glob,
|
||||
"create_task": run_create_task,
|
||||
"update_task": run_update_task,
|
||||
"list_tasks": run_list_tasks,
|
||||
"get_task": run_get_task,
|
||||
"claim_task": run_claim_task,
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<!-- Title -->
|
||||
<rect x="0" y="0" width="760" height="44" fill="url(#header)" rx="8"/>
|
||||
<rect x="0" y="36" width="760" height="8" fill="url(#header)"/>
|
||||
<text x="380" y="28" fill="#fff" font-size="15" font-weight="700" text-anchor="middle">Task System — 5 Task Tools + .tasks/ Persistence + blockedBy Dependencies</text>
|
||||
<text x="380" y="28" fill="#fff" font-size="15" font-weight="700" text-anchor="middle">Task System — 6 Task Tools + .tasks/ Persistence + blockedBy Dependencies</text>
|
||||
|
||||
<!-- Legend -->
|
||||
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
|
||||
@@ -46,7 +46,7 @@
|
||||
<rect x="393" y="80" width="210" height="64" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
|
||||
<text x="498" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">Hooks + TOOL_HANDLERS</text>
|
||||
<text x="408" y="114" fill="#2563eb" font-size="9">bash · read · write · edit · glob</text>
|
||||
<text x="408" y="128" fill="#0d9488" font-size="9" font-weight="600">create_task · list_tasks</text>
|
||||
<text x="408" y="128" fill="#0d9488" font-size="9" font-weight="600">create_task · update_task · list_tasks</text>
|
||||
<text x="408" y="140" fill="#0d9488" font-size="9" font-weight="600">get_task · claim_task · complete_task</text>
|
||||
|
||||
<!-- Loop back -->
|
||||
@@ -61,13 +61,13 @@
|
||||
|
||||
<!-- Arrow: tools → .tasks/ -->
|
||||
<path d="M 440 144 L 440 165 L 250 165 L 250 185" fill="none" stroke="#0d9488" stroke-width="1.5" marker-end="url(#arrow-teal)"/>
|
||||
<text x="320" y="178" fill="#0d9488" font-size="9">create / save / read</text>
|
||||
<text x="300" y="178" fill="#0d9488" font-size="9">create → ID / update edges / read</text>
|
||||
|
||||
<!-- ===== Lifecycle (teal) ===== -->
|
||||
<rect x="390" y="185" width="330" height="76" rx="8" fill="#f0fdfa" stroke="#0d9488" stroke-width="2"/>
|
||||
<text x="555" y="205" fill="#134e4a" font-size="11" font-weight="700" text-anchor="middle">Dependency Check + Lifecycle</text>
|
||||
<text x="408" y="222" fill="#0d9488" font-size="9">can_start: all blockedBy completed?</text>
|
||||
<text x="408" y="238" fill="#0d9488" font-size="9">claim_task → owner = agent, pending → in_progress</text>
|
||||
<text x="408" y="222" fill="#0d9488" font-size="9">create_task → runtime ID; update_task → blockedBy</text>
|
||||
<text x="408" y="238" fill="#0d9488" font-size="9">can_start + claim: all dependencies completed?</text>
|
||||
<text x="408" y="252" fill="#0d9488" font-size="9">complete_task → completed + unblock downstream</text>
|
||||
|
||||
<!-- ===== State machine ===== -->
|
||||
@@ -90,5 +90,5 @@
|
||||
<rect x="60" y="366" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
|
||||
<text x="80" y="376" fill="#475569" font-size="10">Base loop: model call + Permission/Hooks + tool dispatch + tool_result</text>
|
||||
<rect x="60" y="384" width="12" height="10" rx="2" fill="#f0fdfa" stroke="#0d9488" stroke-width="1"/>
|
||||
<text x="80" y="394" fill="#475569" font-size="10">s10 New: Task dataclass + 5 tools + .tasks/ persistence + blockedBy dependency graph</text>
|
||||
<text x="80" y="394" fill="#475569" font-size="10">s10 New: Task dataclass + 6 tools + .tasks/ persistence + blockedBy dependency graph</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.8 KiB |
@@ -16,7 +16,7 @@
|
||||
<!-- タイトル -->
|
||||
<rect x="0" y="0" width="760" height="44" fill="url(#header)" rx="8"/>
|
||||
<rect x="0" y="36" width="760" height="8" fill="url(#header)"/>
|
||||
<text x="380" y="28" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Task System — 5 つのタスクツール + .tasks/ 永続化 + blockedBy 依存</text>
|
||||
<text x="380" y="28" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Task System — 6 つのタスクツール + .tasks/ 永続化 + blockedBy 依存</text>
|
||||
|
||||
<!-- 凡例 -->
|
||||
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
|
||||
@@ -46,7 +46,7 @@
|
||||
<rect x="393" y="80" width="210" height="64" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
|
||||
<text x="498" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">Hooks + TOOL_HANDLERS</text>
|
||||
<text x="408" y="114" fill="#2563eb" font-size="9">bash · read · write · edit · glob</text>
|
||||
<text x="408" y="128" fill="#0d9488" font-size="9" font-weight="600">create_task · list_tasks</text>
|
||||
<text x="408" y="128" fill="#0d9488" font-size="9" font-weight="600">create_task · update_task · list_tasks</text>
|
||||
<text x="408" y="140" fill="#0d9488" font-size="9" font-weight="600">get_task · claim_task · complete_task</text>
|
||||
|
||||
<!-- ループバック -->
|
||||
@@ -61,13 +61,13 @@
|
||||
|
||||
<!-- 矢印: tools → .tasks/ -->
|
||||
<path d="M 440 144 L 440 165 L 250 165 L 250 185" fill="none" stroke="#0d9488" stroke-width="1.5" marker-end="url(#arrow-teal)"/>
|
||||
<text x="320" y="178" fill="#0d9488" font-size="9">create / save / read</text>
|
||||
<text x="300" y="178" fill="#0d9488" font-size="9">create → ID / update edges / read</text>
|
||||
|
||||
<!-- ===== ライフサイクル(ティール) ===== -->
|
||||
<rect x="390" y="185" width="330" height="76" rx="8" fill="#f0fdfa" stroke="#0d9488" stroke-width="2"/>
|
||||
<text x="555" y="205" fill="#134e4a" font-size="11" font-weight="700" text-anchor="middle">依存チェック + ライフサイクル</text>
|
||||
<text x="408" y="222" fill="#0d9488" font-size="9">can_start: blockedBy がすべて completed?</text>
|
||||
<text x="408" y="238" fill="#0d9488" font-size="9">claim_task → owner = agent, pending → in_progress</text>
|
||||
<text x="408" y="222" fill="#0d9488" font-size="9">create_task → 実行時 ID;update_task → blockedBy</text>
|
||||
<text x="408" y="238" fill="#0d9488" font-size="9">can_start + claim:依存がすべて completed?</text>
|
||||
<text x="408" y="252" fill="#0d9488" font-size="9">complete_task → completed + 下流をアンロック</text>
|
||||
|
||||
<!-- ===== 状態マシン ===== -->
|
||||
@@ -90,5 +90,5 @@
|
||||
<rect x="60" y="366" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
|
||||
<text x="80" y="376" fill="#475569" font-size="10">基本ループ:モデル呼び出し + Permission/Hooks + ツール分配 + tool_result</text>
|
||||
<rect x="60" y="384" width="12" height="10" rx="2" fill="#f0fdfa" stroke="#0d9488" stroke-width="1"/>
|
||||
<text x="80" y="394" fill="#475569" font-size="10">s10 新規:Task dataclass + 5 ツール + .tasks/ 永続化 + blockedBy 依存グラフ</text>
|
||||
<text x="80" y="394" fill="#475569" font-size="10">s10 新規:Task dataclass + 6 ツール + .tasks/ 永続化 + blockedBy 依存グラフ</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
@@ -16,7 +16,7 @@
|
||||
<!-- Title -->
|
||||
<rect x="0" y="0" width="760" height="44" fill="url(#header)" rx="8"/>
|
||||
<rect x="0" y="36" width="760" height="8" fill="url(#header)"/>
|
||||
<text x="380" y="28" fill="#fff" font-size="15" font-weight="700" text-anchor="middle">Task System — 5 个任务工具 + .tasks/ 持久化 + blockedBy 依赖</text>
|
||||
<text x="380" y="28" fill="#fff" font-size="15" font-weight="700" text-anchor="middle">Task System — 6 个任务工具 + .tasks/ 持久化 + blockedBy 依赖</text>
|
||||
|
||||
<!-- Legend -->
|
||||
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
|
||||
@@ -46,7 +46,7 @@
|
||||
<rect x="393" y="80" width="210" height="64" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
|
||||
<text x="498" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">Hooks + TOOL_HANDLERS</text>
|
||||
<text x="408" y="114" fill="#2563eb" font-size="9">bash · read · write · edit · glob</text>
|
||||
<text x="408" y="128" fill="#0d9488" font-size="9" font-weight="600">create_task · list_tasks</text>
|
||||
<text x="408" y="128" fill="#0d9488" font-size="9" font-weight="600">create_task · update_task · list_tasks</text>
|
||||
<text x="408" y="140" fill="#0d9488" font-size="9" font-weight="600">get_task · claim_task · complete_task</text>
|
||||
|
||||
<!-- Loop back -->
|
||||
@@ -61,13 +61,13 @@
|
||||
|
||||
<!-- Arrow: tools → .tasks/ -->
|
||||
<path d="M 440 144 L 440 165 L 250 165 L 250 185" fill="none" stroke="#0d9488" stroke-width="1.5" marker-end="url(#arrow-teal)"/>
|
||||
<text x="320" y="178" fill="#0d9488" font-size="9">create / save / read</text>
|
||||
<text x="300" y="178" fill="#0d9488" font-size="9">create → ID / update edges / read</text>
|
||||
|
||||
<!-- ===== Lifecycle (teal) ===== -->
|
||||
<rect x="390" y="185" width="330" height="76" rx="8" fill="#f0fdfa" stroke="#0d9488" stroke-width="2"/>
|
||||
<text x="555" y="205" fill="#134e4a" font-size="11" font-weight="700" text-anchor="middle">依赖检查 + 生命周期</text>
|
||||
<text x="408" y="222" fill="#0d9488" font-size="9">can_start: blockedBy 全部 completed?</text>
|
||||
<text x="408" y="238" fill="#0d9488" font-size="9">claim_task → owner = agent, pending → in_progress</text>
|
||||
<text x="408" y="222" fill="#0d9488" font-size="9">create_task → 运行时 ID;update_task → blockedBy</text>
|
||||
<text x="408" y="238" fill="#0d9488" font-size="9">can_start + claim:依赖全部 completed?</text>
|
||||
<text x="408" y="252" fill="#0d9488" font-size="9">complete_task → completed + 解锁下游</text>
|
||||
|
||||
<!-- ===== State machine ===== -->
|
||||
@@ -90,5 +90,5 @@
|
||||
<rect x="60" y="366" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
|
||||
<text x="80" y="376" fill="#475569" font-size="10">基础循环:模型调用 + Permission/Hooks + 工具分发 + tool_result</text>
|
||||
<rect x="60" y="384" width="12" height="10" rx="2" fill="#f0fdfa" stroke="#0d9488" stroke-width="1"/>
|
||||
<text x="80" y="394" fill="#475569" font-size="10">s10 新增:Task dataclass + 5 个工具 + .tasks/ 持久化 + blockedBy 依赖图</text>
|
||||
<text x="80" y="394" fill="#475569" font-size="10">s10 新增:Task dataclass + 6 个工具 + .tasks/ 持久化 + blockedBy 依赖图</text>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.8 KiB |
Reference in New Issue
Block a user