Consolidate agent harness course into 19 lessons

This commit is contained in:
Haoran
2026-08-04 02:25:40 +08:00
parent 2ad77cee19
commit b36dbcd84f
168 changed files with 6544 additions and 10400 deletions

View File

@@ -11,13 +11,13 @@
<rect width="720" height="400" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L4: autoCompact — LLM Full Summary</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 4: compact_history, Summarize History</text>
<!-- Trigger Condition -->
<rect x="20" y="54" width="680" height="44" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
<text x="35" y="70" fill="#991b1b" font-size="11" font-weight="600">Trigger Condition</text>
<text x="140" y="70" fill="#991b1b" font-size="11">All three preprocessing layers have run, estimated tokens &gt; contextWindow - maxOutputTokens - 13_000.</text>
<text x="140" y="86" fill="#991b1b" font-size="10">Tries sessionMemoryCompact first (lightweight summary from existing memory), only calls LLM if insufficient.</text>
<text x="140" y="70" fill="#991b1b" font-size="11">After Steps 13, estimate_size(messages) &gt; CONTEXT_LIMIT.</text>
<text x="140" y="86" fill="#991b1b" font-size="10">The current CONTEXT_LIMIT is 50,000 characters.</text>
<!-- Steps -->
<rect x="20" y="106" width="200" height="110" rx="8" fill="#fff" stroke="#94a3b8" stroke-width="1.5"/>
@@ -30,21 +30,21 @@
<line x1="225" y1="161" x2="265" y2="161" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="270" y="106" width="200" height="110" rx="8" fill="#fff" stroke="#94a3b8" stroke-width="1.5"/>
<text x="370" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">Step 2: LLM generates summary</text>
<text x="290" y="152" fill="#475569" font-size="10">Send conversation history to LLM</text>
<text x="290" y="166" fill="#475569" font-size="9">Summary must include 9 sections:</text>
<text x="370" y="180" fill="#94a3b8" font-size="8" text-anchor="middle">request · concepts · files · errors</text>
<text x="370" y="192" fill="#94a3b8" font-size="8" text-anchor="middle">resolutions · user messages · todos</text>
<text x="370" y="204" fill="#94a3b8" font-size="8" text-anchor="middle">current state · next steps</text>
<text x="370" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">Step 2: Factual summary</text>
<text x="370" y="152" fill="#475569" font-size="9" text-anchor="middle">Conversation is untrusted data</text>
<text x="290" y="166" fill="#475569" font-size="9">Summary preserves 5 categories:</text>
<text x="370" y="180" fill="#94a3b8" font-size="8" text-anchor="middle">goal · findings and decisions · files</text>
<text x="370" y="192" fill="#94a3b8" font-size="8" text-anchor="middle">remaining work · user constraints</text>
<text x="370" y="204" fill="#94a3b8" font-size="8" text-anchor="middle">do not propose or select an action</text>
<line x1="475" y1="161" x2="515" y2="161" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="520" y="106" width="180" height="110" rx="8" fill="#fef2f2" stroke="#dc2626" stroke-width="2"/>
<text x="610" y="130" fill="#991b1b" font-size="12" font-weight="700" text-anchor="middle">Step 3: Replace message list</text>
<text x="540" y="152" fill="#991b1b" font-size="10">All old messages → 1 summary</text>
<text x="540" y="168" fill="#991b1b" font-size="10">Model continues from summary</text>
<text x="540" y="184" fill="#991b1b" font-size="10">Includes recently_read file list</text>
<text x="540" y="200" fill="#ef4444" font-size="9">⚠ This is an irreversible operation</text>
<text x="610" y="130" fill="#991b1b" font-size="12" font-weight="700" text-anchor="middle">Step 3: Replace history</text>
<text x="610" y="152" fill="#991b1b" font-size="9" text-anchor="middle">Old history → 1 message</text>
<text x="610" y="168" fill="#991b1b" font-size="9" text-anchor="middle">Request + reference state</text>
<text x="610" y="184" fill="#991b1b" font-size="9" text-anchor="middle">System separates instructions/data</text>
<text x="610" y="200" fill="#ef4444" font-size="9" text-anchor="middle">Transcript remains on disk</text>
<!-- Before/After comparison -->
<rect x="20" y="234" width="320" height="94" rx="6" fill="#fff" stroke="#94a3b8" stroke-width="1"/>
@@ -54,19 +54,19 @@
<rect x="149" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="154" y="276" fill="#475569" font-size="8">user</text>
<rect x="206" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="211" y="276" fill="#475569" font-size="8">assistant</text>
<rect x="263" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="268" y="276" fill="#475569" font-size="8">user</text>
<text x="180" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">~180 messages, occupying 62K tokens</text>
<text x="180" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">Many messages, estimated size &gt; 50,000</text>
<line x1="345" y1="281" x2="375" y2="281" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="380" y="234" width="320" height="94" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1"/>
<text x="540" y="256" fill="#991b1b" font-size="11" font-weight="600" text-anchor="middle">After messages</text>
<rect x="395" y="264" width="290" height="32" rx="4" fill="#fee2e2" stroke="#fca5a5" stroke-width="0.5"/>
<text x="540" y="276" fill="#991b1b" font-size="9" text-anchor="middle">[Compacted] Summary: goal → create hello.py ...</text>
<text x="540" y="290" fill="#991b1b" font-size="9" text-anchor="middle">Recent files: hello.py, README.md ...</text>
<text x="540" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">~1 message, occupying 1K tokens</text>
<text x="540" y="276" fill="#991b1b" font-size="9" text-anchor="middle">Authoritative request: captured at input</text>
<text x="540" y="290" fill="#991b1b" font-size="9" text-anchor="middle">Reference state: untrusted factual summary</text>
<text x="540" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">One summary message, well below the limit</text>
<!-- Circuit breaker -->
<!-- Error recovery -->
<rect x="20" y="340" width="680" height="36" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="362" fill="#475569" font-size="11" font-weight="600">Circuit breaker:</text>
<text x="130" y="362" fill="#475569" font-size="10">3 consecutive autocompact failures → stop retrying. Prevents wasting API calls when context is unrecoverable.</text>
<text x="35" y="362" fill="#475569" font-size="11" font-weight="600">Error recovery:</text>
<text x="125" y="362" fill="#475569" font-size="10">If the API still returns prompt_too_long, run reactive_compact and retry only once.</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -11,13 +11,13 @@
<rect width="720" height="400" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L4: autoCompact — LLM 完全要約</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 4: compact_history、履歴を要約</text>
<!-- トリガー条件 -->
<rect x="20" y="54" width="680" height="44" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
<text x="35" y="70" fill="#991b1b" font-size="11" font-weight="600">トリガー条件</text>
<text x="115" y="70" fill="#991b1b" font-size="11">前 3 層の前処理を全て実行後、推定 token &gt; contextWindow - maxOutputTokens - 13_000</text>
<text x="115" y="86" fill="#991b1b" font-size="10">まず sessionMemoryCompact を試行(既存のメモリで軽量要約)、不足時のみ LLM を呼び出し</text>
<text x="115" y="70" fill="#991b1b" font-size="11">Step 13 の後、estimate_size(messages) &gt; CONTEXT_LIMIT</text>
<text x="115" y="86" fill="#991b1b" font-size="10">現在の CONTEXT_LIMIT は 50,000 文字</text>
<!-- ステップ -->
<rect x="20" y="106" width="200" height="110" rx="8" fill="#fff" stroke="#94a3b8" stroke-width="1.5"/>
@@ -30,21 +30,21 @@
<line x1="225" y1="161" x2="265" y2="161" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="270" y="106" width="200" height="110" rx="8" fill="#fff" stroke="#94a3b8" stroke-width="1.5"/>
<text x="370" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">ステップ 2LLM 要約生成</text>
<text x="290" y="152" fill="#475569" font-size="10">対話履歴を LLM に送信</text>
<text x="290" y="166" fill="#475569" font-size="9">要約は 9 つのセクションを含む</text>
<text x="290" y="180" fill="#94a3b8" font-size="8">リクエスト・概念・ファイル・エラー・解決</text>
<text x="290" y="192" fill="#94a3b8" font-size="8">ユーザーメッセージ・TODO・現在・次ステップ</text>
<text x="290" y="206" fill="#94a3b8" font-size="9">1 回のみ生成</text>
<text x="370" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">ステップ 2事実要約</text>
<text x="370" y="152" fill="#475569" font-size="9" text-anchor="middle">元の対話は信頼しないデータ</text>
<text x="290" y="166" fill="#475569" font-size="9">要約は 5 種類の情報を保持</text>
<text x="290" y="180" fill="#94a3b8" font-size="8">目標・発見と判断・関連ファイル</text>
<text x="290" y="192" fill="#94a3b8" font-size="8">残作業・ユーザー制約</text>
<text x="290" y="206" fill="#94a3b8" font-size="9">行動を提案・選択しない</text>
<line x1="475" y1="161" x2="515" y2="161" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="520" y="106" width="180" height="110" rx="8" fill="#fef2f2" stroke="#dc2626" stroke-width="2"/>
<text x="610" y="130" fill="#991b1b" font-size="12" font-weight="700" text-anchor="middle">ステップ 3要約に置換</text>
<text x="540" y="152" fill="#991b1b" font-size="10">全旧メッセージ → 1 件の要約に</text>
<text x="540" y="168" fill="#991b1b" font-size="10">モデルは要約から作業を継続</text>
<text x="540" y="184" fill="#991b1b" font-size="10">recently_read を添付</text>
<text x="540" y="200" fill="#ef4444" font-size="9">⚠ これは復元不可能な操作</text>
<text x="610" y="130" fill="#991b1b" font-size="12" font-weight="700" text-anchor="middle">ステップ 3履歴置換</text>
<text x="610" y="152" fill="#991b1b" font-size="9" text-anchor="middle">旧履歴 → 1 件の圧縮</text>
<text x="610" y="168" fill="#991b1b" font-size="9" text-anchor="middle">要求と参照状態を分離</text>
<text x="610" y="184" fill="#991b1b" font-size="8" text-anchor="middle">system が指示とデータを区別</text>
<text x="610" y="200" fill="#ef4444" font-size="9" text-anchor="middle">transcript はディスクに保持</text>
<!-- 圧縮前/後 比較 -->
<rect x="20" y="234" width="320" height="94" rx="6" fill="#fff" stroke="#94a3b8" stroke-width="1"/>
@@ -54,19 +54,19 @@
<rect x="149" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="154" y="276" fill="#475569" font-size="8">user</text>
<rect x="206" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="211" y="276" fill="#475569" font-size="8">assistant</text>
<rect x="263" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="268" y="276" fill="#475569" font-size="8">user</text>
<text x="180" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">~180 件のメッセージ、62K トークンを占有</text>
<text x="180" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">多数のメッセージ、推定 size &gt; 50,000</text>
<line x1="345" y1="281" x2="375" y2="281" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="380" y="234" width="320" height="94" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1"/>
<text x="540" y="256" fill="#991b1b" font-size="11" font-weight="600" text-anchor="middle">圧縮後 messages</text>
<rect x="395" y="264" width="290" height="32" rx="4" fill="#fee2e2" stroke="#fca5a5" stroke-width="0.5"/>
<text x="540" y="276" fill="#991b1b" font-size="9" text-anchor="middle">[Compacted] 要約:目標 → hello.py を作成 ...</text>
<text x="540" y="290" fill="#991b1b" font-size="9" text-anchor="middle">最近のファイルhello.py, README.md ...</text>
<text x="540" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">~1 件のメッセージ、1K トークンを占有</text>
<text x="540" y="276" fill="#991b1b" font-size="9" text-anchor="middle">Authoritative request入力時に取得した要求</text>
<text x="540" y="290" fill="#991b1b" font-size="9" text-anchor="middle">Reference state信頼しない事実要約</text>
<text x="540" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">1 件の要約メッセージ、上限を下回る</text>
<!-- サーキットブレーカー -->
<!-- エラー回復 -->
<rect x="20" y="340" width="680" height="36" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="362" fill="#475569" font-size="11" font-weight="600">サーキットブレーカー</text>
<text x="145" y="362" fill="#475569" font-size="10">autocompact が連続 3 回失敗 → リトライ停止。コンテキストが復元不可能な場合の API 呼び出しの無駄な反復を防止</text>
<text x="35" y="362" fill="#475569" font-size="11" font-weight="600">エラー回復</text>
<text x="115" y="362" fill="#475569" font-size="10">API が prompt_too_long を返したら reactive_compact を実行し、1 回だけ再試行</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -11,40 +11,40 @@
<rect width="720" height="400" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L4: autoCompact — LLM 全量摘要</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 4: compact_history生成历史摘要</text>
<!-- 触发条件 -->
<rect x="20" y="54" width="680" height="44" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
<text x="35" y="70" fill="#991b1b" font-size="11" font-weight="600">触发条件</text>
<text x="105" y="70" fill="#991b1b" font-size="11">前三层预处理全跑完,估算 token &gt; contextWindow - maxOutputTokens - 13_000</text>
<text x="105" y="86" fill="#991b1b" font-size="10">先尝试 sessionMemoryCompact用已有记忆做轻量摘要不足才调 LLM</text>
<text x="105" y="70" fill="#991b1b" font-size="11">前三步执行后estimate_size(messages) &gt; CONTEXT_LIMIT</text>
<text x="105" y="86" fill="#991b1b" font-size="10">当前实现的 CONTEXT_LIMIT 为 50,000 个字符</text>
<!-- 步骤 -->
<rect x="20" y="106" width="200" height="110" rx="8" fill="#fff" stroke="#94a3b8" stroke-width="1.5"/>
<text x="120" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">步骤 1保存 transcript</text>
<text x="40" y="152" fill="#475569" font-size="10">完整对话写入 .transcripts/</text>
<text x="40" y="168" fill="#475569" font-size="10">JSONL 格式,一行一条消息</text>
<text x="40" y="184" fill="#475569" font-size="10">文件名transcript_{timestamp}.jsonl</text>
<text x="40" y="184" fill="#475569" font-size="10">文件名transcript_{time}.jsonl</text>
<text x="40" y="200" fill="#94a3b8" font-size="9">信息没有丢失,只是移出活跃区</text>
<line x1="225" y1="161" x2="265" y2="161" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="270" y="106" width="200" height="110" rx="8" fill="#fff" stroke="#94a3b8" stroke-width="1.5"/>
<text x="370" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">步骤 2LLM 生成摘要</text>
<text x="290" y="152" fill="#475569" font-size="10">对话历史发给 LLM</text>
<text x="290" y="166" fill="#475569" font-size="9">摘要需包含 9 个部分</text>
<text x="290" y="180" fill="#94a3b8" font-size="8">请求·概念·文件·错误·解决</text>
<text x="290" y="192" fill="#94a3b8" font-size="8">用户消息·待办·当前·下一步</text>
<text x="290" y="206" fill="#94a3b8" font-size="9">只生成一次</text>
<text x="370" y="130" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">步骤 2生成事实摘要</text>
<text x="370" y="152" fill="#475569" font-size="9" text-anchor="middle">对话是不可信数据</text>
<text x="290" y="166" fill="#475569" font-size="9">摘要保留 5 类信息</text>
<text x="290" y="180" fill="#94a3b8" font-size="8">目标·发现与决定·相关文件</text>
<text x="290" y="192" fill="#94a3b8" font-size="8">剩余工作·用户约束</text>
<text x="290" y="206" fill="#94a3b8" font-size="9">不提出或选择后续动作</text>
<line x1="475" y1="161" x2="515" y2="161" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="520" y="106" width="180" height="110" rx="8" fill="#fef2f2" stroke="#dc2626" stroke-width="2"/>
<text x="610" y="130" fill="#991b1b" font-size="12" font-weight="700" text-anchor="middle">步骤 3替换消息列表</text>
<text x="540" y="152" fill="#991b1b" font-size="10">所有旧消息 → 1 条摘要</text>
<text x="540" y="168" fill="#991b1b" font-size="10">模型从摘要继续工作</text>
<text x="540" y="184" fill="#991b1b" font-size="10">附带 recently_read 文件列表</text>
<text x="540" y="200" fill="#ef4444" font-size="9">⚠ 这是无法恢复的操作</text>
<text x="610" y="130" fill="#991b1b" font-size="12" font-weight="700" text-anchor="middle">步骤 3替换历史</text>
<text x="610" y="152" fill="#991b1b" font-size="9" text-anchor="middle">旧历史 → 1 条压缩消息</text>
<text x="610" y="168" fill="#991b1b" font-size="9" text-anchor="middle">用户要求与参考状态分开</text>
<text x="610" y="184" fill="#991b1b" font-size="9" text-anchor="middle">system 区分指令与数据</text>
<text x="610" y="200" fill="#ef4444" font-size="9" text-anchor="middle">完整 transcript 保留在磁盘</text>
<!-- Before/After 对比 -->
<rect x="20" y="234" width="320" height="94" rx="6" fill="#fff" stroke="#94a3b8" stroke-width="1"/>
@@ -54,19 +54,19 @@
<rect x="149" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="154" y="276" fill="#475569" font-size="8">user</text>
<rect x="206" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="211" y="276" fill="#475569" font-size="8">assistant</text>
<rect x="263" y="264" width="52" height="16" rx="3" fill="#e2e8f0"/><text x="268" y="276" fill="#475569" font-size="8">user</text>
<text x="180" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">~180 条消息,占 62K token</text>
<text x="180" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">多条消息,估算 size &gt; 50,000</text>
<line x1="345" y1="281" x2="375" y2="281" stroke="#dc2626" stroke-width="2" marker-end="url(#arrow)"/>
<rect x="380" y="234" width="320" height="94" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1"/>
<text x="540" y="256" fill="#991b1b" font-size="11" font-weight="600" text-anchor="middle">压缩后 messages</text>
<rect x="395" y="264" width="290" height="32" rx="4" fill="#fee2e2" stroke="#fca5a5" stroke-width="0.5"/>
<text x="540" y="276" fill="#991b1b" font-size="9" text-anchor="middle">[Compacted] 摘要:目标 → 创建 hello.py ...</text>
<text x="540" y="290" fill="#991b1b" font-size="9" text-anchor="middle">最近文件hello.py, README.md ...</text>
<text x="540" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">~1 条消息,占 1K token</text>
<text x="540" y="276" fill="#991b1b" font-size="9" text-anchor="middle">Authoritative request入口捕获的用户要求</text>
<text x="540" y="290" fill="#991b1b" font-size="9" text-anchor="middle">Reference state不可信的事实摘要</text>
<text x="540" y="318" fill="#94a3b8" font-size="9" text-anchor="middle">1 条摘要消息,显著低于阈值</text>
<!-- 熔断器 -->
<!-- 错误后补救 -->
<rect x="20" y="340" width="680" height="36" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="362" fill="#475569" font-size="11" font-weight="600">熔断器</text>
<text x="95" y="362" fill="#475569" font-size="10">连续 autocompact 失败 3 次 → 停止重试。防止上下文不可恢复时反复浪费 API 调用</text>
<text x="35" y="362" fill="#475569" font-size="11" font-weight="600">错误后补救</text>
<text x="115" y="362" fill="#475569" font-size="10">API 仍返回 prompt_too_long 时执行 reactive_compact并且只重试 1 次</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -27,7 +27,7 @@
<!-- Title -->
<rect x="0" y="0" width="820" height="48" fill="url(#header)" rx="8"/>
<rect x="0" y="40" width="820" height="8" fill="url(#header)"/>
<text x="410" y="31" fill="#fff" font-size="16" font-weight="700" text-anchor="middle">Context Compact Compression Before LLM Call, Three Trigger Modes</text>
<text x="410" y="31" fill="#fff" font-size="16" font-weight="700" text-anchor="middle">Context Compact: Compression Before LLM Calls, Three Triggers</text>
<!-- Labels -->
<text x="50" y="74" fill="#94a3b8" font-size="11" font-weight="600">s07 Preserved</text>
@@ -50,13 +50,13 @@
<text x="270" y="122" fill="#92400e" font-size="8" font-weight="700" text-anchor="middle">① Every Turn · Unconditional · 0 API</text>
<rect x="186" y="130" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="146" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L3 tool_result_budget</text>
<text x="270" y="146" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 1 tool_result_budget</text>
<rect x="186" y="158" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="174" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L1 snip_compact</text>
<text x="270" y="174" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 2 snip_compact</text>
<rect x="186" y="186" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="202" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L2 micro_compact</text>
<text x="270" y="202" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 3 micro_compact</text>
<!-- ↓ → ◇ -->
<line x1="270" y1="210" x2="270" y2="222" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
@@ -74,10 +74,10 @@
<!-- ── ② Conditional Trigger ── -->
<rect x="186" y="268" width="168" height="16" rx="3" fill="#fed7aa" stroke="#ea580c" stroke-width="0.8"/>
<text x="270" y="280" fill="#9a3412" font-size="8" font-weight="700" text-anchor="middle">② Conditional · Token Over Threshold · 1 API</text>
<text x="270" y="280" fill="#9a3412" font-size="8" font-weight="700" text-anchor="middle">② Conditional · Size Over Limit · 1 API</text>
<rect x="186" y="288" width="168" height="24" rx="4" fill="#fed7aa" stroke="#ea580c" stroke-width="1"/>
<text x="270" y="304" fill="#9a3412" font-size="10" font-weight="600" text-anchor="middle">L4 compact_history</text>
<text x="270" y="304" fill="#9a3412" font-size="10" font-weight="600" text-anchor="middle">Step 4 compact_history</text>
<!-- Pipeline exit → LLM -->
<line x1="370" y1="158" x2="438" y2="158" stroke="#2563eb" stroke-width="2" marker-end="url(#arrow-blue)"/>
@@ -113,7 +113,7 @@
<rect x="580" y="210" width="170" height="56" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1" stroke-dasharray="4,2"/>
<text x="665" y="228" fill="#991b1b" font-size="9" font-weight="700" text-anchor="middle">③ Emergency Trigger</text>
<text x="665" y="242" fill="#991b1b" font-size="8" text-anchor="middle">API returns prompt_too_long</text>
<text x="665" y="256" fill="#991b1b" font-size="8" text-anchor="middle">→ reactive_compact → retry</text>
<text x="665" y="256" fill="#991b1b" font-size="8" text-anchor="middle">→ reactive_compact → retry once</text>
<!-- ===== Loop Back ===== -->
<path d="M 710 158 L 760 158 L 760 348 L 90 348 L 90 184" fill="none" stroke="#555" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
@@ -126,13 +126,13 @@
<text x="94" y="414" fill="#334155" font-size="10">s07 Preserved: loop, hooks, skill loading, sub-agents</text>
<rect x="70" y="426" width="16" height="12" rx="3" fill="#fde68a" stroke="#d97706" stroke-width="1"/>
<text x="94" y="436" fill="#334155" font-size="10">① Every Turn Auto: L3→L1→L2 run unconditionally before each LLM call, 0 API</text>
<text x="94" y="436" fill="#334155" font-size="10">① Every Turn: Steps 1→2→3 run before each LLM call, 0 API</text>
<rect x="70" y="448" width="16" height="12" rx="3" fill="#fed7aa" stroke="#ea580c" stroke-width="1"/>
<text x="94" y="458" fill="#334155" font-size="10">② Conditional: after L3/L1/L2, tokens still over threshold → compact_history, 1 API</text>
<text x="94" y="458" fill="#334155" font-size="10">② Conditional: size remains over the limit after Step 3 → compact_history, 1 API</text>
<rect x="70" y="470" width="16" height="12" rx="3" fill="#fef2f2" stroke="#dc2626" stroke-width="1" stroke-dasharray="3,2"/>
<text x="94" y="480" fill="#334155" font-size="10">Emergency: API returns prompt_too_long → reactive_compact → retry</text>
<text x="94" y="480" fill="#334155" font-size="10">Recovery: API returns prompt_too_long → reactive_compact → retry once</text>
<text x="70" y="498" fill="#94a3b8" font-size="9">Three modes with increasing cost: 0 API → 1 API → 1 API + more aggressive trimming</text>
<text x="70" y="498" fill="#94a3b8" font-size="9">Increasing cost: 0 API → one summary call → one summary call and retry</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -27,7 +27,7 @@
<!-- タイトル -->
<rect x="0" y="0" width="820" height="48" fill="url(#header)" rx="8"/>
<rect x="0" y="40" width="820" height="8" fill="url(#header)"/>
<text x="410" y="31" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Context CompactLLM 呼び出し前圧縮3 つのトリガーモード</text>
<text x="410" y="31" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Context CompactLLM 呼び出し前圧縮3 つのトリガー</text>
<!-- ラベル -->
<text x="50" y="74" fill="#94a3b8" font-size="11" font-weight="600">s07 保持</text>
@@ -50,20 +50,20 @@
<text x="270" y="122" fill="#92400e" font-size="8" font-weight="700" text-anchor="middle">① 毎ターン自動 · 無条件 · 0 API</text>
<rect x="186" y="130" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="146" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L3 tool_result_budget</text>
<text x="270" y="146" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 1 tool_result_budget</text>
<rect x="186" y="158" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="174" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L1 snip_compact</text>
<text x="270" y="174" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 2 snip_compact</text>
<rect x="186" y="186" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="202" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L2 micro_compact</text>
<text x="270" y="202" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 3 micro_compact</text>
<!-- ↓ → ◇ -->
<line x1="270" y1="210" x2="270" y2="222" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- ◇ 判定ダイヤモンド -->
<polygon points="270,226 300,244 270,262 240,244" fill="#f0f4ff" stroke="#ea580c" stroke-width="1.5"/>
<text x="270" y="247" fill="#9a3412" font-size="7" font-weight="600" text-anchor="middle">値超過?</text>
<text x="270" y="247" fill="#9a3412" font-size="7" font-weight="600" text-anchor="middle">推定値超過?</text>
<!-- いいえ:右側注釈 -->
<text x="306" y="240" fill="#16a34a" font-size="9" font-weight="700">No → 通過</text>
@@ -74,10 +74,10 @@
<!-- ── ② 条件トリガー ── -->
<rect x="186" y="268" width="168" height="16" rx="3" fill="#fed7aa" stroke="#ea580c" stroke-width="0.8"/>
<text x="270" y="280" fill="#9a3412" font-size="8" font-weight="700" text-anchor="middle">② 条件 · トークン閾値超過 · 1 API</text>
<text x="270" y="280" fill="#9a3412" font-size="8" font-weight="700" text-anchor="middle">② 条件 · サイズ上限超過 · 1 API</text>
<rect x="186" y="288" width="168" height="24" rx="4" fill="#fed7aa" stroke="#ea580c" stroke-width="1"/>
<text x="270" y="304" fill="#9a3412" font-size="10" font-weight="600" text-anchor="middle">L4 compact_history</text>
<text x="270" y="304" fill="#9a3412" font-size="10" font-weight="600" text-anchor="middle">Step 4 compact_history</text>
<!-- パイプライン出口 → LLM -->
<line x1="370" y1="158" x2="438" y2="158" stroke="#2563eb" stroke-width="2" marker-end="url(#arrow-blue)"/>
@@ -113,7 +113,7 @@
<rect x="580" y="210" width="170" height="56" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1" stroke-dasharray="4,2"/>
<text x="665" y="228" fill="#991b1b" font-size="9" font-weight="700" text-anchor="middle">③ 緊急トリガー</text>
<text x="665" y="242" fill="#991b1b" font-size="8" text-anchor="middle">API が prompt_too_long を返す</text>
<text x="665" y="256" fill="#991b1b" font-size="8" text-anchor="middle">→ reactive_compact → リトライ</text>
<text x="665" y="256" fill="#991b1b" font-size="8" text-anchor="middle">→ reactive_compact → 1 回リトライ</text>
<!-- ===== ループバック ===== -->
<path d="M 710 158 L 760 158 L 760 348 L 90 348 L 90 184" fill="none" stroke="#555" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
@@ -126,13 +126,13 @@
<text x="94" y="414" fill="#334155" font-size="10">s07 保持:ループ、フック、スキルロード、サブエージェント</text>
<rect x="70" y="426" width="16" height="12" rx="3" fill="#fde68a" stroke="#d97706" stroke-width="1"/>
<text x="94" y="436" fill="#334155" font-size="10">① 毎ターン自動L3→L1→L2 が各 LLM 呼び出し前に無条件実行、0 API</text>
<text x="94" y="436" fill="#334155" font-size="10">① 毎ターンStep 1→2→3 を各 LLM 呼び出し前に実行、0 API</text>
<rect x="70" y="448" width="16" height="12" rx="3" fill="#fed7aa" stroke="#ea580c" stroke-width="1"/>
<text x="94" y="458" fill="#334155" font-size="10">② 条件トリガーL3/L1/L2 後もトークン超過 → compact_history、1 API</text>
<text x="94" y="458" fill="#334155" font-size="10">② 条件Step 3 後もサイズ上限超過 → compact_history、1 API</text>
<rect x="70" y="470" width="16" height="12" rx="3" fill="#fef2f2" stroke="#dc2626" stroke-width="1" stroke-dasharray="3,2"/>
<text x="94" y="480" fill="#334155" font-size="10">緊急トリガーAPI が prompt_too_long を返す → reactive_compact → リトライ</text>
<text x="94" y="480" fill="#334155" font-size="10">回復API が prompt_too_long を返す → reactive_compact → 1 回リトライ</text>
<text x="70" y="498" fill="#94a3b8" font-size="9">3 つのモードはコスト増加0 API → 1 API → 1 API + より積極的なトリム</text>
<text x="70" y="498" fill="#94a3b8" font-size="9">コストは順に増加0 API → 1 回の要約 → 1 回の要約とリトライ</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -27,7 +27,7 @@
<!-- 标题 -->
<rect x="0" y="0" width="820" height="48" fill="url(#header)" rx="8"/>
<rect x="0" y="40" width="820" height="8" fill="url(#header)"/>
<text x="410" y="31" fill="#fff" font-size="16" font-weight="700" text-anchor="middle">Context Compact — 压缩插在 LLM 调用前,三种触发</text>
<text x="410" y="31" fill="#fff" font-size="16" font-weight="700" text-anchor="middle">Context CompactLLM 调用前压缩,三种触发</text>
<!-- 标签 -->
<text x="50" y="74" fill="#94a3b8" font-size="11" font-weight="600">s07 保留</text>
@@ -50,20 +50,20 @@
<text x="270" y="122" fill="#92400e" font-size="8" font-weight="700" text-anchor="middle">① 每轮自动 · 无条件 · 0 API</text>
<rect x="186" y="130" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="146" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L3 tool_result_budget</text>
<text x="270" y="146" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 1 tool_result_budget</text>
<rect x="186" y="158" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="174" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L1 snip_compact</text>
<text x="270" y="174" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 2 snip_compact</text>
<rect x="186" y="186" width="168" height="24" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="270" y="202" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">L2 micro_compact</text>
<text x="270" y="202" fill="#92400e" font-size="10" font-weight="600" text-anchor="middle">Step 3 micro_compact</text>
<!-- ↓ → ◇ -->
<line x1="270" y1="210" x2="270" y2="222" stroke="#555" stroke-width="1.2" marker-end="url(#arrow)"/>
<!-- ◇ 判断菱形(紧凑) -->
<polygon points="270,226 300,244 270,262 240,244" fill="#f0f4ff" stroke="#ea580c" stroke-width="1.5"/>
<text x="270" y="247" fill="#9a3412" font-size="7" font-weight="600" text-anchor="middle">超阈值?</text>
<text x="270" y="247" fill="#9a3412" font-size="7" font-weight="600" text-anchor="middle">估算超限?</text>
<!-- 否:右侧文字标注 -->
<text x="306" y="240" fill="#16a34a" font-size="9" font-weight="700">否 → 通过</text>
@@ -74,10 +74,10 @@
<!-- ── ② 条件触发 ── -->
<rect x="186" y="268" width="168" height="16" rx="3" fill="#fed7aa" stroke="#ea580c" stroke-width="0.8"/>
<text x="270" y="280" fill="#9a3412" font-size="8" font-weight="700" text-anchor="middle">② 条件触发 · token 超阈值 · 1 API</text>
<text x="270" y="280" fill="#9a3412" font-size="8" font-weight="700" text-anchor="middle">② 条件触发 · size 超阈值 · 1 API</text>
<rect x="186" y="288" width="168" height="24" rx="4" fill="#fed7aa" stroke="#ea580c" stroke-width="1"/>
<text x="270" y="304" fill="#9a3412" font-size="10" font-weight="600" text-anchor="middle">L4 compact_history</text>
<text x="270" y="304" fill="#9a3412" font-size="10" font-weight="600" text-anchor="middle">Step 4 compact_history</text>
<!-- 管线出口 → LLM -->
<line x1="370" y1="158" x2="438" y2="158" stroke="#2563eb" stroke-width="2" marker-end="url(#arrow-blue)"/>
@@ -113,7 +113,7 @@
<rect x="580" y="210" width="170" height="56" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1" stroke-dasharray="4,2"/>
<text x="665" y="228" fill="#991b1b" font-size="9" font-weight="700" text-anchor="middle">③ 异常触发</text>
<text x="665" y="242" fill="#991b1b" font-size="8" text-anchor="middle">API 返回 prompt_too_long</text>
<text x="665" y="256" fill="#991b1b" font-size="8" text-anchor="middle">→ reactive_compact → 重试</text>
<text x="665" y="256" fill="#991b1b" font-size="8" text-anchor="middle">→ reactive_compact → 重试一次</text>
<!-- ===== 回环y=348 在管线框底 y=334 下方,完全不穿过) ===== -->
<path d="M 710 158 L 760 158 L 760 348 L 90 348 L 90 184" fill="none" stroke="#555" stroke-width="2" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
@@ -126,13 +126,13 @@
<text x="94" y="414" fill="#334155" font-size="10">s07 保留循环、hook、技能加载、子 Agent</text>
<rect x="70" y="426" width="16" height="12" rx="3" fill="#fde68a" stroke="#d97706" stroke-width="1"/>
<text x="94" y="436" fill="#334155" font-size="10">① 每轮自动:L3→L1→L2 在每次 LLM 调用前无条件执行0 API</text>
<text x="94" y="436" fill="#334155" font-size="10">① 每轮自动:Step 1→2→3 在每次 LLM 调用前执行0 API</text>
<rect x="70" y="448" width="16" height="12" rx="3" fill="#fed7aa" stroke="#ea580c" stroke-width="1"/>
<text x="94" y="458" fill="#334155" font-size="10">② 条件触发:L3/L1/L2 跑完 token 仍超阈值 → compact_history1 API</text>
<text x="94" y="458" fill="#334155" font-size="10">② 条件触发:前三步后 size 仍超阈值 → compact_history1 API</text>
<rect x="70" y="470" width="16" height="12" rx="3" fill="#fef2f2" stroke="#dc2626" stroke-width="1" stroke-dasharray="3,2"/>
<text x="94" y="480" fill="#334155" font-size="10">③ 异常触发API 返回 prompt_too_long → reactive_compact → 重试</text>
<text x="94" y="480" fill="#334155" font-size="10">③ 异常触发API 返回 prompt_too_long → reactive_compact → 重试一次</text>
<text x="70" y="498" fill="#94a3b8" font-size="9">三种模式的代价递增0 API → 1 API → 1 API + 更激进的裁剪</text>
<text x="70" y="498" fill="#94a3b8" font-size="9">三种方式逐步增加成本0 API → 1 次摘要 → 1 次摘要与重试</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -22,77 +22,77 @@
<!-- Title bar -->
<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">Context Compaction — Pre-processing Pipeline + Auto-compact + Emergency Fallback</text>
<text x="380" y="28" fill="#fff" font-size="15" font-weight="700" text-anchor="middle">Context Compaction: Four Steps and API Error Recovery</text>
<!-- Design principles (left) -->
<rect x="20" y="62" width="220" height="80" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="130" y="82" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">Design Principles</text>
<text x="130" y="100" fill="#475569" font-size="10" text-anchor="middle">Cheap operations first, expensive later</text>
<text x="130" y="116" fill="#475569" font-size="10" text-anchor="middle">Trim text before dropping messages</text>
<text x="130" y="132" fill="#475569" font-size="10" text-anchor="middle">Drop messages before calling LLM</text>
<text x="130" y="100" fill="#475569" font-size="10" text-anchor="middle">Run lower-cost operations first</text>
<text x="130" y="116" fill="#475569" font-size="10" text-anchor="middle">Preserve recoverable information</text>
<text x="130" y="132" fill="#475569" font-size="10" text-anchor="middle">Summarize only above the limit</text>
<!-- Cost escalation (right) -->
<rect x="530" y="62" width="210" height="80" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="635" y="82" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">Increasing Cost</text>
<text x="635" y="104" fill="#475569" font-size="10" text-anchor="middle">Text ops → LLM summary → Emergency trim</text>
<text x="635" y="124" fill="#94a3b8" font-size="9" text-anchor="middle">0 API · 0 API · 0 API · 1 API · 1 API</text>
<text x="635" y="104" fill="#475569" font-size="10" text-anchor="middle">Structure → Summary → Recovery</text>
<text x="635" y="124" fill="#94a3b8" font-size="9" text-anchor="middle">0 API × 3 · 1 API · at most 1 more</text>
<!-- ===== Pre-processing pipeline title ===== -->
<rect x="20" y="146" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="55" y="163" fill="#64748b" font-size="11" font-weight="600">Pre-processing Pipeline (execution order: L3 → L1 → L2, before every LLM call, 0 API)</text>
<text x="55" y="163" fill="#64748b" font-size="11" font-weight="600">Pre-processing (Step 1 → Step 2 → Step 3 before every LLM call, 0 API)</text>
<!-- L3: toolResultBudget -->
<!-- Step 1: tool_result_budget -->
<rect x="80" y="180" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="200" fill="#1e40af" font-size="12" font-weight="600">L3</text>
<text x="135" y="200" fill="#1e40af" font-size="13" font-weight="700">toolResultBudget</text>
<text x="260" y="200" fill="#1e40af" font-size="11">tool_result total &gt; 200KB → spill largest item</text>
<text x="100" y="200" fill="#1e40af" font-size="12" font-weight="600">Step 1</text>
<text x="155" y="200" fill="#1e40af" font-size="13" font-weight="700">tool_result_budget</text>
<text x="315" y="200" fill="#1e40af" font-size="11">total &gt; 200,000 chars → persist largest</text>
<text x="650" y="200" fill="#1e40af" font-size="10" text-anchor="end">keep full content</text>
<text x="135" y="218" fill="#2563eb" font-size="9">Trigger: every turn, before microCompact can replace full content</text>
<text x="155" y="218" fill="#2563eb" font-size="9">Runs every turn before micro_compact can replace content</text>
<!-- Arrow L3→L1 -->
<!-- Step 1 to Step 2 -->
<line x1="380" y1="226" x2="380" y2="238" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow-d)"/>
<!-- L1: snipCompact -->
<!-- Step 2: snip_compact -->
<rect x="80" y="240" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="260" fill="#1e40af" font-size="12" font-weight="600">L1</text>
<text x="135" y="260" fill="#1e40af" font-size="13" font-weight="700">snipCompact</text>
<text x="100" y="260" fill="#1e40af" font-size="12" font-weight="600">Step 2</text>
<text x="155" y="260" fill="#1e40af" font-size="13" font-weight="700">snip_compact</text>
<text x="260" y="260" fill="#1e40af" font-size="11">messages &gt; 50 → trim middle</text>
<text x="650" y="260" fill="#1e40af" font-size="10" text-anchor="end">keep head/tail</text>
<text x="135" y="278" fill="#2563eb" font-size="9">Trigger: message count exceeds threshold</text>
<text x="155" y="278" fill="#2563eb" font-size="9">Trims above 50 messages and preserves tool pairs</text>
<!-- Arrow L1→L2 -->
<!-- Step 2 to Step 3 -->
<line x1="380" y1="286" x2="380" y2="298" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow-d)"/>
<!-- L2: microCompact -->
<!-- Step 3: micro_compact -->
<rect x="80" y="300" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="320" fill="#1e40af" font-size="12" font-weight="600">L2</text>
<text x="135" y="320" fill="#1e40af" font-size="13" font-weight="700">microCompact</text>
<text x="100" y="320" fill="#1e40af" font-size="12" font-weight="600">Step 3</text>
<text x="155" y="320" fill="#1e40af" font-size="13" font-weight="700">micro_compact</text>
<text x="260" y="320" fill="#1e40af" font-size="11">old tool_result → placeholder (keep latest 3)</text>
<text x="650" y="320" fill="#1e40af" font-size="10" text-anchor="end">compact old</text>
<text x="135" y="338" fill="#2563eb" font-size="9">Trigger: every turn; replace older results with text placeholders</text>
<text x="155" y="338" fill="#2563eb" font-size="9">Runs every turn and keeps the latest 3 results complete</text>
<!-- ===== Auto-compact title ===== -->
<rect x="20" y="358" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="70" y="375" fill="#64748b" font-size="11" font-weight="600">Auto-compact Decision (triggered when pre-processing is insufficient, 1 API call)</text>
<!-- L4: autoCompact -->
<!-- Step 4: compact_history -->
<rect x="80" y="390" width="600" height="58" rx="7" fill="url(#auto)" stroke="#dc2626" stroke-width="2"/>
<text x="100" y="412" fill="#991b1b" font-size="12" font-weight="600">L4</text>
<text x="135" y="412" fill="#991b1b" font-size="13" font-weight="700">autoCompact</text>
<text x="260" y="412" fill="#991b1b" font-size="11">tokens over threshold → LLM summary</text>
<text x="100" y="412" fill="#991b1b" font-size="12" font-weight="600">Step 4</text>
<text x="155" y="412" fill="#991b1b" font-size="13" font-weight="700">compact_history</text>
<text x="305" y="412" fill="#991b1b" font-size="11">size above 50,000 → LLM summary</text>
<text x="650" y="412" fill="#991b1b" font-size="10" text-anchor="end">1 API call</text>
<text x="135" y="428" fill="#dc2626" font-size="9">Threshold: contextWindow - maxOutputTokens - 13,000 · Try sessionMemoryCompact first, then LLM</text>
<text x="135" y="442" fill="#dc2626" font-size="9">Circuit breaker: stop retrying after 3 consecutive failures</text>
<text x="155" y="428" fill="#dc2626" font-size="9">Condition: estimate_size(messages) &gt; CONTEXT_LIMIT</text>
<text x="155" y="442" fill="#dc2626" font-size="9">Save a transcript, then replace active history with one summary</text>
<!-- ===== Emergency fallback title ===== -->
<rect x="20" y="460" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="55" y="477" fill="#64748b" font-size="11" font-weight="600">Emergency Fallback (triggered when API still returns prompt_too_long)</text>
<text x="55" y="477" fill="#64748b" font-size="11" font-weight="600">Error Recovery (when the API returns prompt_too_long, at most once)</text>
<!-- Emergency: reactiveCompact -->
<!-- Fallback: reactive_compact -->
<rect x="80" y="492" width="600" height="62" rx="7" fill="url(#emergency)" stroke="#c2410c" stroke-width="1.5"/>
<text x="100" y="512" fill="#9a3412" font-size="12" font-weight="600">Emrg</text>
<text x="135" y="512" fill="#9a3412" font-size="13" font-weight="700">reactiveCompact</text>
<text x="135" y="528" fill="#9a3412" font-size="10">API returns 413 / prompt_too_long → byte-level trim</text>
<text x="135" y="544" fill="#c2410c" font-size="9">Keep last 5 + summary; more aggressive than autoCompact</text>
<text x="100" y="512" fill="#9a3412" font-size="12" font-weight="600">Retry</text>
<text x="155" y="512" fill="#9a3412" font-size="13" font-weight="700">reactive_compact</text>
<text x="155" y="528" fill="#9a3412" font-size="10">Summarize older history and keep the latest 5 messages</text>
<text x="155" y="544" fill="#c2410c" font-size="9">Preserve tool pairs, then retry once</text>
</svg>

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -22,77 +22,77 @@
<!-- タイトルバー -->
<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">コンテキスト圧縮 — 前処理パイプライン + 自動圧縮 + 緊急フォールバック</text>
<text x="380" y="28" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">コンテキスト圧縮4 ステップと API エラー後の回復</text>
<!-- 設計原則(左側) -->
<rect x="20" y="62" width="220" height="80" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="130" y="82" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">設計原則</text>
<text x="130" y="100" fill="#475569" font-size="10" text-anchor="middle">安価な処理を先に、高価な処理を後に</text>
<text x="130" y="116" fill="#475569" font-size="10" text-anchor="middle">テキスト修正 → メッセージ削除の順</text>
<text x="130" y="132" fill="#475569" font-size="10" text-anchor="middle">メッセージ削除 → LLM 呼び出しの順</text>
<text x="130" y="100" fill="#475569" font-size="10" text-anchor="middle">低コストな処理を先に実行</text>
<text x="130" y="116" fill="#475569" font-size="10" text-anchor="middle">再取得できる情報を保持</text>
<text x="130" y="132" fill="#475569" font-size="10" text-anchor="middle">上限超過時だけ履歴を要約</text>
<!-- コスト増加(右側) -->
<rect x="530" y="62" width="210" height="80" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="635" y="82" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">コスト増加</text>
<text x="635" y="104" fill="#475569" font-size="10" text-anchor="middle">テキスト操作 → LLM 要約 → 緊急トリム</text>
<text x="635" y="124" fill="#94a3b8" font-size="9" text-anchor="middle">0 API · 0 API · 0 API · 1 API · 1 API</text>
<text x="635" y="104" fill="#475569" font-size="10" text-anchor="middle">構造整理 → 履歴要約 → エラー回復</text>
<text x="635" y="124" fill="#94a3b8" font-size="9" text-anchor="middle">0 API × 3 · 1 API · 最大 1 API 追加</text>
<!-- ===== 前処理パイプラインタイトル ===== -->
<rect x="20" y="146" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="55" y="163" fill="#64748b" font-size="11" font-weight="600">前処理パイプライン実行順L3 → L1 → L2、各 LLM 呼び出し前に自動実行、0 API</text>
<text x="55" y="163" fill="#64748b" font-size="11" font-weight="600">前処理Step 1 → Step 2 → Step 3、各 LLM 呼び出し前、0 API</text>
<!-- L3: toolResultBudget -->
<!-- Step 1: tool_result_budget -->
<rect x="80" y="180" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="200" fill="#1e40af" font-size="12" font-weight="600">L3</text>
<text x="135" y="200" fill="#1e40af" font-size="13" font-weight="700">toolResultBudget</text>
<text x="260" y="200" fill="#1e40af" font-size="11">tool_result 合計 &gt; 200KB → 最大項目を退避</text>
<text x="100" y="200" fill="#1e40af" font-size="12" font-weight="600">Step 1</text>
<text x="155" y="200" fill="#1e40af" font-size="13" font-weight="700">tool_result_budget</text>
<text x="315" y="200" fill="#1e40af" font-size="11">合計 &gt; 200,000 文字 → 最大項目を保存</text>
<text x="650" y="200" fill="#1e40af" font-size="10" text-anchor="end">完全内容を保持</text>
<text x="135" y="218" fill="#2563eb" font-size="9">トリガー:毎ターン、microCompact が完全内容を置換する前に実行</text>
<text x="155" y="218" fill="#2563eb" font-size="9">毎ターン実行し、micro_compact より先に内容を保存</text>
<!-- 矢印 L3→L1 -->
<!-- Step 1 to Step 2 -->
<line x1="380" y1="226" x2="380" y2="238" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow-d)"/>
<!-- L1: snipCompact -->
<!-- Step 2: snip_compact -->
<rect x="80" y="240" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="260" fill="#1e40af" font-size="12" font-weight="600">L1</text>
<text x="135" y="260" fill="#1e40af" font-size="13" font-weight="700">snipCompact</text>
<text x="100" y="260" fill="#1e40af" font-size="12" font-weight="600">Step 2</text>
<text x="155" y="260" fill="#1e40af" font-size="13" font-weight="700">snip_compact</text>
<text x="260" y="260" fill="#1e40af" font-size="11">メッセージ &gt; 50 → 中間をトリム</text>
<text x="650" y="260" fill="#1e40af" font-size="10" text-anchor="end">先頭/末尾保持</text>
<text x="135" y="278" fill="#2563eb" font-size="9">トリガー:メッセージ数が閾値を超過</text>
<text x="155" y="278" fill="#2563eb" font-size="9">50 件を超えたら中間を省略し、ツールの組を保持</text>
<!-- 矢印 L1→L2 -->
<!-- Step 2 to Step 3 -->
<line x1="380" y1="286" x2="380" y2="298" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow-d)"/>
<!-- L2: microCompact -->
<!-- Step 3: micro_compact -->
<rect x="80" y="300" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="320" fill="#1e40af" font-size="12" font-weight="600">L2</text>
<text x="135" y="320" fill="#1e40af" font-size="13" font-weight="700">microCompact</text>
<text x="100" y="320" fill="#1e40af" font-size="12" font-weight="600">Step 3</text>
<text x="155" y="320" fill="#1e40af" font-size="13" font-weight="700">micro_compact</text>
<text x="260" y="320" fill="#1e40af" font-size="11">古い tool_result → プレースホルダー(最新 3 件保持)</text>
<text x="650" y="320" fill="#1e40af" font-size="10" text-anchor="end">旧結果を圧縮</text>
<text x="135" y="338" fill="#2563eb" font-size="9">トリガー:毎ターン、古い結果をテキストプレースホルダーに置換</text>
<text x="155" y="338" fill="#2563eb" font-size="9">毎ターン実行し、最新 3 件は完全に保持</text>
<!-- ===== 自動圧縮タイトル ===== -->
<rect x="20" y="358" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="70" y="375" fill="#64748b" font-size="11" font-weight="600">自動圧縮判定前処理で不足時にトリガー、1 API 呼び出し)</text>
<!-- L4: autoCompact -->
<!-- Step 4: compact_history -->
<rect x="80" y="390" width="600" height="58" rx="7" fill="url(#auto)" stroke="#dc2626" stroke-width="2"/>
<text x="100" y="412" fill="#991b1b" font-size="12" font-weight="600">L4</text>
<text x="135" y="412" fill="#991b1b" font-size="13" font-weight="700">autoCompact</text>
<text x="260" y="412" fill="#991b1b" font-size="11">トークンが閾値超過 → LLM 全量要約</text>
<text x="100" y="412" fill="#991b1b" font-size="12" font-weight="600">Step 4</text>
<text x="155" y="412" fill="#991b1b" font-size="13" font-weight="700">compact_history</text>
<text x="305" y="412" fill="#991b1b" font-size="11">サイズが 50,000 超 → LLM 要約</text>
<text x="590" y="412" fill="#991b1b" font-size="10" text-anchor="end">1 API 呼び出し</text>
<text x="135" y="428" fill="#dc2626" font-size="9">閾値: contextWindow - maxOutputTokens - 13,000 · sessionMemoryCompact を先に試行、不足時のみ LLM 呼び出し</text>
<text x="135" y="442" fill="#dc2626" font-size="9">サーキットブレーカー:連続 3 回失敗後にリトライ停止</text>
<text x="155" y="428" fill="#dc2626" font-size="9">条件estimate_size(messages) &gt; CONTEXT_LIMIT</text>
<text x="155" y="442" fill="#dc2626" font-size="9">transcript 保存後、現在の履歴を 1 件の要約に置換</text>
<!-- ===== 緊急フォールバックタイトル ===== -->
<rect x="20" y="460" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="55" y="477" fill="#64748b" font-size="11" font-weight="600">緊急フォールバックAPI が引き続き prompt_too_long を返す場合にトリガー</text>
<text x="55" y="477" fill="#64748b" font-size="11" font-weight="600">エラー回復API が prompt_too_long を返した場合、最大 1 回</text>
<!-- 緊急: reactiveCompact -->
<!-- Fallback: reactive_compact -->
<rect x="80" y="492" width="600" height="62" rx="7" fill="url(#emergency)" stroke="#c2410c" stroke-width="1.5"/>
<text x="100" y="512" fill="#9a3412" font-size="12" font-weight="600">緊急</text>
<text x="135" y="512" fill="#9a3412" font-size="13" font-weight="700">reactiveCompact</text>
<text x="135" y="528" fill="#9a3412" font-size="10">API が 413 / prompt_too_long を返す → バイト単位でトリム</text>
<text x="135" y="544" fill="#c2410c" font-size="9">最後の 5 件 + 要約を保持、autoCompact より積極的</text>
<text x="100" y="512" fill="#9a3412" font-size="12" font-weight="600">回復</text>
<text x="155" y="512" fill="#9a3412" font-size="13" font-weight="700">reactive_compact</text>
<text x="155" y="528" fill="#9a3412" font-size="10">古い履歴を要約し、最新 5 メッセージを保持</text>
<text x="155" y="544" fill="#c2410c" font-size="9">ツールの組を維持して 1 回だけリトライ</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -22,77 +22,77 @@
<!-- 标题栏 -->
<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">上下文压缩 — 预处理管线 + 自动压缩 + 应急兜底</text>
<text x="380" y="28" fill="#fff" font-size="15" font-weight="700" text-anchor="middle">上下文压缩:四步管线与 API 拒绝后的补救</text>
<!-- 左侧说明 -->
<rect x="20" y="62" width="220" height="80" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="130" y="82" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">设计原则</text>
<text x="130" y="100" fill="#475569" font-size="10" text-anchor="middle">便宜的先跑,贵的后跑</text>
<text x="130" y="116" fill="#475569" font-size="10" text-anchor="middle">能改文本 → 不删整条</text>
<text x="130" y="132" fill="#475569" font-size="10" text-anchor="middle">能删整条 → 不调 LLM</text>
<text x="130" y="100" fill="#475569" font-size="10" text-anchor="middle">低成本的处理优先执行</text>
<text x="130" y="116" fill="#475569" font-size="10" text-anchor="middle">可恢复的信息优先保留</text>
<text x="130" y="132" fill="#475569" font-size="10" text-anchor="middle">整理后仍超限才生成摘要</text>
<!-- 右侧代价箭头 -->
<rect x="530" y="62" width="210" height="80" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="635" y="82" fill="#1e3a5f" font-size="12" font-weight="700" text-anchor="middle">代价递增</text>
<text x="635" y="104" fill="#475569" font-size="10" text-anchor="middle">文本操作 → LLM 摘要 → 应急裁剪</text>
<text x="635" y="124" fill="#94a3b8" font-size="9" text-anchor="middle">0 API · 0 API · 0 API · 1 API · 1 API</text>
<text x="635" y="104" fill="#475569" font-size="10" text-anchor="middle">结构整理 → 历史摘要 → 错误后补救</text>
<text x="635" y="124" fill="#94a3b8" font-size="9" text-anchor="middle">0 API × 3 · 1 API · 最多再 1 API</text>
<!-- ===== 预处理管线标题 ===== -->
<rect x="20" y="146" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="55" y="163" fill="#64748b" font-size="11" font-weight="600">预处理管线(执行顺序:L3 → L1 → L2每轮 LLM 调用前自动执行0 API</text>
<text x="55" y="163" fill="#64748b" font-size="11" font-weight="600">预处理管线(执行顺序:Step 1 → Step 2 → Step 3每轮调用前执行0 API</text>
<!-- L3: toolResultBudget -->
<!-- Step 1: tool_result_budget -->
<rect x="80" y="180" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="200" fill="#1e40af" font-size="12" font-weight="600">L3</text>
<text x="135" y="200" fill="#1e40af" font-size="13" font-weight="700">toolResultBudget</text>
<text x="260" y="200" fill="#1e40af" font-size="11">tool_result 总和 &gt; 200KB → 最大项落盘</text>
<text x="100" y="200" fill="#1e40af" font-size="12" font-weight="600">Step 1</text>
<text x="155" y="200" fill="#1e40af" font-size="13" font-weight="700">tool_result_budget</text>
<text x="315" y="200" fill="#1e40af" font-size="11">总和 &gt; 200,000 字符 → 最大项落盘</text>
<text x="650" y="200" fill="#1e40af" font-size="10" text-anchor="end">保留完整内容</text>
<text x="135" y="218" fill="#2563eb" font-size="9">触发:每轮自动,必须在 microCompact 前保留完整内容</text>
<text x="155" y="218" fill="#2563eb" font-size="9">每轮执行,在 micro_compact 前保留超大结果</text>
<!-- 箭头 L3→L1 -->
<!-- Step 1 to Step 2 -->
<line x1="380" y1="226" x2="380" y2="238" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow-d)"/>
<!-- L1: snipCompact -->
<!-- Step 2: snip_compact -->
<rect x="80" y="240" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="260" fill="#1e40af" font-size="12" font-weight="600">L1</text>
<text x="135" y="260" fill="#1e40af" font-size="13" font-weight="700">snipCompact</text>
<text x="100" y="260" fill="#1e40af" font-size="12" font-weight="600">Step 2</text>
<text x="155" y="260" fill="#1e40af" font-size="13" font-weight="700">snip_compact</text>
<text x="260" y="260" fill="#1e40af" font-size="11">消息 &gt; 50 条 → 裁掉中间</text>
<text x="650" y="260" fill="#1e40af" font-size="10" text-anchor="end">保留头尾</text>
<text x="135" y="278" fill="#2563eb" font-size="9">触发:消息超过阈值</text>
<text x="155" y="278" fill="#2563eb" font-size="9">消息超过 50 条时裁剪,并保护工具调用与结果的配对</text>
<!-- 箭头 L1→L2 -->
<!-- Step 2 to Step 3 -->
<line x1="380" y1="286" x2="380" y2="298" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow-d)"/>
<!-- L2: microCompact -->
<!-- Step 3: micro_compact -->
<rect x="80" y="300" width="600" height="46" rx="7" fill="url(#pre)" stroke="#2563eb" stroke-width="1.5"/>
<text x="100" y="320" fill="#1e40af" font-size="12" font-weight="600">L2</text>
<text x="135" y="320" fill="#1e40af" font-size="13" font-weight="700">microCompact</text>
<text x="100" y="320" fill="#1e40af" font-size="12" font-weight="600">Step 3</text>
<text x="155" y="320" fill="#1e40af" font-size="13" font-weight="700">micro_compact</text>
<text x="260" y="320" fill="#1e40af" font-size="11">旧 tool_result → 占位符(保留最近 3 条)</text>
<text x="650" y="320" fill="#1e40af" font-size="10" text-anchor="end">压旧结果</text>
<text x="135" y="338" fill="#2563eb" font-size="9">触发:每轮自动,把较旧结果替换为文本占位符</text>
<text x="155" y="338" fill="#2563eb" font-size="9">每轮执行,最近 3 条结果保持完整</text>
<!-- ===== 自动压缩标题 ===== -->
<rect x="20" y="358" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="70" y="375" fill="#64748b" font-size="11" font-weight="600">自动压缩决策预处理不够时触发1 API 调用)</text>
<!-- L4: autoCompact -->
<!-- Step 4: compact_history -->
<rect x="80" y="390" width="600" height="58" rx="7" fill="url(#auto)" stroke="#dc2626" stroke-width="2"/>
<text x="100" y="412" fill="#991b1b" font-size="12" font-weight="600">L4</text>
<text x="135" y="412" fill="#991b1b" font-size="13" font-weight="700">autoCompact</text>
<text x="260" y="412" fill="#991b1b" font-size="11">token 超阈值 → LLM 全量摘要</text>
<text x="100" y="412" fill="#991b1b" font-size="12" font-weight="600">Step 4</text>
<text x="155" y="412" fill="#991b1b" font-size="13" font-weight="700">compact_history</text>
<text x="305" y="412" fill="#991b1b" font-size="11">size 超过 50,000 → LLM 摘要</text>
<text x="590" y="412" fill="#991b1b" font-size="10" text-anchor="end">1 API 调用</text>
<text x="135" y="428" fill="#dc2626" font-size="9">阈值: contextWindow - maxOutputTokens - 13,000 · 先尝试 sessionMemoryCompact不够才调 LLM</text>
<text x="135" y="442" fill="#dc2626" font-size="9">熔断:连续失败 3 次后停止重试</text>
<text x="155" y="428" fill="#dc2626" font-size="9">条件estimate_size(messages) &gt; CONTEXT_LIMIT</text>
<text x="155" y="442" fill="#dc2626" font-size="9">先保存 transcript再用一条摘要替换当前历史</text>
<!-- ===== 应急兜底标题 ===== -->
<rect x="20" y="460" width="720" height="24" rx="4" fill="#f1f5f9"/>
<text x="55" y="477" fill="#64748b" font-size="11" font-weight="600">应急兜底API 仍然返回 prompt_too_long 时触发)</text>
<text x="55" y="477" fill="#64748b" font-size="11" font-weight="600">错误后补救API 返回 prompt_too_long 时触发,最多一次</text>
<!-- 应急: reactiveCompact -->
<!-- Fallback: reactive_compact -->
<rect x="80" y="492" width="600" height="62" rx="7" fill="url(#emergency)" stroke="#c2410c" stroke-width="1.5"/>
<text x="100" y="512" fill="#9a3412" font-size="12" font-weight="600">应急</text>
<text x="135" y="512" fill="#9a3412" font-size="13" font-weight="700">reactiveCompact</text>
<text x="135" y="528" fill="#9a3412" font-size="10">API 返回 413 / prompt_too_long → 字节级裁剪</text>
<text x="135" y="544" fill="#c2410c" font-size="9">留最后 5 条 + 摘要,比 autoCompact 更激进</text>
<text x="100" y="512" fill="#9a3412" font-size="12" font-weight="600">补救</text>
<text x="155" y="512" fill="#9a3412" font-size="13" font-weight="700">reactive_compact</text>
<text x="155" y="528" fill="#9a3412" font-size="10">总结较早历史,保留最近 5 条消息</text>
<text x="155" y="544" fill="#c2410c" font-size="9">持工具调用与结果配对,随后重试一次</text>
</svg>

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -11,20 +11,20 @@
<rect width="720" height="356" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L3: toolResultBudget Large Result Persistence</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 1: tool_result_budget, Persist Large Results</text>
<!-- Pain Point -->
<rect x="20" y="54" width="680" height="42" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
<text x="35" y="72" fill="#991b1b" font-size="11" font-weight="600">Pain Point</text>
<text x="105" y="72" fill="#991b1b" font-size="11">Model read 30 files in one turn; total tool_result adds up to 500KB, filling the entire context window</text>
<text x="105" y="72" fill="#991b1b" font-size="11">The model read 30 files in one turn; tool_result content totals about 500,000 characters</text>
<!-- Before -->
<text x="155" y="118" fill="#64748b" font-size="12" font-weight="600" text-anchor="middle">Before</text>
<rect x="20" y="128" width="270" height="82" rx="6" fill="#fff" stroke="#94a3b8" stroke-width="1"/>
<text x="35" y="148" fill="#475569" font-size="10" font-family="monospace">tool_result: (78KB) ...</text>
<text x="35" y="164" fill="#475569" font-size="10" font-family="monospace">tool_result: (142KB) ...</text>
<text x="35" y="180" fill="#475569" font-size="10" font-family="monospace">tool_result: (290KB) ...</text>
<text x="155" y="202" fill="#ef4444" font-size="9" font-weight="600" text-anchor="middle">Total 510KB → over budget</text>
<text x="35" y="148" fill="#475569" font-size="10" font-family="monospace">tool_result: (78K chars) ...</text>
<text x="35" y="164" fill="#475569" font-size="10" font-family="monospace">tool_result: (142K chars) ...</text>
<text x="35" y="180" fill="#475569" font-size="10" font-family="monospace">tool_result: (290K chars) ...</text>
<text x="155" y="202" fill="#ef4444" font-size="9" font-weight="600" text-anchor="middle">Total 510K chars → over budget</text>
<!-- Arrow -->
<line x1="295" y1="163" x2="360" y2="163" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow)"/>
@@ -33,18 +33,18 @@
<text x="485" y="118" fill="#16a34a" font-size="12" font-weight="600" text-anchor="middle">After</text>
<rect x="365" y="128" width="335" height="82" rx="6" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="380" y="148" fill="#166534" font-size="10" font-family="monospace">tool_result: &lt;persisted-output&gt;</text>
<text x="395" y="164" fill="#166534" font-size="9">Full output: .task_outputs/t1.txt</text>
<text x="395" y="164" fill="#166534" font-size="9">Full output: .task_outputs/tool-results/t1.txt</text>
<text x="395" y="178" fill="#166534" font-size="9">Preview: (first 2000 chars) ...</text>
<text x="532" y="202" fill="#16a34a" font-size="9" font-weight="600" text-anchor="middle">Total 18KB → normal</text>
<text x="532" y="202" fill="#16a34a" font-size="9" font-weight="600" text-anchor="middle">About 18K chars → within budget</text>
<!-- How it works -->
<rect x="20" y="214" width="680" height="64" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="234" fill="#1e3a5f" font-size="11" font-weight="600">How</text>
<text x="70" y="234" fill="#475569" font-size="10">1. Sum the size of all tool_result in the latest turn</text>
<text x="70" y="250" fill="#475569" font-size="10">2. Over 200KB → sort by size, persist the largest to .task_outputs/tool-results/</text>
<text x="70" y="250" fill="#475569" font-size="10">2. Above 200,000 chars → persist largest results to .task_outputs/tool-results/</text>
<text x="70" y="266" fill="#475569" font-size="10">3. Keep only &lt;persisted-output&gt; marker + first 2000 chars preview in context</text>
<!-- Result summary -->
<rect x="20" y="290" width="680" height="36" rx="6" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="35" y="312" fill="#166534" font-size="11">Result: No data lost (full data on disk), context drops from 510KB to ~18KB, 0 API calls</text>
<text x="35" y="312" fill="#166534" font-size="11">Result: full data remains on disk; context drops from 510K to about 18K chars, 0 API calls</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -11,20 +11,20 @@
<rect width="720" height="356" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L3: toolResultBudget — 大結果の永続化</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 1: tool_result_budget、大きな結果を保存</text>
<!-- ペインポイント -->
<rect x="20" y="54" width="680" height="42" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
<text x="35" y="72" fill="#991b1b" font-size="11" font-weight="600">ペインポイント</text>
<text x="100" y="72" fill="#991b1b" font-size="11">モデルが一度に 30 ファイルを読み込み、単一ターンの tool_result 合計 500KB に達し、コンテキストウィンドウを圧迫</text>
<text x="100" y="72" fill="#991b1b" font-size="11">モデルが一度に 30 ファイルを読みtool_result 合計が約 500,000 文字に到達</text>
<!-- 圧縮前 -->
<text x="155" y="118" fill="#64748b" font-size="12" font-weight="600" text-anchor="middle">圧縮前</text>
<rect x="20" y="128" width="270" height="82" rx="6" fill="#fff" stroke="#94a3b8" stroke-width="1"/>
<text x="35" y="148" fill="#475569" font-size="10" font-family="monospace">tool_result: (78KB) ...</text>
<text x="35" y="164" fill="#475569" font-size="10" font-family="monospace">tool_result: (142KB) ...</text>
<text x="35" y="180" fill="#475569" font-size="10" font-family="monospace">tool_result: (290KB) ...</text>
<text x="155" y="202" fill="#ef4444" font-size="9" font-weight="600" text-anchor="middle">合計 510KB → 予算超過</text>
<text x="35" y="148" fill="#475569" font-size="10" font-family="monospace">tool_result: (78K chars) ...</text>
<text x="35" y="164" fill="#475569" font-size="10" font-family="monospace">tool_result: (142K chars) ...</text>
<text x="35" y="180" fill="#475569" font-size="10" font-family="monospace">tool_result: (290K chars) ...</text>
<text x="155" y="202" fill="#ef4444" font-size="9" font-weight="600" text-anchor="middle">合計 510K 文字 → 予算超過</text>
<!-- 矢印 -->
<line x1="295" y1="163" x2="360" y2="163" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow)"/>
@@ -33,18 +33,18 @@
<text x="485" y="118" fill="#16a34a" font-size="12" font-weight="600" text-anchor="middle">圧縮後</text>
<rect x="365" y="128" width="335" height="82" rx="6" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="380" y="148" fill="#166534" font-size="10" font-family="monospace">tool_result: &lt;persisted-output&gt;</text>
<text x="395" y="164" fill="#166534" font-size="9">Full output: .task_outputs/t1.txt</text>
<text x="395" y="164" fill="#166534" font-size="9">Full output: .task_outputs/tool-results/t1.txt</text>
<text x="395" y="178" fill="#166534" font-size="9">Preview: (先頭 2000 文字) ...</text>
<text x="532" y="202" fill="#16a34a" font-size="9" font-weight="600" text-anchor="middle">合計 18KB → 正常</text>
<text x="532" y="202" fill="#16a34a" font-size="9" font-weight="600" text-anchor="middle"> 18K 文字 → 予算内</text>
<!-- 原理説明 -->
<rect x="20" y="214" width="680" height="64" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="234" fill="#1e3a5f" font-size="11" font-weight="600">方法</text>
<text x="70" y="234" fill="#475569" font-size="10">1. 最終ターンの全 tool_result の合計サイズを集計</text>
<text x="70" y="250" fill="#475569" font-size="10">2. 200KB 超過 → サイズ順にソートし、最大のものから .task_outputs/tool-results/ に永続化</text>
<text x="70" y="250" fill="#475569" font-size="10">2. 200,000 文字超過 → 大きな結果から .task_outputs/tool-results/ に保存</text>
<text x="70" y="266" fill="#475569" font-size="10">3. コンテキストには &lt;persisted-output&gt; マーカー + 先頭 2000 文字のプレビューのみ残す</text>
<!-- 変更サマリー -->
<rect x="20" y="290" width="680" height="36" rx="6" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="35" y="312" fill="#166534" font-size="11">結果:情報は失われていない(ディスクに完全なデータあり)、コンテキストは 510KB → ~18KB に削減、0 回 API 呼び出し</text>
<text x="35" y="312" fill="#166534" font-size="11">結果:完全データはディスクに残り、コンテキストは 510K から約 18K 文字へ縮小、0 API</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -11,20 +11,20 @@
<rect width="720" height="356" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L3: toolResultBudget大结果落盘</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 1: tool_result_budget大结果落盘</text>
<!-- 痛点 -->
<rect x="20" y="54" width="680" height="42" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
<text x="35" y="72" fill="#991b1b" font-size="11" font-weight="600">痛点</text>
<text x="75" y="72" fill="#991b1b" font-size="11">模型一次读了 30 个文件,单轮 tool_result 加起来 500KB直接把上下文窗口打满</text>
<text x="75" y="72" fill="#991b1b" font-size="11">模型一次读了 30 个文件,单轮 tool_result 合计约 500,000 字符</text>
<!-- Before -->
<text x="155" y="118" fill="#64748b" font-size="12" font-weight="600" text-anchor="middle">压缩前</text>
<rect x="20" y="128" width="270" height="82" rx="6" fill="#fff" stroke="#94a3b8" stroke-width="1"/>
<text x="35" y="148" fill="#475569" font-size="10" font-family="monospace">tool_result: (78KB) ...</text>
<text x="35" y="164" fill="#475569" font-size="10" font-family="monospace">tool_result: (142KB) ...</text>
<text x="35" y="180" fill="#475569" font-size="10" font-family="monospace">tool_result: (290KB) ...</text>
<text x="155" y="202" fill="#ef4444" font-size="9" font-weight="600" text-anchor="middle">合计 510KB → 超预算</text>
<text x="35" y="148" fill="#475569" font-size="10" font-family="monospace">tool_result: (78K chars) ...</text>
<text x="35" y="164" fill="#475569" font-size="10" font-family="monospace">tool_result: (142K chars) ...</text>
<text x="35" y="180" fill="#475569" font-size="10" font-family="monospace">tool_result: (290K chars) ...</text>
<text x="155" y="202" fill="#ef4444" font-size="9" font-weight="600" text-anchor="middle">合计 510K 字符 → 超预算</text>
<!-- Arrow -->
<line x1="295" y1="163" x2="360" y2="163" stroke="#16a34a" stroke-width="2" marker-end="url(#arrow)"/>
@@ -33,18 +33,18 @@
<text x="485" y="118" fill="#16a34a" font-size="12" font-weight="600" text-anchor="middle">压缩后</text>
<rect x="365" y="128" width="335" height="82" rx="6" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="380" y="148" fill="#166534" font-size="10" font-family="monospace">tool_result: &lt;persisted-output&gt;</text>
<text x="395" y="164" fill="#166534" font-size="9">Full output: .task_outputs/t1.txt</text>
<text x="395" y="164" fill="#166534" font-size="9">Full output: .task_outputs/tool-results/t1.txt</text>
<text x="395" y="178" fill="#166534" font-size="9">Preview: (前 2000 字符) ...</text>
<text x="532" y="202" fill="#16a34a" font-size="9" font-weight="600" text-anchor="middle">合计 18KB → 正常</text>
<text x="532" y="202" fill="#16a34a" font-size="9" font-weight="600" text-anchor="middle">合计 18K 字符 → 正常</text>
<!-- 原理说明 -->
<rect x="20" y="214" width="680" height="64" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="234" fill="#1e3a5f" font-size="11" font-weight="600">怎么做</text>
<text x="85" y="234" fill="#475569" font-size="10">1. 统计最后一轮所有 tool_result 的总大小</text>
<text x="85" y="250" fill="#475569" font-size="10">2. 超过 200KB → 按大小排序,从最大的开始落盘到 .task_outputs/tool-results/</text>
<text x="85" y="250" fill="#475569" font-size="10">2. 超过 200,000 字符 → 从最大的开始落盘到 .task_outputs/tool-results/</text>
<text x="85" y="266" fill="#475569" font-size="10">3. 上下文里只留 &lt;persisted-output&gt; 标记 + 前 2000 字符预览</text>
<!-- 变化摘要 -->
<rect x="20" y="290" width="680" height="36" rx="6" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="35" y="312" fill="#166534" font-size="11">结果:信息没丢(磁盘有完整数据),上下文从 510KB 降到 ~18KB0 次 API 调用</text>
<text x="35" y="312" fill="#166534" font-size="11">结果:完整数据保留在磁盘,上下文从 510K 降到 18K 字符0 次 API 调用</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -11,7 +11,7 @@
<rect width="720" height="300" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L2: microCompact — Old Result Placeholder Replacement</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 3: micro_compact, Replace Older Results</text>
<!-- Pain Point -->
<rect x="20" y="54" width="680" height="36" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
@@ -39,11 +39,11 @@
<text x="535" y="114" fill="#ca8a04" font-size="12" font-weight="600" text-anchor="middle">After (keep only latest 3 complete)</text>
<rect x="390" y="122" width="310" height="95" rx="6" fill="#fefce8" stroke="#ca8a04" stroke-width="1"/>
<rect x="400" y="130" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="138" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="138" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="145" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="153" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="153" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="160" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="168" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="168" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="175" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="183" fill="#92400e" font-size="8" font-family="monospace">Read file J: (full content, 2800 chars)</text>
<text x="545" y="212" fill="#ca8a04" font-size="9" font-weight="600" text-anchor="middle">Keep latest 3; first 7 become placeholders</text>
@@ -51,7 +51,7 @@
<!-- How -->
<rect x="20" y="228" width="680" height="62" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">Rule</text>
<text x="75" y="248" fill="#475569" font-size="10">Keep the latest 3 tool results complete and replace older results with placeholders.</text>
<text x="75" y="248" fill="#475569" font-size="10">Keep the latest 3; replace older results above 120 characters with placeholders.</text>
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">Placeholder</text>
<text x="105" y="264" fill="#475569" font-size="10">Explain that the result was compacted and that the tool can be run again if needed.</text>
<text x="105" y="280" fill="#94a3b8" font-size="9">The message structure remains valid for the next loop iteration.</text>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -11,7 +11,7 @@
<rect width="720" height="300" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L2: microCompact — 旧結果のプレースホルダー置換</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 3: micro_compact、古い結果を置換</text>
<!-- ペインポイント -->
<rect x="20" y="54" width="680" height="36" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
@@ -39,11 +39,11 @@
<text x="535" y="114" fill="#ca8a04" font-size="12" font-weight="600" text-anchor="middle">圧縮後(最新 3 件のみ完全保持)</text>
<rect x="390" y="122" width="310" height="95" rx="6" fill="#fefce8" stroke="#ca8a04" stroke-width="1"/>
<rect x="400" y="130" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="138" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="138" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="145" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="153" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="153" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="160" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="168" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="168" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="175" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="183" fill="#92400e" font-size="8" font-family="monospace">Read file J: (完全な内容, 2800 文字)</text>
<text x="545" y="212" fill="#ca8a04" font-size="9" font-weight="600" text-anchor="middle">最新 3 件を保持、前 7 件は置換</text>
@@ -51,7 +51,7 @@
<!-- 原理 -->
<rect x="20" y="228" width="680" height="62" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">処理規則</text>
<text x="95" y="248" fill="#475569" font-size="10">最新 3 件の tool_result を完全保持し、古い結果をプレースホルダーに置換する</text>
<text x="95" y="248" fill="#475569" font-size="10">最新 3 件を保持し、120 文字超の古い結果をプレースホルダーに置換。</text>
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">プレースホルダー</text>
<text x="125" y="264" fill="#475569" font-size="10">結果が圧縮済みで、必要ならツールを再実行できることを示す。</text>
<text x="125" y="280" fill="#94a3b8" font-size="9">メッセージ構造を保ったまま次のループへ進める。</text>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -11,7 +11,7 @@
<rect width="720" height="300" fill="#fafbfc" rx="8"/>
<rect x="0" y="0" width="720" height="38" fill="url(#header)" rx="8"/>
<rect x="0" y="30" width="720" height="8" fill="url(#header)"/>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">L2: microCompact旧结果占位替换</text>
<text x="360" y="25" fill="#fff" font-size="14" font-weight="700" text-anchor="middle">Step 3: micro_compact旧结果占位替换</text>
<!-- 痛点 -->
<rect x="20" y="54" width="680" height="36" rx="6" fill="#fef2f2" stroke="#fca5a5" stroke-width="1"/>
@@ -38,11 +38,11 @@
<text x="535" y="114" fill="#ca8a04" font-size="12" font-weight="600" text-anchor="middle">压缩后(只保留最近 3 条完整)</text>
<rect x="390" y="122" width="310" height="95" rx="6" fill="#fefce8" stroke="#ca8a04" stroke-width="1"/>
<rect x="400" y="130" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="138" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="138" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="145" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="153" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="153" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="160" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="168" fill="#92400e" font-size="8" font-family="monospace">[Earlier result compacted. Re-run if needed.]</text>
<text x="408" y="168" fill="#92400e" font-size="8" font-family="monospace">[Earlier tool result compacted. Re-run if needed.]</text>
<rect x="400" y="175" width="290" height="10" rx="2" fill="#fef3c7"/>
<text x="408" y="183" fill="#92400e" font-size="8" font-family="monospace">Read file J: (完整内容, 2800 字符)</text>
<text x="545" y="212" fill="#ca8a04" font-size="9" font-weight="600">只保留最近 3 条,前 7 条变占位</text>
@@ -50,7 +50,7 @@
<!-- 原理 -->
<rect x="20" y="228" width="680" height="62" rx="6" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1"/>
<text x="35" y="248" fill="#1e3a5f" font-size="11" font-weight="600">处理规则</text>
<text x="95" y="248" fill="#475569" font-size="10">遍历 tool_result只保留最近 3 条完整,更旧的替换为占位符。</text>
<text x="95" y="248" fill="#475569" font-size="10">最近 3 条保持完整,更早且超过 120 字符的结果替换为占位符。</text>
<text x="35" y="264" fill="#1e3a5f" font-size="11" font-weight="600">占位内容</text>
<text x="95" y="264" fill="#475569" font-size="10">说明原结果已压缩,并提示需要时重新运行对应工具。</text>
<text x="95" y="280" fill="#94a3b8" font-size="9">消息结构保持不变,后续循环仍可继续处理。</text>

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -38,7 +38,7 @@
<rect x="155" y="86" width="135" height="72" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="222" y="108" fill="#1e3a5f" font-size="11" font-weight="700" text-anchor="middle">Compression</text>
<text x="222" y="124" fill="#64748b" font-size="9" text-anchor="middle">budget → snip → micro</text>
<text x="222" y="138" fill="#64748b" font-size="9" text-anchor="middle">autoCompact</text>
<text x="222" y="138" fill="#64748b" font-size="9" text-anchor="middle">compact_history</text>
<text x="222" y="152" fill="#94a3b8" font-size="8" text-anchor="middle">(s08)</text>
<!-- arrow → Loading (purple) -->
@@ -98,7 +98,7 @@
<!-- ===== Bottom notes ===== -->
<rect x="40" y="358" width="680" height="56" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="60" y="372" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="80" y="382" fill="#475569" font-size="10">s08 preserved: compression pipeline (budget → snip → micro → auto) + emergency trim + loop</text>
<text x="80" y="382" fill="#475569" font-size="10">s08 preserved: budget → snip → micro → summary + error recovery + loop</text>
<rect x="60" y="392" width="12" height="10" rx="2" fill="#f3e8ff" stroke="#7c3aed" stroke-width="1"/>
<text x="80" y="402" fill="#475569" font-size="10">s09 new: Loading (index in SYSTEM + on-demand inject) + Extraction (after each turn) + Consolidation (threshold)</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -38,7 +38,7 @@
<rect x="155" y="86" width="135" height="72" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="222" y="108" fill="#1e3a5f" font-size="11" font-weight="700" text-anchor="middle">圧縮パイプライン</text>
<text x="222" y="124" fill="#64748b" font-size="9" text-anchor="middle">budget → snip → micro</text>
<text x="222" y="138" fill="#64748b" font-size="9" text-anchor="middle">autoCompact</text>
<text x="222" y="138" fill="#64748b" font-size="9" text-anchor="middle">compact_history</text>
<text x="222" y="152" fill="#94a3b8" font-size="8" text-anchor="middle">(s08)</text>
<!-- arrow → Loading (purple) -->
@@ -98,7 +98,7 @@
<!-- ===== Bottom notes ===== -->
<rect x="40" y="358" width="680" height="56" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="60" y="372" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="80" y="382" fill="#475569" font-size="10">s08 維持:圧縮パイプライン(budget → snip → micro → auto+ 緊急トリム + ループ</text>
<text x="80" y="382" fill="#475569" font-size="10">s08 維持budget → snip → micro → summary + エラー回復 + ループ</text>
<rect x="60" y="392" width="12" height="10" rx="2" fill="#f3e8ff" stroke="#7c3aed" stroke-width="1"/>
<text x="80" y="402" fill="#475569" font-size="10">s09 追加Loadingインデックス常駐 + オンデマンド注入)+ Extraction毎ターン終了後+ Consolidation閾値トリガー</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -38,7 +38,7 @@
<rect x="155" y="86" width="135" height="72" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="222" y="108" fill="#1e3a5f" font-size="11" font-weight="700" text-anchor="middle">压缩管线</text>
<text x="222" y="124" fill="#64748b" font-size="9" text-anchor="middle">budget → snip → micro</text>
<text x="222" y="138" fill="#64748b" font-size="9" text-anchor="middle">autoCompact</text>
<text x="222" y="138" fill="#64748b" font-size="9" text-anchor="middle">compact_history</text>
<text x="222" y="152" fill="#94a3b8" font-size="8" text-anchor="middle">(s08)</text>
<!-- arrow → Loading (purple) -->
@@ -98,7 +98,7 @@
<!-- ===== Bottom notes ===== -->
<rect x="40" y="358" width="680" height="56" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="60" y="372" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="80" y="382" fill="#475569" font-size="10">s08 保留:压缩管线(budget → snip → micro → auto+ 应急裁剪 + 循环</text>
<text x="80" y="382" fill="#475569" font-size="10">s08 保留budget → snip → micro → summary + 错误后补救 + 循环</text>
<rect x="60" y="392" width="12" height="10" rx="2" fill="#f3e8ff" stroke="#7c3aed" stroke-width="1"/>
<text x="80" y="402" fill="#475569" font-size="10">s09 新增Loading索引常驻 + 按需注入)+ Extraction每轮结束后+ Consolidation阈值触发</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -73,6 +73,6 @@
<rect x="40" y="296" width="660" height="72" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<text x="60" y="316" fill="#5b21b6" font-size="11" font-weight="600">CC Source Comparison</text>
<text x="60" y="334" fill="#475569" font-size="10">• Selection: LLM side-query (Sonnet selects), not embedding vector similarity</text>
<text x="60" y="350" fill="#475569" font-size="10">• Extraction timing: stop hook (after each turn ends), not after autoCompact</text>
<text x="60" y="350" fill="#475569" font-size="10">• Extraction timing: stop hook after each turn, separate from compact_history</text>
<text x="60" y="365" fill="#475569" font-size="10">• Dream: time + sessions + file lock, not simple count</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -73,6 +73,6 @@
<rect x="40" y="296" width="660" height="72" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<text x="60" y="316" fill="#5b21b6" font-size="11" font-weight="600">CC ソースコード対照</text>
<text x="60" y="334" fill="#475569" font-size="10">• 記憶選択LLM side-querySonnet が選択、embedding ベクトル類似度ではない</text>
<text x="60" y="350" fill="#475569" font-size="10">• 抽出タイミング:stop hook毎ターン終了後、autoCompact 後ではない</text>
<text x="60" y="350" fill="#475569" font-size="10">• 抽出タイミング:各ターン終了時の stop hook、compact_history とは別に実行</text>
<text x="60" y="365" fill="#475569" font-size="10">• Dream時間・セッション・ロックで判定</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -73,6 +73,6 @@
<rect x="40" y="296" width="660" height="72" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<text x="60" y="316" fill="#5b21b6" font-size="11" font-weight="600">CC 源码对照</text>
<text x="60" y="334" fill="#475569" font-size="10">• 记忆选择LLM side-querySonnet 选),不是 embedding 向量相似度</text>
<text x="60" y="350" fill="#475569" font-size="10">• 提取时机stop hook 触发(每轮结束后),不是 autoCompact 后</text>
<text x="60" y="350" fill="#475569" font-size="10">• 提取时机:每轮结束时由 stop hook 触发,与 compact_history 分开执行</text>
<text x="60" y="366" fill="#475569" font-size="10">• Dream 整理:三层门控(时间 ≥ 24h + 会话 ≥ 5 + 文件锁),不是简单计数</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,120 +1,107 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" font-family="system-ui, -apple-system, sans-serif">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 620" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#0891b2"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#475569"/>
</marker>
<marker id="arrow-cyan" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<marker id="arrow-cyan" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#0891b2"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d97706"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<marker id="arrow-green" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#16a34a"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d97706"/>
</marker>
</defs>
<rect width="760" height="470" fill="#fafbfc" rx="8"/>
<rect width="760" height="620" rx="8" fill="#fafbfc"/>
<rect width="760" height="44" rx="8" fill="url(#header)"/>
<rect y="36" width="760" height="8" fill="url(#header)"/>
<text x="380" y="28" text-anchor="middle" fill="#fff" font-size="15" font-weight="700">Agent Teams — One Team Harness</text>
<!-- 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">Agent Teams — Lead Loop + Teammate Threads + MessageBus</text>
<!-- User confirmation, Lead, and typed control -->
<rect x="28" y="82" width="140" height="62" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.5"/>
<text x="98" y="106" text-anchor="middle" fill="#334155" font-size="11" font-weight="700">User</text>
<text x="98" y="124" text-anchor="middle" fill="#64748b" font-size="9">confirm team first</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s10-s14 Preserved</text>
<rect x="180" y="56" width="12" height="10" rx="2" fill="#ecfeff" stroke="#0891b2" stroke-width="1"/>
<text x="198" y="66" fill="#0891b2" font-size="10" font-weight="600">s15 New</text>
<rect x="280" y="56" width="12" height="10" rx="2" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="298" y="66" fill="#16a34a" font-size="10" font-weight="600">Teammate</text>
<rect x="395" y="56" width="12" height="10" rx="2" fill="#fffbeb" stroke="#d97706" stroke-width="1"/>
<text x="413" y="66" fill="#d97706" font-size="10" font-weight="600">Protocol gate</text>
<line x1="168" y1="113" x2="220" y2="113" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- ===== Row 1: Lead Agent Loop ===== -->
<rect x="28" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="63" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">cron_queue</text>
<rect x="220" y="72" width="300" height="82" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.8"/>
<text x="370" y="96" text-anchor="middle" fill="#1e3a5f" font-size="12" font-weight="700">Lead Agent Loop</text>
<text x="370" y="116" text-anchor="middle" fill="#475569" font-size="9">user conversation · task creation · team coordination</text>
<text x="370" y="134" text-anchor="middle" fill="#2563eb" font-size="9" font-weight="600">spawn · send · worktree create/remove · plan review</text>
<line x1="98" y1="110" x2="112" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="520" y1="113" x2="570" y2="113" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<rect x="115" y="90" width="72" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="151" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<rect x="570" y="82" width="162" height="62" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
<text x="651" y="105" text-anchor="middle" fill="#92400e" font-size="10" font-weight="700">Typed control</text>
<text x="651" y="122" text-anchor="middle" fill="#a16207" font-size="8.5">request_id · shutdown</text>
<text x="651" y="136" text-anchor="middle" fill="#a16207" font-size="8.5">plan approval gate</text>
<line x1="187" y1="110" x2="201" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- Connect top row to MessageBus; endpoints meet box edges -->
<line x1="370" y1="154" x2="370" y2="190" stroke="#0891b2" stroke-width="1.8" marker-end="url(#arrow-cyan)"/>
<line x1="651" y1="144" x2="651" y2="190" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<rect x="204" y="86" width="86" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="247" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt + cache</text>
<rect x="60" y="190" width="640" height="44" rx="22" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="380" y="209" text-anchor="middle" fill="#0e7490" font-size="11" font-weight="700">MessageBus · .mailboxes/&lt;name&gt;.jsonl</text>
<text x="380" y="225" text-anchor="middle" fill="#0f766e" font-size="8.5">runtime delivery · ordinary messages · result · idle_notification · control events</text>
<line x1="290" y1="110" x2="304" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- MessageBus and teammate loops -->
<line x1="118" y1="234" x2="118" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="348" y1="234" x2="348" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="578" y1="234" x2="578" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="182" y1="282" x2="182" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="412" y1="282" x2="412" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="642" y1="282" x2="642" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<rect x="307" y="86" width="74" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="344" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM call</text>
<rect x="40" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="150" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">Teammate: config</text>
<text x="150" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">independent prompt · messages · tools</text>
<text x="150" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="150" y="356" text-anchor="middle" fill="#64748b" font-size="8">direct message returns to WORK</text>
<line x1="381" y1="110" x2="395" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="270" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="380" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">Teammate: auth</text>
<text x="380" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">independent prompt · messages · tools</text>
<text x="380" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="380" y="356" text-anchor="middle" fill="#64748b" font-size="8">claimed task returns to WORK</text>
<rect x="398" y="80" width="336" height="60" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="566" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH</text>
<text x="414" y="114" fill="#2563eb" font-size="8">bash · read · write · task(4) · cron(3)</text>
<text x="414" y="128" fill="#0891b2" font-size="8" font-weight="700">★ spawn · send · shutdown · plan review</text>
<rect x="500" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="610" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">Teammate: tests</text>
<text x="610" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">independent prompt · messages · tools</text>
<text x="610" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="610" y="356" text-anchor="middle" fill="#64748b" font-size="8">shutdown exits the loop</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 63 150 L 63 130" fill="none" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
<!-- IDLE task discovery -->
<line x1="150" y1="364" x2="150" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="380" y1="364" x2="380" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="610" y1="364" x2="610" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<!-- ===== Spawn arrow: TOOLS bottom → MessageBus top ===== -->
<line x1="560" y1="140" x2="560" y2="178" stroke="#0891b2" stroke-width="2" marker-end="url(#arrow-cyan)"/>
<rect x="543" y="152" width="38" height="14" rx="3" fill="#ecfeff"/>
<text x="562" y="163" fill="#0891b2" font-size="8" font-weight="600" text-anchor="middle">spawn</text>
<rect x="60" y="404" width="640" height="54" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.5"/>
<text x="380" y="425" text-anchor="middle" fill="#334155" font-size="11" font-weight="700">Shared Task Board · .tasks/</text>
<text x="380" y="444" text-anchor="middle" fill="#475569" font-size="9">IDLE: wait for mailbox first → scan ready tasks → claim atomically → reuse WORK loop</text>
<!-- ===== Row 2: MessageBus ===== -->
<rect x="60" y="178" width="640" height="34" rx="17" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="380" y="200" fill="#0e7490" font-size="11" font-weight="700" text-anchor="middle">MessageBus (.mailboxes/*.jsonl)</text>
<!-- Task binding selects cwd -->
<line x1="380" y1="458" x2="380" y2="482" stroke="#475569" stroke-width="1.5"/>
<line x1="220" y1="482" x2="540" y2="482" stroke="#475569" stroke-width="1.5"/>
<line x1="220" y1="482" x2="220" y2="506" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="540" y1="482" x2="540" y2="506" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="311" y="468" width="138" height="18" rx="4" fill="#fafbfc"/>
<text x="380" y="480" text-anchor="middle" fill="#475569" font-size="8.5" font-weight="600">Task.worktree selects cwd</text>
<!-- ===== Row 3: Teammates ===== -->
<line x1="170" y1="212" x2="170" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="380" y1="212" x2="380" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="590" y1="212" x2="590" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="124" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<text x="334" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<text x="544" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<rect x="60" y="506" width="300" height="66" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="210" y="529" text-anchor="middle" fill="#1e3a5f" font-size="10.5" font-weight="700">Default: repository WORKDIR</text>
<text x="210" y="548" text-anchor="middle" fill="#475569" font-size="8.5">task.worktree is null</text>
<text x="210" y="562" text-anchor="middle" fill="#64748b" font-size="8">same behavior as earlier lessons</text>
<line x1="200" y1="248" x2="200" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<line x1="410" y1="248" x2="410" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<line x1="620" y1="248" x2="620" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<text x="214" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<text x="424" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<text x="634" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<rect x="400" y="506" width="300" height="66" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.5"/>
<text x="550" y="529" text-anchor="middle" fill="#92400e" font-size="10.5" font-weight="700">Opt-in: .worktrees/&lt;name&gt;</text>
<text x="550" y="548" text-anchor="middle" fill="#a16207" font-size="8.5">separate checkout + retained wt/&lt;name&gt; branch</text>
<text x="550" y="562" text-anchor="middle" fill="#78716c" font-size="8">working-directory isolation, not a sandbox</text>
<rect x="60" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="170" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Teammate: alice (Backend)</text>
<text x="75" y="284" fill="#16a34a" font-size="8">inbox → LLM → bash/read/write/send</text>
<text x="75" y="298" fill="#6b7280" font-size="8">WORK → result → IDLE → next message</text>
<rect x="270" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="380" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Teammate: bob (Frontend)</text>
<text x="285" y="284" fill="#16a34a" font-size="8">Independent agent_loop, shared client</text>
<text x="285" y="298" fill="#6b7280" font-size="8">Thread(daemon=True)</text>
<rect x="480" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="590" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Teammate: charlie (QA)</text>
<text x="495" y="284" fill="#16a34a" font-size="8">Cannot spawn other teammates</text>
<text x="495" y="298" fill="#6b7280" font-size="8">spawn → work → result → idle</text>
<!-- ===== Row 4: Plan approval gate ===== -->
<path d="M 60 360 L 10 360 L 10 195 L 60 195" fill="none" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)" stroke-dasharray="5,3"/>
<rect x="20" y="318" width="126" height="18" rx="4" fill="#fffbeb" stroke="#f59e0b" stroke-width="1"/>
<text x="83" y="331" fill="#d97706" font-size="10" font-weight="700" text-anchor="middle">plan_request</text>
<rect x="60" y="340" width="640" height="50" rx="6" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
<text x="380" y="360" fill="#92400e" font-size="11" font-weight="700" text-anchor="middle">Plan Approval Gate</text>
<text x="80" y="378" fill="#78716c" font-size="9">① Teammate submits plan ② Lead approves or rejects ③ bash / write_file stay blocked until approved</text>
<!-- ===== Row 5: Bottom notes ===== -->
<rect x="60" y="410" width="640" height="44" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="80" y="424" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="100" y="434" fill="#475569" font-size="10">s10-s14: prompt assembly, error recovery, task graph, background threads, cron scheduling</text>
<rect x="80" y="440" width="12" height="10" rx="2" fill="#ecfeff" stroke="#0891b2" stroke-width="1"/>
<text x="100" y="450" fill="#475569" font-size="10">s15: MessageBus + persistent teammates + event delivery + typed protocols + plan gate</text>
<rect x="60" y="590" width="640" height="20" rx="5" fill="#ecfdf5" stroke="#bbf7d0"/>
<text x="380" y="604" text-anchor="middle" fill="#166534" font-size="8.5" font-weight="600">Only successful task completion clears the teammate assignment and cwd.</text>
</svg>

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1,120 +1,107 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" font-family="system-ui, -apple-system, sans-serif">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 620" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#0891b2"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#475569"/>
</marker>
<marker id="arrow-cyan" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<marker id="arrow-cyan" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#0891b2"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d97706"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<marker id="arrow-green" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#16a34a"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d97706"/>
</marker>
</defs>
<rect width="760" height="470" fill="#fafbfc" rx="8"/>
<rect width="760" height="620" rx="8" fill="#fafbfc"/>
<rect width="760" height="44" rx="8" fill="url(#header)"/>
<rect y="36" width="760" height="8" fill="url(#header)"/>
<text x="380" y="28" text-anchor="middle" fill="#fff" font-size="15" font-weight="700">Agent Teams — 1 つの Team Harness</text>
<!-- タイト-->
<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">Agent Teams — Lead ループ + チームメイトスレッド + MessageBus</text>
<!-- ユーザー確認、Lead、制御プロトコ-->
<rect x="28" y="82" width="140" height="62" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.5"/>
<text x="98" y="106" text-anchor="middle" fill="#334155" font-size="11" font-weight="700">ユーザー</text>
<text x="98" y="124" text-anchor="middle" fill="#64748b" font-size="9">先にチームを確認</text>
<!-- 凡例 -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s10-s14 保持</text>
<rect x="160" y="56" width="12" height="10" rx="2" fill="#ecfeff" stroke="#0891b2" stroke-width="1"/>
<text x="178" y="66" fill="#0891b2" font-size="10" font-weight="600">s15 新規</text>
<rect x="260" y="56" width="12" height="10" rx="2" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="278" y="66" fill="#16a34a" font-size="10" font-weight="600">チームメイト</text>
<rect x="390" y="56" width="12" height="10" rx="2" fill="#fffbeb" stroke="#d97706" stroke-width="1"/>
<text x="408" y="66" fill="#d97706" font-size="10" font-weight="600">プロトコルゲート</text>
<line x1="168" y1="113" x2="220" y2="113" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- ===== 行 1: Lead Agent ループ ===== -->
<rect x="28" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="63" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">cron_queue</text>
<rect x="220" y="72" width="300" height="82" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.8"/>
<text x="370" y="96" text-anchor="middle" fill="#1e3a5f" font-size="12" font-weight="700">Lead Agent Loop</text>
<text x="370" y="116" text-anchor="middle" fill="#475569" font-size="9">ユーザー対話 · タスク作成 · チーム調整</text>
<text x="370" y="134" text-anchor="middle" fill="#2563eb" font-size="9" font-weight="600">起動 · 送信 · worktree 作成/削除 · 計画レビュー</text>
<line x1="98" y1="110" x2="112" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="520" y1="113" x2="570" y2="113" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<rect x="115" y="90" width="72" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="151" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<rect x="570" y="82" width="162" height="62" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
<text x="651" y="105" text-anchor="middle" fill="#92400e" font-size="10" font-weight="700">型付き制御</text>
<text x="651" y="122" text-anchor="middle" fill="#a16207" font-size="8.5">request_id · shutdown</text>
<text x="651" y="136" text-anchor="middle" fill="#a16207" font-size="8.5">計画承認ゲート</text>
<line x1="187" y1="110" x2="201" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- 線の端点はコンポーネントの境界に合わせる -->
<line x1="370" y1="154" x2="370" y2="190" stroke="#0891b2" stroke-width="1.8" marker-end="url(#arrow-cyan)"/>
<line x1="651" y1="144" x2="651" y2="190" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<rect x="204" y="86" width="86" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="247" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt + cache</text>
<rect x="60" y="190" width="640" height="44" rx="22" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="380" y="209" text-anchor="middle" fill="#0e7490" font-size="11" font-weight="700">MessageBus · .mailboxes/&lt;name&gt;.jsonl</text>
<text x="380" y="225" text-anchor="middle" fill="#0f766e" font-size="8.5">ランタイム配信 · 通常メッセージ · result · idle_notification · 制御イベント</text>
<line x1="290" y1="110" x2="304" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- MessageBus とチームメイトループ -->
<line x1="118" y1="234" x2="118" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="348" y1="234" x2="348" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="578" y1="234" x2="578" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="182" y1="282" x2="182" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="412" y1="282" x2="412" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="642" y1="282" x2="642" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<rect x="307" y="86" width="74" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="344" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM call</text>
<rect x="40" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="150" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">チームメイトconfig</text>
<text x="150" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">独立した prompt · messages · tools</text>
<text x="150" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="150" y="356" text-anchor="middle" fill="#64748b" font-size="8">直接メッセージで WORK へ戻る</text>
<line x1="381" y1="110" x2="395" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="270" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="380" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">チームメイトauth</text>
<text x="380" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">独立した prompt · messages · tools</text>
<text x="380" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="380" y="356" text-anchor="middle" fill="#64748b" font-size="8">Claim したタスクで WORK へ戻る</text>
<rect x="398" y="80" width="336" height="60" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="566" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH</text>
<text x="414" y="114" fill="#2563eb" font-size="8">bash · read · write · task(4) · cron(3)</text>
<text x="414" y="128" fill="#0891b2" font-size="8" font-weight="700">★ spawn · send · shutdown · plan review</text>
<rect x="500" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="610" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">チームメイトtests</text>
<text x="610" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">独立した prompt · messages · tools</text>
<text x="610" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="610" y="356" text-anchor="middle" fill="#64748b" font-size="8">shutdown でループ終了</text>
<!-- ループバック -->
<path d="M 734 110 L 748 110 L 748 150 L 63 150 L 63 130" fill="none" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
<!-- IDLE のタスク発見 -->
<line x1="150" y1="364" x2="150" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="380" y1="364" x2="380" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="610" y1="364" x2="610" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<!-- ===== spawn 矢印 ===== -->
<line x1="560" y1="140" x2="560" y2="178" stroke="#0891b2" stroke-width="2" marker-end="url(#arrow-cyan)"/>
<rect x="543" y="152" width="38" height="14" rx="3" fill="#ecfeff"/>
<text x="562" y="163" fill="#0891b2" font-size="8" font-weight="600" text-anchor="middle">spawn</text>
<rect x="60" y="404" width="640" height="54" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.5"/>
<text x="380" y="425" text-anchor="middle" fill="#334155" font-size="11" font-weight="700">共有タスクボード · .tasks/</text>
<text x="380" y="444" text-anchor="middle" fill="#475569" font-size="9">IDLE受信箱を先に待つ → ready task を走査 → アトミックに Claim → WORK を再利用</text>
<!-- ===== 行 2: MessageBus ===== -->
<rect x="60" y="178" width="640" height="34" rx="17" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="380" y="200" fill="#0e7490" font-size="11" font-weight="700" text-anchor="middle">MessageBus (.mailboxes/*.jsonl)</text>
<!-- タスクの紐付けが cwd を選ぶ -->
<line x1="380" y1="458" x2="380" y2="482" stroke="#475569" stroke-width="1.5"/>
<line x1="220" y1="482" x2="540" y2="482" stroke="#475569" stroke-width="1.5"/>
<line x1="220" y1="482" x2="220" y2="506" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="540" y1="482" x2="540" y2="506" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="311" y="468" width="138" height="18" rx="4" fill="#fafbfc"/>
<text x="380" y="480" text-anchor="middle" fill="#475569" font-size="8.5" font-weight="600">Task.worktree が cwd を選択</text>
<!-- ===== 行 3: チームメイト ===== -->
<line x1="170" y1="212" x2="170" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="380" y1="212" x2="380" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="590" y1="212" x2="590" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="124" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<text x="334" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<text x="544" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<rect x="60" y="506" width="300" height="66" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="210" y="529" text-anchor="middle" fill="#1e3a5f" font-size="10.5" font-weight="700">デフォルト:リポジトリ WORKDIR</text>
<text x="210" y="548" text-anchor="middle" fill="#475569" font-size="8.5">task.worktree は null</text>
<text x="210" y="562" text-anchor="middle" fill="#64748b" font-size="8">以前のレッスンと同じ動作</text>
<line x1="200" y1="248" x2="200" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<line x1="410" y1="248" x2="410" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<line x1="620" y1="248" x2="620" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<text x="214" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<text x="424" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<text x="634" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<rect x="400" y="506" width="300" height="66" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.5"/>
<text x="550" y="529" text-anchor="middle" fill="#92400e" font-size="10.5" font-weight="700">任意:.worktrees/&lt;name&gt;</text>
<text x="550" y="548" text-anchor="middle" fill="#a16207" font-size="8.5">独立 checkout + wt/&lt;name&gt; branch を保持</text>
<text x="550" y="562" text-anchor="middle" fill="#78716c" font-size="8">作業ディレクトリの分離であり sandbox ではない</text>
<rect x="60" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="170" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">チームメイト: alice (Backend)</text>
<text x="75" y="284" fill="#16a34a" font-size="8">inbox → LLM → bash/read/write/send</text>
<text x="75" y="298" fill="#6b7280" font-size="8">WORK → result → IDLE → next message</text>
<rect x="270" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="380" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">チームメイト: bob (Frontend)</text>
<text x="285" y="284" fill="#16a34a" font-size="8">独立 agent_loop、共有 client</text>
<text x="285" y="298" fill="#6b7280" font-size="8">Thread(daemon=True)</text>
<rect x="480" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="590" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">チームメイト: charlie (QA)</text>
<text x="495" y="284" fill="#16a34a" font-size="8">他のチームメイトを spawn 不可</text>
<text x="495" y="298" fill="#6b7280" font-size="8">spawn → work → result → idle</text>
<!-- ===== 行 4: プラン承認ゲート ===== -->
<path d="M 60 360 L 10 360 L 10 195 L 60 195" fill="none" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)" stroke-dasharray="5,3"/>
<rect x="20" y="318" width="126" height="18" rx="4" fill="#fffbeb" stroke="#f59e0b" stroke-width="1"/>
<text x="83" y="331" fill="#d97706" font-size="10" font-weight="700" text-anchor="middle">plan_request</text>
<rect x="60" y="340" width="640" height="50" rx="6" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
<text x="380" y="360" fill="#92400e" font-size="11" font-weight="700" text-anchor="middle">プラン承認ゲート</text>
<text x="80" y="378" fill="#78716c" font-size="9">① プラン提出 ② Lead が承認または却下 ③ approved まで bash / write_file を遮断</text>
<!-- ===== 行 5: 下部ノート ===== -->
<rect x="60" y="410" width="640" height="44" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="80" y="424" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="100" y="434" fill="#475569" font-size="10">s10-s14プロンプト組み立て、エラーリカバリ、タスクグラフ、バックグラウンドスレッド、cron</text>
<rect x="80" y="440" width="12" height="10" rx="2" fill="#ecfeff" stroke="#0891b2" stroke-width="1"/>
<text x="100" y="450" fill="#475569" font-size="10">s15MessageBus + 永続チームメイト + イベント配信 + 型付きプロトコル + プランゲート</text>
<rect x="60" y="590" width="640" height="20" rx="5" fill="#ecfdf5" stroke="#bbf7d0"/>
<text x="380" y="604" text-anchor="middle" fill="#166534" font-size="8.5" font-weight="600">タスク完了に成功した時だけ、チームメイト assignment と cwd を解除する。</text>
</svg>

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@@ -1,131 +1,107 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" font-family="system-ui, -apple-system, sans-serif">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 620" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#0891b2"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#475569"/>
</marker>
<marker id="arrow-cyan" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<marker id="arrow-cyan" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#0891b2"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d97706"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<marker id="arrow-green" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#16a34a"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#d97706"/>
</marker>
</defs>
<rect width="760" height="470" fill="#fafbfc" rx="8"/>
<rect width="760" height="620" rx="8" fill="#fafbfc"/>
<rect width="760" height="44" rx="8" fill="url(#header)"/>
<rect y="36" width="760" height="8" fill="url(#header)"/>
<text x="380" y="28" text-anchor="middle" fill="#fff" font-size="15" font-weight="700">Agent Teams — 一套 Team Harness</text>
<!-- 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">Agent Teams — Lead Loop + Teammate Threads + MessageBus</text>
<!-- 用户确认、Lead 与控制协议 -->
<rect x="28" y="82" width="140" height="62" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.5"/>
<text x="98" y="106" text-anchor="middle" fill="#334155" font-size="11" font-weight="700">用户</text>
<text x="98" y="124" text-anchor="middle" fill="#64748b" font-size="9">先确认团队方案</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s10-s14 保留</text>
<rect x="160" y="56" width="12" height="10" rx="2" fill="#ecfeff" stroke="#0891b2" stroke-width="1"/>
<text x="178" y="66" fill="#0891b2" font-size="10" font-weight="600">s15 新增</text>
<rect x="270" y="56" width="12" height="10" rx="2" fill="#f0fdf4" stroke="#16a34a" stroke-width="1"/>
<text x="288" y="66" fill="#16a34a" font-size="10" font-weight="600">Teammate</text>
<rect x="390" y="56" width="12" height="10" rx="2" fill="#fffbeb" stroke="#d97706" stroke-width="1"/>
<text x="408" y="66" fill="#d97706" font-size="10" font-weight="600">协议闸门</text>
<line x1="168" y1="113" x2="220" y2="113" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- ===== Row 1: Lead Agent Loop ===== -->
<!-- Boxes at y=90..130 (h=40), prompt/LLM at y=86..134 (h=48), TOOLS at y=80..140 (h=60) -->
<rect x="220" y="72" width="300" height="82" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.8"/>
<text x="370" y="96" text-anchor="middle" fill="#1e3a5f" font-size="12" font-weight="700">Lead Agent Loop</text>
<text x="370" y="116" text-anchor="middle" fill="#475569" font-size="9">用户对话 · 创建任务 · 协调团队</text>
<text x="370" y="134" text-anchor="middle" fill="#2563eb" font-size="9" font-weight="600">启动 · 发消息 · 创建/移除 worktree · 审批计划</text>
<rect x="28" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="63" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">cron_queue</text>
<line x1="520" y1="113" x2="570" y2="113" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<line x1="98" y1="110" x2="112" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="570" y="82" width="162" height="62" rx="8" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
<text x="651" y="105" text-anchor="middle" fill="#92400e" font-size="10" font-weight="700">类型化控制</text>
<text x="651" y="122" text-anchor="middle" fill="#a16207" font-size="8.5">request_id · shutdown</text>
<text x="651" y="136" text-anchor="middle" fill="#a16207" font-size="8.5">计划审批闸门</text>
<rect x="115" y="90" width="72" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="151" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<!-- 连线端点精确落在组件边缘 -->
<line x1="370" y1="154" x2="370" y2="190" stroke="#0891b2" stroke-width="1.8" marker-end="url(#arrow-cyan)"/>
<line x1="651" y1="144" x2="651" y2="190" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<line x1="187" y1="110" x2="201" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="60" y="190" width="640" height="44" rx="22" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="380" y="209" text-anchor="middle" fill="#0e7490" font-size="11" font-weight="700">MessageBus · .mailboxes/&lt;name&gt;.jsonl</text>
<text x="380" y="225" text-anchor="middle" fill="#0f766e" font-size="8.5">运行时投递 · 普通消息 · result · idle_notification · 控制事件</text>
<rect x="204" y="86" width="86" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="247" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt + cache</text>
<!-- MessageBus 与队友循环 -->
<line x1="118" y1="234" x2="118" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="348" y1="234" x2="348" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="578" y1="234" x2="578" y2="282" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="182" y1="282" x2="182" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="412" y1="282" x2="412" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="642" y1="282" x2="642" y2="234" stroke="#0891b2" stroke-width="1.2" stroke-dasharray="4 3" marker-end="url(#arrow-cyan)"/>
<line x1="290" y1="110" x2="304" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="40" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="150" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">队友config</text>
<text x="150" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">独立 prompt · messages · tools</text>
<text x="150" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="150" y="356" text-anchor="middle" fill="#64748b" font-size="8">直接消息使其回到 WORK</text>
<rect x="307" y="86" width="74" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="344" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM call</text>
<rect x="270" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="380" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">队友auth</text>
<text x="380" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">独立 prompt · messages · tools</text>
<text x="380" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="380" y="356" text-anchor="middle" fill="#64748b" font-size="8">认领任务使其回到 WORK</text>
<line x1="381" y1="110" x2="395" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="500" y="282" width="220" height="82" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="610" y="305" text-anchor="middle" fill="#166534" font-size="10.5" font-weight="700">队友tests</text>
<text x="610" y="324" text-anchor="middle" fill="#15803d" font-size="8.5">独立 prompt · messages · tools</text>
<text x="610" y="342" text-anchor="middle" fill="#475569" font-size="8.5">WORK → result → IDLE</text>
<text x="610" y="356" text-anchor="middle" fill="#64748b" font-size="8">shutdown 结束循环</text>
<rect x="398" y="80" width="336" height="60" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="566" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH</text>
<text x="414" y="114" fill="#2563eb" font-size="8">bash · read · write · task(4) · cron(3)</text>
<text x="414" y="128" fill="#0891b2" font-size="8" font-weight="700">★ spawn · send · shutdown · plan review</text>
<!-- IDLE 时发现任务 -->
<line x1="150" y1="364" x2="150" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="380" y1="364" x2="380" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="610" y1="364" x2="610" y2="404" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 63 150 L 63 130" fill="none" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)" stroke-dasharray="6,3"/>
<rect x="60" y="404" width="640" height="54" rx="8" fill="#f8fafc" stroke="#64748b" stroke-width="1.5"/>
<text x="380" y="425" text-anchor="middle" fill="#334155" font-size="11" font-weight="700">共享任务板 · .tasks/</text>
<text x="380" y="444" text-anchor="middle" fill="#475569" font-size="9">IDLE先等收件箱 → 扫描 ready task → 原子认领 → 复用 WORK 循环</text>
<!-- ===== Spawn arrow: TOOLS bottom → MessageBus top ===== -->
<!-- TOOLS bottom: y=140, Bus top: y=178 -->
<line x1="560" y1="140" x2="560" y2="178" stroke="#0891b2" stroke-width="2" marker-end="url(#arrow-cyan)"/>
<rect x="543" y="152" width="38" height="14" rx="3" fill="#ecfeff"/>
<text x="562" y="163" fill="#0891b2" font-size="8" font-weight="600" text-anchor="middle">spawn</text>
<!-- 任务绑定选择 cwd -->
<line x1="380" y1="458" x2="380" y2="482" stroke="#475569" stroke-width="1.5"/>
<line x1="220" y1="482" x2="540" y2="482" stroke="#475569" stroke-width="1.5"/>
<line x1="220" y1="482" x2="220" y2="506" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="540" y1="482" x2="540" y2="506" stroke="#475569" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="311" y="468" width="138" height="18" rx="4" fill="#fafbfc"/>
<text x="380" y="480" text-anchor="middle" fill="#475569" font-size="8.5" font-weight="600">Task.worktree 选择 cwd</text>
<!-- ===== Row 2: MessageBus ===== -->
<!-- y=178..212 (h=34) -->
<rect x="60" y="178" width="640" height="34" rx="17" fill="#ecfeff" stroke="#0891b2" stroke-width="2"/>
<text x="380" y="200" fill="#0e7490" font-size="11" font-weight="700" text-anchor="middle">MessageBus (.mailboxes/*.jsonl)</text>
<rect x="60" y="506" width="300" height="66" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="210" y="529" text-anchor="middle" fill="#1e3a5f" font-size="10.5" font-weight="700">默认:仓库 WORKDIR</text>
<text x="210" y="548" text-anchor="middle" fill="#475569" font-size="8.5">task.worktree 为 null</text>
<text x="210" y="562" text-anchor="middle" fill="#64748b" font-size="8">行为与前面章节一致</text>
<!-- ===== Row 3: Teammates ===== -->
<!-- Bus bottom: y=212, Teammate top: y=248 (gap=36) -->
<rect x="400" y="506" width="300" height="66" rx="8" fill="#fff7ed" stroke="#d97706" stroke-width="1.5"/>
<text x="550" y="529" text-anchor="middle" fill="#92400e" font-size="10.5" font-weight="700">按需开启:.worktrees/&lt;name&gt;</text>
<text x="550" y="548" text-anchor="middle" fill="#a16207" font-size="8.5">独立 checkout + 保留 wt/&lt;name&gt; 分支</text>
<text x="550" y="562" text-anchor="middle" fill="#78716c" font-size="8">只隔开工作目录,不是安全沙箱</text>
<!-- Bus → Teammate: incoming arrows (solid green) -->
<line x1="170" y1="212" x2="170" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="380" y1="212" x2="380" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<line x1="590" y1="212" x2="590" y2="248" stroke="#16a34a" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="124" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<text x="334" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<text x="544" y="226" fill="#16a34a" font-size="9" font-weight="600">receive</text>
<!-- Teammate → Bus: send_message (dashed cyan, offset 30px right) -->
<line x1="200" y1="248" x2="200" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<line x1="410" y1="248" x2="410" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<line x1="620" y1="248" x2="620" y2="212" stroke="#0891b2" stroke-width="1" stroke-dasharray="4,2" marker-end="url(#arrow-cyan)"/>
<text x="214" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<text x="424" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<text x="634" y="241" fill="#0891b2" font-size="9" font-weight="600">send</text>
<!-- alice: x=60..280, y=248..314 -->
<rect x="60" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="170" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Teammate: alice (Backend)</text>
<text x="75" y="284" fill="#16a34a" font-size="8">inbox → LLM → bash/read/write/send</text>
<text x="75" y="298" fill="#6b7280" font-size="8">WORK → result → IDLE → next message</text>
<!-- bob: x=270..490, y=248..314 -->
<rect x="270" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="380" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Teammate: bob (Frontend)</text>
<text x="285" y="284" fill="#16a34a" font-size="8">独立 agent_loop共享 client</text>
<text x="285" y="298" fill="#6b7280" font-size="8">Thread(daemon=True)</text>
<!-- charlie: x=480..700, y=248..314 -->
<rect x="480" y="248" width="220" height="66" rx="8" fill="#f0fdf4" stroke="#16a34a" stroke-width="1.5"/>
<text x="590" y="268" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Teammate: charlie (QA)</text>
<text x="495" y="284" fill="#16a34a" font-size="8">不能 spawn 其他 teammate</text>
<text x="495" y="298" fill="#6b7280" font-size="8">spawn → work → result → idle</text>
<!-- ===== Row 4: Plan approval gate ===== -->
<path d="M 60 360 L 10 360 L 10 195 L 60 195" fill="none" stroke="#d97706" stroke-width="1.5" marker-end="url(#arrow-amber)" stroke-dasharray="5,3"/>
<rect x="20" y="318" width="126" height="18" rx="4" fill="#fffbeb" stroke="#f59e0b" stroke-width="1"/>
<text x="83" y="331" fill="#d97706" font-size="10" font-weight="700" text-anchor="middle">plan_request</text>
<rect x="60" y="340" width="640" height="50" rx="6" fill="#fffbeb" stroke="#d97706" stroke-width="1.5"/>
<text x="380" y="360" fill="#92400e" font-size="11" font-weight="700" text-anchor="middle">计划审批闸门</text>
<text x="80" y="378" fill="#78716c" font-size="9">① 队友提交计划 ② Lead 批准或拒绝 ③ approved 前 bash / write_file 被拦截</text>
<!-- ===== Row 5: Bottom notes ===== -->
<rect x="60" y="410" width="640" height="44" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="80" y="424" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="100" y="434" fill="#475569" font-size="10">s10-s14: prompt 组装、错误恢复、任务图、后台线程、cron 调度</text>
<rect x="80" y="440" width="12" height="10" rx="2" fill="#ecfeff" stroke="#0891b2" stroke-width="1"/>
<text x="100" y="450" fill="#475569" font-size="10">s15: MessageBus + 持久队友 + 自动事件投递 + 类型化协议 + 计划闸门</text>
<rect x="60" y="590" width="640" height="20" rx="5" fill="#ecfdf5" stroke="#bbf7d0"/>
<text x="380" y="604" text-anchor="middle" fill="#166534" font-size="8.5" font-weight="600">只有任务成功完成后,运行时才会清除队友的 assignment 和 cwd。</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -1,109 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#059669"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#059669"/>
</marker>
<marker id="arrow-red" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#dc2626"/>
</marker>
</defs>
<rect width="760" height="470" fill="#fafbfc" rx="8"/>
<!-- 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">Autonomous Agents — Idle Task Discovery + Atomic Claim</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s15 Preserved</text>
<rect x="160" y="56" width="12" height="10" rx="2" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="178" y="66" fill="#059669" font-size="10" font-weight="600">s16 New</text>
<!-- ===== Row 1: Lead Loop (s15 preserved) ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
<line x1="90" y1="110" x2="104" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="107" y="90" width="70" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="142" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<line x1="177" y1="110" x2="191" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="194" y="86" width="80" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="234" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt</text>
<line x1="274" y1="110" x2="288" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="291" y="86" width="70" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="326" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM</text>
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="80" width="356" height="60" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (all s15 preserved)</text>
<text x="394" y="114" fill="#2563eb" font-size="8">bash · read · write · task tools · send · protocols</text>
<text x="394" y="128" fill="#7c3aed" font-size="8" font-weight="700">★ request_shutdown · request_plan · review_plan</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- Connector: s16 extends the existing idle state with task discovery -->
<path d="M 326 134 L 326 160 L 170 160 L 170 210" fill="none" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<text x="248" y="156" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">idle teammates look for ready work</text>
<!-- ===== Row 2: Task discovery added to the s15 lifecycle ===== -->
<rect x="30" y="172" width="700" height="195" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="2"/>
<text x="380" y="194" fill="#065f46" font-size="11" font-weight="700" text-anchor="middle">s15 Lifecycle + s16 Task-Board Entry</text>
<!-- WORK box -->
<rect x="55" y="210" width="230" height="100" rx="6" fill="#fff" stroke="#059669" stroke-width="1.5"/>
<text x="170" y="230" fill="#059669" font-size="10" font-weight="700" text-anchor="middle">WORK Phase</text>
<text x="70" y="248" fill="#374151" font-size="8">runtime-delivered messages → LLM → tool calls</text>
<text x="70" y="262" fill="#374151" font-size="8">stop_reason == tool_use → loop</text>
<text x="70" y="276" fill="#374151" font-size="8">stop_reason != tool_use → IDLE</text>
<text x="70" y="298" fill="#6b7280" font-size="7">send result, then enter IDLE</text>
<!-- Arrow: WORK → IDLE -->
<line x1="285" y1="260" x2="415" y2="260" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="350" y="253" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">task done</text>
<!-- Arrow: IDLE → WORK (curved, above) -->
<path d="M 415 232 C 375 200, 320 200, 285 232" fill="none" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<text x="350" y="208" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">work found</text>
<!-- IDLE box -->
<rect x="418" y="210" width="295" height="100" rx="6" fill="#fff" stroke="#059669" stroke-width="1.5"/>
<text x="565" y="230" fill="#059669" font-size="10" font-weight="700" text-anchor="middle">IDLE Phase</text>
<text x="433" y="248" fill="#374151" font-size="8">├ Wait for runtime delivery → back to WORK</text>
<text x="433" y="264" fill="#374151" font-size="8">├ scan_unclaimed_tasks → claim → back to WORK</text>
<text x="433" y="280" fill="#374151" font-size="8">└ No ready task → remain IDLE</text>
<text x="433" y="298" fill="#6b7280" font-size="7">wait_for_messages() + claim_next_task()</text>
<!-- SHUTDOWN box -->
<rect x="515" y="335" width="130" height="24" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1.5"/>
<text x="580" y="351" fill="#991b1b" font-size="9" font-weight="700" text-anchor="middle">SHUTDOWN</text>
<!-- Arrow: IDLE → SHUTDOWN -->
<line x1="580" y1="310" x2="580" y2="335" stroke="#dc2626" stroke-width="1.5" marker-end="url(#arrow-red)"/>
<text x="598" y="326" fill="#dc2626" font-size="7">shutdown_request</text>
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="388" width="700" height="42" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="400" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="410" fill="#475569" font-size="10">s15: MessageBus + protocols + request_shutdown + plan approval</text>
<rect x="50" y="414" width="12" height="10" rx="2" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="70" y="424" fill="#475569" font-size="10">s16: scan_unclaimed_tasks + claim_next_task + task_lock</text>
<!-- ===== Row 4: Autonomous note ===== -->
<rect x="30" y="442" width="700" height="22" rx="4" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="380" y="457" fill="#065f46" font-size="9" text-anchor="middle">Lead creates the task graph · teammates gain 3 task tools and atomically claim ready work</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -1,109 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#059669"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#059669"/>
</marker>
<marker id="arrow-red" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#dc2626"/>
</marker>
</defs>
<rect width="760" height="470" fill="#fafbfc" rx="8"/>
<!-- 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="14" font-weight="700" text-anchor="middle">Autonomous Agents — アイドル時のタスク発見 + 原子的な認領</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s15 保持</text>
<rect x="130" y="56" width="12" height="10" rx="2" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="148" y="66" fill="#059669" font-size="10" font-weight="600">s16 新規</text>
<!-- ===== Row 1: Lead Loop ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
<line x1="90" y1="110" x2="104" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="107" y="90" width="70" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="142" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<line x1="177" y1="110" x2="191" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="194" y="86" width="80" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="234" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt</text>
<line x1="274" y1="110" x2="288" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="291" y="86" width="70" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="326" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM</text>
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="80" width="356" height="60" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCHs15 全保持)</text>
<text x="394" y="114" fill="#2563eb" font-size="8">bash · read · write · task tools · send · protocols</text>
<text x="394" y="128" fill="#7c3aed" font-size="8" font-weight="700">★ request_shutdown · request_plan · review_plan</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- Connector: s16 extends the existing idle state with task discovery -->
<path d="M 326 134 L 326 160 L 170 160 L 170 210" fill="none" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<text x="248" y="156" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">待機中に実行可能な仕事を探す</text>
<!-- ===== Row 2: Task discovery added to the s15 lifecycle ===== -->
<rect x="30" y="172" width="700" height="195" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="2"/>
<text x="380" y="194" fill="#065f46" font-size="11" font-weight="700" text-anchor="middle">s15 ライフサイクル + s16 タスクボード入口</text>
<!-- WORK box -->
<rect x="55" y="210" width="230" height="100" rx="6" fill="#fff" stroke="#059669" stroke-width="1.5"/>
<text x="170" y="230" fill="#059669" font-size="10" font-weight="700" text-anchor="middle">WORK フェーズ</text>
<text x="70" y="248" fill="#374151" font-size="8">ランタイム配信メッセージ → LLM → ツール呼び出し</text>
<text x="70" y="262" fill="#374151" font-size="8">stop_reason == tool_use → ループ</text>
<text x="70" y="276" fill="#374151" font-size="8">stop_reason != tool_use → IDLE</text>
<text x="70" y="298" fill="#6b7280" font-size="7">result を送り、IDLE に入る</text>
<!-- Arrow: WORK → IDLE -->
<line x1="285" y1="260" x2="415" y2="260" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="350" y="253" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">タスク完了</text>
<!-- Arrow: IDLE → WORK -->
<path d="M 415 232 C 375 200, 320 200, 285 232" fill="none" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<text x="350" y="208" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">仕事を発見</text>
<!-- IDLE box -->
<rect x="418" y="210" width="295" height="100" rx="6" fill="#fff" stroke="#059669" stroke-width="1.5"/>
<text x="565" y="230" fill="#059669" font-size="10" font-weight="700" text-anchor="middle">IDLE フェーズ</text>
<text x="433" y="248" fill="#374151" font-size="8">├ ランタイム配信を待つ → WORK に戻る</text>
<text x="433" y="264" fill="#374151" font-size="8">├ scan_unclaimed_tasks → 認領 → WORK に戻る</text>
<text x="433" y="280" fill="#374151" font-size="8">└ 実行可能なタスクなし → IDLE を維持</text>
<text x="433" y="298" fill="#6b7280" font-size="7">wait_for_messages() + claim_next_task()</text>
<!-- SHUTDOWN box -->
<rect x="515" y="335" width="130" height="24" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1.5"/>
<text x="580" y="351" fill="#991b1b" font-size="9" font-weight="700" text-anchor="middle">SHUTDOWN</text>
<!-- Arrow: IDLE → SHUTDOWN -->
<line x1="580" y1="310" x2="580" y2="335" stroke="#dc2626" stroke-width="1.5" marker-end="url(#arrow-red)"/>
<text x="598" y="326" fill="#dc2626" font-size="7">shutdown_request</text>
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="388" width="700" height="42" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="400" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="410" fill="#475569" font-size="10">s15: MessageBus + protocols + request_shutdown + plan approval</text>
<rect x="50" y="414" width="12" height="10" rx="2" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="70" y="424" fill="#475569" font-size="10">s16: scan_unclaimed_tasks + claim_next_task + task_lock</text>
<!-- ===== Row 4 ===== -->
<rect x="30" y="442" width="700" height="22" rx="4" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="380" y="457" fill="#065f46" font-size="9" text-anchor="middle">Lead が依存グラフを作成 · チームメイトは 3 つのタスクツールで仕事を原子的に認領</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -1,109 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 470" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#059669"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#059669"/>
</marker>
<marker id="arrow-red" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#dc2626"/>
</marker>
</defs>
<rect width="760" height="470" fill="#fafbfc" rx="8"/>
<!-- 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">Autonomous Agents — 空闲任务发现 + 原子认领</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s15 保留</text>
<rect x="140" y="56" width="12" height="10" rx="2" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="158" y="66" fill="#059669" font-size="10" font-weight="600">s16 新增</text>
<!-- ===== Row 1: Lead Loop (s15 preserved) ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
<line x1="90" y1="110" x2="104" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="107" y="90" width="70" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="142" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<line x1="177" y1="110" x2="191" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="194" y="86" width="80" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="234" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt</text>
<line x1="274" y1="110" x2="288" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="291" y="86" width="70" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="326" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM</text>
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="80" width="356" height="60" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="98" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (s15 全保留)</text>
<text x="394" y="114" fill="#2563eb" font-size="8">bash · read · write · task tools · send · protocols</text>
<text x="394" y="128" fill="#7c3aed" font-size="8" font-weight="700">★ request_shutdown · request_plan · review_plan</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- Connector: s16 extends the existing idle state with task discovery -->
<path d="M 326 134 L 326 160 L 170 160 L 170 210" fill="none" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<text x="248" y="156" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">空闲时从任务板寻找可执行工作</text>
<!-- ===== Row 2: Task discovery added to the s15 lifecycle ===== -->
<rect x="30" y="172" width="700" height="195" rx="8" fill="#ecfdf5" stroke="#059669" stroke-width="2"/>
<text x="380" y="194" fill="#065f46" font-size="11" font-weight="700" text-anchor="middle">s15 生命周期 + s16 任务板入口</text>
<!-- WORK box -->
<rect x="55" y="210" width="230" height="100" rx="6" fill="#fff" stroke="#059669" stroke-width="1.5"/>
<text x="170" y="230" fill="#059669" font-size="10" font-weight="700" text-anchor="middle">WORK 阶段</text>
<text x="70" y="248" fill="#374151" font-size="8">消息自动进入上下文 → LLM → 工具调用</text>
<text x="70" y="262" fill="#374151" font-size="8">stop_reason == tool_use → loop</text>
<text x="70" y="276" fill="#374151" font-size="8">stop_reason != tool_use → IDLE</text>
<text x="70" y="298" fill="#6b7280" font-size="7">完成后发送 result再进入 IDLE</text>
<!-- Arrow: WORK → IDLE -->
<line x1="285" y1="260" x2="415" y2="260" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)"/>
<text x="350" y="253" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">任务完成</text>
<!-- Arrow: IDLE → WORK (curved, above) -->
<path d="M 415 232 C 375 200, 320 200, 285 232" fill="none" stroke="#059669" stroke-width="1.5" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<text x="350" y="208" fill="#059669" font-size="8" font-weight="600" text-anchor="middle">发现新任务</text>
<!-- IDLE box -->
<rect x="418" y="210" width="295" height="100" rx="6" fill="#fff" stroke="#059669" stroke-width="1.5"/>
<text x="565" y="230" fill="#059669" font-size="10" font-weight="700" text-anchor="middle">IDLE 阶段</text>
<text x="433" y="248" fill="#374151" font-size="8">├ 等待运行时投递消息 → 回 WORK</text>
<text x="433" y="264" fill="#374151" font-size="8">├ scan_unclaimed_tasks → 认领 → 回 WORK</text>
<text x="433" y="280" fill="#374151" font-size="8">└ 没有就绪任务 → 保持 IDLE</text>
<text x="433" y="298" fill="#6b7280" font-size="7">wait_for_messages() + claim_next_task()</text>
<!-- SHUTDOWN box -->
<rect x="515" y="335" width="130" height="24" rx="6" fill="#fef2f2" stroke="#dc2626" stroke-width="1.5"/>
<text x="580" y="351" fill="#991b1b" font-size="9" font-weight="700" text-anchor="middle">SHUTDOWN</text>
<!-- Arrow: IDLE → SHUTDOWN -->
<line x1="580" y1="310" x2="580" y2="335" stroke="#dc2626" stroke-width="1.5" marker-end="url(#arrow-red)"/>
<text x="598" y="326" fill="#dc2626" font-size="7">shutdown_request</text>
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="388" width="700" height="42" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="400" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="410" fill="#475569" font-size="10">s15: MessageBus + protocols + request_shutdown + plan approval</text>
<rect x="50" y="414" width="12" height="10" rx="2" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="70" y="424" fill="#475569" font-size="10">s16: scan_unclaimed_tasks + claim_next_task + task_lock</text>
<!-- ===== Row 4: Autonomous note ===== -->
<rect x="30" y="442" width="700" height="22" rx="4" fill="#ecfdf5" stroke="#059669" stroke-width="1"/>
<text x="380" y="457" fill="#065f46" font-size="9" text-anchor="middle">Lead 创建任务依赖图 · 队友获得 3 个任务工具并原子认领就绪工作</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -23,11 +23,11 @@
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s17 Preserved</text>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s15 Preserved</text>
<rect x="160" y="56" width="12" height="10" rx="2" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="178" y="66" fill="#dc2626" font-size="10" font-weight="600">s18 New</text>
<text x="178" y="66" fill="#dc2626" font-size="10" font-weight="600">s16 New</text>
<!-- ===== Row 1: Lead Loop (s17 preserved) ===== -->
<!-- ===== Row 1: Lead Loop (s15 preserved) ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
@@ -49,18 +49,18 @@
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="76" width="356" height="72" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (Lead 18 tools)</text>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (Lead 16 tools)</text>
<text x="394" y="109" fill="#2563eb" font-size="7.5">bash · read · write · task(4) · send · inbox</text>
<text x="394" y="121" fill="#7c3aed" font-size="7.5" font-weight="700">request_shutdown · request_plan · review_plan</text>
<text x="394" y="133" fill="#b45309" font-size="7.5" font-weight="700">create_worktree · remove_worktree · keep_worktree</text>
<text x="394" y="133" fill="#b45309" font-size="7.5" font-weight="700">create_worktree · remove_worktree</text>
<text x="394" y="145" fill="#dc2626" font-size="7.5" font-weight="700">★ connect_mcp + dynamic mcp__server__tool tools</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- ===== Row 2: MCP Architecture (s18 new) ===== -->
<!-- ===== Row 2: MCP Architecture (s16 new) ===== -->
<rect x="30" y="172" width="700" height="215" rx="8" fill="#fff1f2" stroke="#dc2626" stroke-width="2"/>
<text x="380" y="194" fill="#991b1b" font-size="11" font-weight="700" text-anchor="middle">MCP Architecture (s18 new: standard protocol + external tools dynamic integration)</text>
<text x="380" y="194" fill="#991b1b" font-size="11" font-weight="700" text-anchor="middle">MCP Architecture (s16 new: standard protocol + dynamic external tools)</text>
<!-- Agent Side -->
<rect x="50" y="210" width="255" height="140" rx="6" fill="#fff" stroke="#dc2626" stroke-width="1.5"/>
@@ -102,11 +102,11 @@
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="400" width="700" height="22" rx="4" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="408" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="418" fill="#475569" font-size="10">s17: worktree + events + protocols (Lead 17)</text>
<text x="70" y="418" fill="#475569" font-size="10">s15: atomic claims + task worktrees + protocols</text>
<rect x="420" y="408" width="12" height="10" rx="2" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="440" y="418" fill="#475569" font-size="10">s18: MCP + dynamic tools (Lead 18)</text>
<text x="440" y="418" fill="#475569" font-size="10">s16: MCP + dynamic tools (Lead 16)</text>
<!-- ===== Final note ===== -->
<rect x="30" y="430" width="700" height="22" rx="4" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="380" y="444" fill="#991b1b" font-size="9" font-weight="600" text-anchor="middle">Next: s19 combines tools, permissions, teams, worktrees, MCP, and more into one while True loop.</text>
<text x="380" y="444" fill="#991b1b" font-size="9" font-weight="600" text-anchor="middle">Next: s17 combines tools, permissions, teams, worktrees, MCP, and more into one while True loop.</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -23,9 +23,9 @@
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s17 保持</text>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s15 保持</text>
<rect x="130" y="56" width="12" height="10" rx="2" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="148" y="66" fill="#dc2626" font-size="10" font-weight="600">s18 新規</text>
<text x="148" y="66" fill="#dc2626" font-size="10" font-weight="600">s16 新規</text>
<!-- ===== Row 1: Lead Loop ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
@@ -49,10 +49,10 @@
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="76" width="356" height="72" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCHLead 18 tools</text>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCHLead 16 tools</text>
<text x="394" y="109" fill="#2563eb" font-size="7.5">bash · read · write · task(4) · send · inbox</text>
<text x="394" y="121" fill="#7c3aed" font-size="7.5" font-weight="700">request_shutdown · request_plan · review_plan</text>
<text x="394" y="133" fill="#b45309" font-size="7.5" font-weight="700">create_worktree · remove_worktree · keep_worktree</text>
<text x="394" y="133" fill="#b45309" font-size="7.5" font-weight="700">create_worktree · remove_worktree</text>
<text x="394" y="145" fill="#dc2626" font-size="7.5" font-weight="700">★ connect_mcp + 動的 mcp__server__tool ツール</text>
<!-- Loop back -->
@@ -60,7 +60,7 @@
<!-- ===== Row 2: MCP Architecture ===== -->
<rect x="30" y="172" width="700" height="215" rx="8" fill="#fff1f2" stroke="#dc2626" stroke-width="2"/>
<text x="380" y="194" fill="#991b1b" font-size="11" font-weight="700" text-anchor="middle">MCP アーキテクチャs18 新規:標準プロトコル + 外部ツール動的統合)</text>
<text x="380" y="194" fill="#991b1b" font-size="11" font-weight="700" text-anchor="middle">MCP アーキテクチャs16 新規:標準プロトコル + 外部ツール動的統合)</text>
<!-- Agent Side -->
<rect x="50" y="210" width="255" height="140" rx="6" fill="#fff" stroke="#dc2626" stroke-width="1.5"/>
@@ -102,11 +102,11 @@
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="400" width="700" height="22" rx="4" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="408" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="418" fill="#475569" font-size="10">s17: worktree + events + protocolsLead 17</text>
<text x="70" y="418" fill="#475569" font-size="10">s15: atomic claim + task worktree + protocols</text>
<rect x="420" y="408" width="12" height="10" rx="2" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="440" y="418" fill="#475569" font-size="10">s18: MCP + dynamic toolsLead 18</text>
<text x="440" y="418" fill="#475569" font-size="10">s16: MCP + dynamic toolsLead 16</text>
<!-- ===== Final note ===== -->
<rect x="30" y="430" width="700" height="22" rx="4" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="380" y="444" fill="#991b1b" font-size="9" font-weight="600" text-anchor="middle">次の s19tools、permissions、teams、worktree、MCP などを 1 つの while True ループに統合。</text>
<text x="380" y="444" fill="#991b1b" font-size="9" font-weight="600" text-anchor="middle">次の s17tools、permissions、teams、worktree、MCP などを 1 つの while True ループに統合。</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -23,11 +23,11 @@
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s17 保留</text>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s15 保留</text>
<rect x="140" y="56" width="12" height="10" rx="2" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="158" y="66" fill="#dc2626" font-size="10" font-weight="600">s18 新增</text>
<text x="158" y="66" fill="#dc2626" font-size="10" font-weight="600">s16 新增</text>
<!-- ===== Row 1: Lead Loop (s17 preserved) ===== -->
<!-- ===== Row 1: Lead Loop (s15 preserved) ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
@@ -49,18 +49,18 @@
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="76" width="356" height="72" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (Lead 18 tools)</text>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (Lead 16 tools)</text>
<text x="394" y="109" fill="#2563eb" font-size="7.5">bash · read · write · task(4) · send · inbox</text>
<text x="394" y="121" fill="#7c3aed" font-size="7.5" font-weight="700">request_shutdown · request_plan · review_plan</text>
<text x="394" y="133" fill="#b45309" font-size="7.5" font-weight="700">create_worktree · remove_worktree · keep_worktree</text>
<text x="394" y="133" fill="#b45309" font-size="7.5" font-weight="700">create_worktree · remove_worktree</text>
<text x="394" y="145" fill="#dc2626" font-size="7.5" font-weight="700">★ connect_mcp + 动态 mcp__server__tool 工具</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- ===== Row 2: MCP Architecture (s18 new) ===== -->
<!-- ===== Row 2: MCP Architecture (s16 new) ===== -->
<rect x="30" y="172" width="700" height="215" rx="8" fill="#fff1f2" stroke="#dc2626" stroke-width="2"/>
<text x="380" y="194" fill="#991b1b" font-size="11" font-weight="700" text-anchor="middle">MCP 架构s18 新增:标准协议 + 外部工具动态接入)</text>
<text x="380" y="194" fill="#991b1b" font-size="11" font-weight="700" text-anchor="middle">MCP 架构s16 新增:标准协议 + 外部工具动态接入)</text>
<!-- Agent Side -->
<rect x="50" y="210" width="255" height="140" rx="6" fill="#fff" stroke="#dc2626" stroke-width="1.5"/>
@@ -102,11 +102,11 @@
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="400" width="700" height="22" rx="4" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="408" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="418" fill="#475569" font-size="10">s17: worktree + events + protocols (Lead 17)</text>
<text x="70" y="418" fill="#475569" font-size="10">s15: 原子认领 + 任务 worktree + 协议</text>
<rect x="420" y="408" width="12" height="10" rx="2" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="440" y="418" fill="#475569" font-size="10">s18: MCP + dynamic tools (Lead 18)</text>
<text x="440" y="418" fill="#475569" font-size="10">s16: MCP + dynamic tools (Lead 16)</text>
<!-- ===== Final note ===== -->
<rect x="30" y="430" width="700" height="22" rx="4" fill="#fff1f2" stroke="#dc2626" stroke-width="1"/>
<text x="380" y="444" fill="#991b1b" font-size="9" font-weight="600" text-anchor="middle">下一章 s19把工具、权限、团队、worktree、MCP 等机制合回同一个 while True 循环。</text>
<text x="380" y="444" fill="#991b1b" font-size="9" font-weight="600" text-anchor="middle">下一章 s17把工具、权限、团队、worktree、MCP 等机制合回同一个 while True 循环。</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -20,7 +20,7 @@
<rect width="920" height="620" rx="8" fill="#fafbfc"/>
<rect x="0" y="0" width="920" height="46" rx="8" fill="url(#header)"/>
<rect x="0" y="38" width="920" height="8" fill="url(#header)"/>
<text x="460" y="29" text-anchor="middle" fill="#fff" font-size="17" font-weight="700">s19 Integrated Harness — Many Mechanisms, One Loop</text>
<text x="460" y="29" text-anchor="middle" fill="#fff" font-size="17" font-weight="700">s17 Integrated Harness — Many Mechanisms, One Loop</text>
<rect x="40" y="76" width="840" height="212" rx="8" fill="#eef2ff" stroke="#2563eb" stroke-width="1.8"/>
<text x="460" y="101" text-anchor="middle" fill="#1e3a8a" font-size="13" font-weight="700">Core Agent Loop</text>
<rect x="70" y="128" width="110" height="48" rx="7" fill="#fff" stroke="#2563eb" stroke-width="1.4"/>
@@ -69,9 +69,9 @@
<rect x="700" y="318" width="180" height="104" rx="8" fill="#f0fdfa" stroke="#0d9488" stroke-width="1.4"/>
<text x="790" y="341" text-anchor="middle" fill="#0f766e" font-size="11" font-weight="700">Teams &amp; Plugins</text>
<text x="718" y="362" fill="#0f766e" font-size="9">s06 subagent</text>
<text x="718" y="377" fill="#0f766e" font-size="9">s15-s16 team protocols</text>
<text x="718" y="392" fill="#0f766e" font-size="9">s17 worktree isolation</text>
<text x="718" y="407" fill="#0f766e" font-size="9">s18 MCP tools</text>
<text x="718" y="377" fill="#0f766e" font-size="9">s15 teams + task protocols</text>
<text x="718" y="392" fill="#0f766e" font-size="9">s15 task-bound worktrees</text>
<text x="718" y="407" fill="#0f766e" font-size="9">s16 MCP tools</text>
<path d="M 790 318 L 790 188" fill="none" stroke="#0d9488" stroke-width="1.3" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<rect x="70" y="462" width="780" height="112" rx="8" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.2"/>
<text x="460" y="487" text-anchor="middle" fill="#1e293b" font-size="12" font-weight="700">TOOL POOL: 27 builtins + dynamic mcp__server__tool</text>
@@ -80,6 +80,6 @@
<text x="95" y="548" fill="#334155" font-size="9">durable work: task tools · cron tools</text>
<text x="510" y="512" fill="#334155" font-size="9">team: spawn_teammate · send_message · typed protocols</text>
<text x="510" y="530" fill="#334155" font-size="9">protocol: request_shutdown · request_plan · review_plan</text>
<text x="510" y="548" fill="#334155" font-size="9">isolation/plugin: worktree tools · connect_mcp</text>
<text x="510" y="548" fill="#334155" font-size="9">workdir/plugin: create/remove_worktree · connect_mcp</text>
<path d="M 850 518 L 890 518 L 890 152 L 850 152" fill="none" stroke="#475569" stroke-width="1.2" marker-end="url(#arrow)" stroke-dasharray="4,4"/>
</svg>

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -20,7 +20,7 @@
<rect width="920" height="620" rx="8" fill="#fafbfc"/>
<rect x="0" y="0" width="920" height="46" rx="8" fill="url(#header)"/>
<rect x="0" y="38" width="920" height="8" fill="url(#header)"/>
<text x="460" y="29" text-anchor="middle" fill="#fff" font-size="17" font-weight="700">s19 Integrated Harness — 多くの仕組みを 1 つのループへ</text>
<text x="460" y="29" text-anchor="middle" fill="#fff" font-size="17" font-weight="700">s17 Integrated Harness — 多くの仕組みを 1 つのループへ</text>
<rect x="40" y="76" width="840" height="212" rx="8" fill="#eef2ff" stroke="#2563eb" stroke-width="1.8"/>
<text x="460" y="101" text-anchor="middle" fill="#1e3a8a" font-size="13" font-weight="700">Core Agent Loop</text>
<rect x="70" y="128" width="110" height="48" rx="7" fill="#fff" stroke="#2563eb" stroke-width="1.4"/>
@@ -69,9 +69,9 @@
<rect x="700" y="318" width="180" height="104" rx="8" fill="#f0fdfa" stroke="#0d9488" stroke-width="1.4"/>
<text x="790" y="341" text-anchor="middle" fill="#0f766e" font-size="11" font-weight="700">Teams / Plugins</text>
<text x="718" y="362" fill="#0f766e" font-size="9">s06 subagent</text>
<text x="718" y="377" fill="#0f766e" font-size="9">s15-s16 team protocols</text>
<text x="718" y="392" fill="#0f766e" font-size="9">s17 worktree isolation</text>
<text x="718" y="407" fill="#0f766e" font-size="9">s18 MCP tools</text>
<text x="718" y="377" fill="#0f766e" font-size="9">s15 teams + task protocols</text>
<text x="718" y="392" fill="#0f766e" font-size="9">s15 task-bound worktrees</text>
<text x="718" y="407" fill="#0f766e" font-size="9">s16 MCP tools</text>
<path d="M 790 318 L 790 188" fill="none" stroke="#0d9488" stroke-width="1.3" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<rect x="70" y="462" width="780" height="112" rx="8" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.2"/>
<text x="460" y="487" text-anchor="middle" fill="#1e293b" font-size="12" font-weight="700">TOOL POOL: 27 builtins + dynamic mcp__server__tool</text>
@@ -80,6 +80,6 @@
<text x="95" y="548" fill="#334155" font-size="9">durable work: task tools · cron tools</text>
<text x="510" y="512" fill="#334155" font-size="9">team: spawn_teammate · send_message · typed protocols</text>
<text x="510" y="530" fill="#334155" font-size="9">protocol: request_shutdown · request_plan · review_plan</text>
<text x="510" y="548" fill="#334155" font-size="9">isolation/plugin: worktree tools · connect_mcp</text>
<text x="510" y="548" fill="#334155" font-size="9">workdir/plugin: create/remove_worktree · connect_mcp</text>
<path d="M 850 518 L 890 518 L 890 152 L 850 152" fill="none" stroke="#475569" stroke-width="1.2" marker-end="url(#arrow)" stroke-dasharray="4,4"/>
</svg>

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -21,7 +21,7 @@
<rect width="920" height="620" rx="8" fill="#fafbfc"/>
<rect x="0" y="0" width="920" height="46" rx="8" fill="url(#header)"/>
<rect x="0" y="38" width="920" height="8" fill="url(#header)"/>
<text x="460" y="29" text-anchor="middle" fill="#fff" font-size="17" font-weight="700">s19 Agent Harness 集成 — 多种机制,一个循环</text>
<text x="460" y="29" text-anchor="middle" fill="#fff" font-size="17" font-weight="700">s17 Agent Harness 集成 — 多种机制,一个循环</text>
<!-- Main loop band -->
<rect x="40" y="76" width="840" height="212" rx="8" fill="#eef2ff" stroke="#2563eb" stroke-width="1.8"/>
@@ -87,9 +87,9 @@
<rect x="700" y="318" width="180" height="104" rx="8" fill="#f0fdfa" stroke="#0d9488" stroke-width="1.4"/>
<text x="790" y="341" text-anchor="middle" fill="#0f766e" font-size="11" font-weight="700">团队与插件</text>
<text x="718" y="362" fill="#0f766e" font-size="9">s06 subagent</text>
<text x="718" y="377" fill="#0f766e" font-size="9">s15-s16 team protocols</text>
<text x="718" y="392" fill="#0f766e" font-size="9">s17 worktree isolation</text>
<text x="718" y="407" fill="#0f766e" font-size="9">s18 MCP tools</text>
<text x="718" y="377" fill="#0f766e" font-size="9">s15 teams + task protocols</text>
<text x="718" y="392" fill="#0f766e" font-size="9">s15 task-bound worktrees</text>
<text x="718" y="407" fill="#0f766e" font-size="9">s16 MCP tools</text>
<path d="M 790 318 L 790 188" fill="none" stroke="#0d9488" stroke-width="1.3" marker-end="url(#arrow-green)" stroke-dasharray="5,3"/>
<!-- Tool pool -->
@@ -100,6 +100,6 @@
<text x="95" y="548" fill="#334155" font-size="9">durable work: create/list/get/claim/complete_task · schedule/list/cancel_cron</text>
<text x="510" y="512" fill="#334155" font-size="9">team: spawn_teammate · send_message · typed protocols</text>
<text x="510" y="530" fill="#334155" font-size="9">protocol: request_shutdown · request_plan · review_plan</text>
<text x="510" y="548" fill="#334155" font-size="9">isolation/plugin: create/remove/keep_worktree · connect_mcp</text>
<text x="510" y="548" fill="#334155" font-size="9">workdir/plugin: create/remove_worktree · connect_mcp</text>
<path d="M 850 518 L 890 518 L 890 152 L 850 152" fill="none" stroke="#475569" stroke-width="1.2" marker-end="url(#arrow)" stroke-dasharray="4,4"/>
</svg>

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@@ -1,103 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 450" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#b45309"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#b45309"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#16a34a"/>
</marker>
</defs>
<rect width="760" height="450" fill="#fafbfc" rx="8"/>
<!-- 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">Worktree Isolation — Git Worktree + Task-Directory Binding + Event Log</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s16 Preserved</text>
<rect x="160" y="56" width="12" height="10" rx="2" fill="#fffbeb" stroke="#b45309" stroke-width="1"/>
<text x="178" y="66" fill="#b45309" font-size="10" font-weight="600">s17 New</text>
<!-- ===== Row 1: Lead Loop (s16 preserved) ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
<line x1="90" y1="110" x2="104" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="107" y="90" width="70" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="142" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<line x1="177" y1="110" x2="191" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="194" y="86" width="80" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="234" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt</text>
<line x1="274" y1="110" x2="288" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="291" y="86" width="70" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="326" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM</text>
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="76" width="356" height="70" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (s16 + s17)</text>
<text x="394" y="110" fill="#2563eb" font-size="8">bash · read · write · task(4) · send · inbox</text>
<text x="394" y="123" fill="#7c3aed" font-size="8" font-weight="700">request_shutdown · request_plan · review_plan</text>
<text x="394" y="136" fill="#b45309" font-size="8" font-weight="700">★ create_worktree · remove_worktree · keep_worktree</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- ===== Row 2: Worktree Topology (s17 new) ===== -->
<rect x="30" y="172" width="700" height="215" rx="8" fill="#fffbeb" stroke="#b45309" stroke-width="2"/>
<text x="380" y="194" fill="#78350f" font-size="11" font-weight="700" text-anchor="middle">Worktree Isolation (s17 new: each task gets its own directory + branch)</text>
<!-- Main repo box -->
<rect x="230" y="208" width="300" height="36" rx="6" fill="#fff" stroke="#b45309" stroke-width="1.5"/>
<text x="380" y="231" fill="#78350f" font-size="10" font-weight="600" text-anchor="middle">Main repo (.tasks/ + .worktrees/ + .mailboxes/)</text>
<!-- Arrow: Main repo → Worktree 1 (Alice) -->
<line x1="310" y1="244" x2="178" y2="272" stroke="#b45309" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<text x="200" y="262" fill="#b45309" font-size="7" font-weight="600" transform="rotate(-12 200 262)">create + bind</text>
<!-- Arrow: Main repo → Worktree 2 (Bob) -->
<line x1="450" y1="244" x2="582" y2="272" stroke="#b45309" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<text x="530" y="252" fill="#b45309" font-size="7" font-weight="600" transform="rotate(12 530 252)">create + bind</text>
<!-- Worktree 1: Alice -->
<rect x="50" y="275" width="255" height="78" rx="6" fill="#fff" stroke="#16a34a" stroke-width="1.5"/>
<text x="177" y="294" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Alice: .worktrees/auth/</text>
<text x="65" y="310" fill="#374151" font-size="8">branch: wt/auth-refactor</text>
<text x="65" y="324" fill="#374151" font-size="8">Task: Refactor auth module</text>
<text x="65" y="344" fill="#16a34a" font-size="8" font-weight="600">✓ Isolated, no impact on Bob or main repo</text>
<!-- Worktree 2: Bob -->
<rect x="455" y="275" width="255" height="78" rx="6" fill="#fff" stroke="#16a34a" stroke-width="1.5"/>
<text x="582" y="294" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Bob: .worktrees/ui/</text>
<text x="470" y="310" fill="#374151" font-size="8">branch: wt/ui-login</text>
<text x="470" y="324" fill="#374151" font-size="8">Task: Refactor UI login page</text>
<text x="470" y="344" fill="#16a34a" font-size="8" font-weight="600">✓ Isolated, no impact on Alice or main repo</text>
<!-- Event log + Lifecycle -->
<rect x="50" y="362" width="310" height="20" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="205" y="376" fill="#92400e" font-size="8" text-anchor="middle">Event log: .worktrees/events.jsonl → create / remove / keep</text>
<rect x="400" y="362" width="310" height="20" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="555" y="376" fill="#92400e" font-size="8" text-anchor="middle">Cleanup: keep (preserve for review) / remove (delete worktree)</text>
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="400" width="700" height="42" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="412" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="422" fill="#475569" font-size="10">s16: scan_unclaimed_tasks + claim_next_task + task_lock</text>
<rect x="50" y="426" width="12" height="10" rx="2" fill="#fffbeb" stroke="#b45309" stroke-width="1"/>
<text x="70" y="436" fill="#475569" font-size="10">s17: create_worktree + bind_task + remove/keep + events.jsonl</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -1,103 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 450" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#b45309"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#b45309"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#16a34a"/>
</marker>
</defs>
<rect width="760" height="450" fill="#fafbfc" rx="8"/>
<!-- 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="14" font-weight="700" text-anchor="middle">Worktree Isolation — Git Worktree + タスク・ディレクトリ紐付け + イベントログ</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s16 保持</text>
<rect x="130" y="56" width="12" height="10" rx="2" fill="#fffbeb" stroke="#b45309" stroke-width="1"/>
<text x="148" y="66" fill="#b45309" font-size="10" font-weight="600">s17 新規</text>
<!-- ===== Row 1: Lead Loop ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
<line x1="90" y1="110" x2="104" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="107" y="90" width="70" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="142" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<line x1="177" y1="110" x2="191" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="194" y="86" width="80" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="234" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt</text>
<line x1="274" y1="110" x2="288" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="291" y="86" width="70" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="326" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM</text>
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="76" width="356" height="70" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCHs16 + s17</text>
<text x="394" y="110" fill="#2563eb" font-size="8">bash · read · write · task(4) · send · inbox</text>
<text x="394" y="123" fill="#7c3aed" font-size="8" font-weight="700">request_shutdown · request_plan · review_plan</text>
<text x="394" y="136" fill="#b45309" font-size="8" font-weight="700">★ create_worktree · remove_worktree · keep_worktree</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- ===== Row 2: Worktree Topology ===== -->
<rect x="30" y="172" width="700" height="215" rx="8" fill="#fffbeb" stroke="#b45309" stroke-width="2"/>
<text x="380" y="194" fill="#78350f" font-size="11" font-weight="700" text-anchor="middle">Worktree 隔離s17 新規:各タスクに独立ディレクトリ + 独立ブランチ)</text>
<!-- Main repo box -->
<rect x="230" y="208" width="300" height="36" rx="6" fill="#fff" stroke="#b45309" stroke-width="1.5"/>
<text x="380" y="231" fill="#78350f" font-size="10" font-weight="600" text-anchor="middle">メインリポジトリ(.tasks/ + .worktrees/ + .mailboxes/</text>
<!-- Arrow: Main repo → Worktree 1 (Alice) -->
<line x1="310" y1="244" x2="178" y2="272" stroke="#b45309" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<text x="200" y="262" fill="#b45309" font-size="7" font-weight="600" transform="rotate(-12 200 262)">create + bind</text>
<!-- Arrow: Main repo → Worktree 2 (Bob) -->
<line x1="450" y1="244" x2="582" y2="272" stroke="#b45309" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<text x="530" y="252" fill="#b45309" font-size="7" font-weight="600" transform="rotate(12 530 252)">create + bind</text>
<!-- Worktree 1: Alice -->
<rect x="50" y="275" width="255" height="78" rx="6" fill="#fff" stroke="#16a34a" stroke-width="1.5"/>
<text x="177" y="294" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Alice: .worktrees/auth/</text>
<text x="65" y="310" fill="#374151" font-size="8">branch: wt/auth-refactor</text>
<text x="65" y="324" fill="#374151" font-size="8">Task: 認証モジュールのリファクタリング</text>
<text x="65" y="344" fill="#16a34a" font-size="8" font-weight="600">✓ 隔離、Bob とメインリポジトリに影響なし</text>
<!-- Worktree 2: Bob -->
<rect x="455" y="275" width="255" height="78" rx="6" fill="#fff" stroke="#16a34a" stroke-width="1.5"/>
<text x="582" y="294" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Bob: .worktrees/ui/</text>
<text x="470" y="310" fill="#374151" font-size="8">branch: wt/ui-login</text>
<text x="470" y="324" fill="#374151" font-size="8">Task: UI ログインページのリファクタリング</text>
<text x="470" y="344" fill="#16a34a" font-size="8" font-weight="600">✓ 隔離、Alice とメインリポジトリに影響なし</text>
<!-- Event log + Lifecycle -->
<rect x="50" y="362" width="310" height="20" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="205" y="376" fill="#92400e" font-size="8" text-anchor="middle">イベントログ: .worktrees/events.jsonl → create / remove / keep</text>
<rect x="400" y="362" width="310" height="20" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="555" y="376" fill="#92400e" font-size="8" text-anchor="middle">片付け: keepreview 用に保持)/ removeworktree を削除)</text>
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="400" width="700" height="42" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="412" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="422" fill="#475569" font-size="10">s16: scan_unclaimed_tasks + claim_next_task + task_lock</text>
<rect x="50" y="426" width="12" height="10" rx="2" fill="#fffbeb" stroke="#b45309" stroke-width="1"/>
<text x="70" y="436" fill="#475569" font-size="10">s17: create_worktree + bind_task + remove/keep + events.jsonl</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.2 KiB

View File

@@ -1,103 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760 450" font-family="system-ui, -apple-system, sans-serif">
<defs>
<linearGradient id="header" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#1e3a5f"/><stop offset="100%" stop-color="#b45309"/>
</linearGradient>
<marker id="arrow" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#555"/>
</marker>
<marker id="arrow-amber" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#b45309"/>
</marker>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#16a34a"/>
</marker>
</defs>
<rect width="760" height="450" fill="#fafbfc" rx="8"/>
<!-- 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">Worktree Isolation — Git Worktree + 任务-目录绑定 + 事件日志</text>
<!-- Legend -->
<rect x="40" y="56" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="58" y="66" fill="#2563eb" font-size="10" font-weight="600">s16 保留</text>
<rect x="140" y="56" width="12" height="10" rx="2" fill="#fffbeb" stroke="#b45309" stroke-width="1"/>
<text x="158" y="66" fill="#b45309" font-size="10" font-weight="600">s17 新增</text>
<!-- ===== Row 1: Lead Loop (s16 preserved) ===== -->
<rect x="20" y="90" width="70" height="40" rx="8" fill="#eef2ff" stroke="#4f46e5" stroke-width="1.5"/>
<text x="55" y="114" fill="#4f46e5" font-size="8" font-weight="600" text-anchor="middle">turn</text>
<line x1="90" y1="110" x2="104" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="107" y="90" width="70" height="40" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="142" y="114" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">messages</text>
<line x1="177" y1="110" x2="191" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="194" y="86" width="80" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="234" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">prompt</text>
<line x1="274" y1="110" x2="288" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="291" y="86" width="70" height="48" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="326" y="114" fill="#1e3a5f" font-size="9" font-weight="600" text-anchor="middle">LLM</text>
<line x1="361" y1="110" x2="375" y2="110" stroke="#555" stroke-width="1.5" marker-end="url(#arrow)"/>
<rect x="378" y="76" width="356" height="70" rx="8" fill="#f0f4ff" stroke="#2563eb" stroke-width="1.5"/>
<text x="556" y="94" fill="#1e3a5f" font-size="10" font-weight="600" text-anchor="middle">TOOL DISPATCH (s16 + s17)</text>
<text x="394" y="110" fill="#2563eb" font-size="8">bash · read · write · task(4) · send · inbox</text>
<text x="394" y="123" fill="#7c3aed" font-size="8" font-weight="700">request_shutdown · request_plan · review_plan</text>
<text x="394" y="136" fill="#b45309" font-size="8" font-weight="700">★ create_worktree · remove_worktree · keep_worktree</text>
<!-- Loop back -->
<path d="M 734 110 L 748 110 L 748 150 L 55 150 L 55 130" fill="none" stroke="#94a3b8" stroke-width="1" marker-end="url(#arrow)" stroke-dasharray="5,4"/>
<!-- ===== Row 2: Worktree Topology (s17 new) ===== -->
<rect x="30" y="172" width="700" height="215" rx="8" fill="#fffbeb" stroke="#b45309" stroke-width="2"/>
<text x="380" y="194" fill="#78350f" font-size="11" font-weight="700" text-anchor="middle">Worktree 隔离s17 新增:每个任务独立目录 + 独立分支)</text>
<!-- Main repo box -->
<rect x="230" y="208" width="300" height="36" rx="6" fill="#fff" stroke="#b45309" stroke-width="1.5"/>
<text x="380" y="231" fill="#78350f" font-size="10" font-weight="600" text-anchor="middle">主仓库 (.tasks/ + .worktrees/ + .mailboxes/)</text>
<!-- Arrow: Main repo → Worktree 1 (Alice) -->
<line x1="310" y1="244" x2="178" y2="272" stroke="#b45309" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<text x="200" y="262" fill="#b45309" font-size="7" font-weight="600" transform="rotate(-12 200 262)">create + bind</text>
<!-- Arrow: Main repo → Worktree 2 (Bob) -->
<line x1="450" y1="244" x2="582" y2="272" stroke="#b45309" stroke-width="1.5" marker-end="url(#arrow-amber)"/>
<text x="530" y="252" fill="#b45309" font-size="7" font-weight="600" transform="rotate(12 530 252)">create + bind</text>
<!-- Worktree 1: Alice -->
<rect x="50" y="275" width="255" height="78" rx="6" fill="#fff" stroke="#16a34a" stroke-width="1.5"/>
<text x="177" y="294" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Alice: .worktrees/auth/</text>
<text x="65" y="310" fill="#374151" font-size="8">branch: wt/auth-refactor</text>
<text x="65" y="324" fill="#374151" font-size="8">Task: 重构认证模块</text>
<text x="65" y="344" fill="#16a34a" font-size="8" font-weight="600">✓ 隔离,不影响 Bob 和主仓库</text>
<!-- Worktree 2: Bob -->
<rect x="455" y="275" width="255" height="78" rx="6" fill="#fff" stroke="#16a34a" stroke-width="1.5"/>
<text x="582" y="294" fill="#166534" font-size="10" font-weight="700" text-anchor="middle">Bob: .worktrees/ui/</text>
<text x="470" y="310" fill="#374151" font-size="8">branch: wt/ui-login</text>
<text x="470" y="324" fill="#374151" font-size="8">Task: 重构 UI 登录页</text>
<text x="470" y="344" fill="#16a34a" font-size="8" font-weight="600">✓ 隔离,不影响 Alice 和主仓库</text>
<!-- Event log + Lifecycle -->
<rect x="50" y="362" width="310" height="20" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="205" y="376" fill="#92400e" font-size="8" text-anchor="middle">事件日志: .worktrees/events.jsonl → create / remove / keep</text>
<rect x="400" y="362" width="310" height="20" rx="4" fill="#fef3c7" stroke="#d97706" stroke-width="1"/>
<text x="555" y="376" fill="#92400e" font-size="8" text-anchor="middle">收尾: keep (保留分支 review) / remove (删除 worktree)</text>
<!-- ===== Row 3: Bottom notes ===== -->
<rect x="30" y="400" width="700" height="42" rx="6" fill="#f8fafc" stroke="#e2e8f0" stroke-width="1"/>
<rect x="50" y="412" width="12" height="10" rx="2" fill="#f0f4ff" stroke="#2563eb" stroke-width="1"/>
<text x="70" y="422" fill="#475569" font-size="10">s16: scan_unclaimed_tasks + claim_next_task + task_lock</text>
<rect x="50" y="426" width="12" height="10" rx="2" fill="#fffbeb" stroke="#b45309" stroke-width="1"/>
<text x="70" y="436" fill="#475569" font-size="10">s17: create_worktree + bind_task + remove/keep + events.jsonl</text>
</svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,115 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 640" font-family="system-ui, -apple-system, sans-serif" role="img" aria-labelledby="title description">
<title id="title">Workflow Runtime execution flow</title>
<desc id="description">One Workflow tool call executes a complete workflow run. Lifecycle and progress events remain inside the call, which returns one tool result containing launch metadata, the result, and task state.</desc>
<defs>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#22c55e"/>
</marker>
<marker id="arrow-gray" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#888888"/>
</marker>
</defs>
<rect width="960" height="640" rx="8" fill="#ffffff"/>
<text x="480" y="30" text-anchor="middle" fill="#1a1a1a" font-size="19" font-weight="700">Workflow Runtime — one Workflow call executes one complete run</text>
<text x="480" y="51" text-anchor="middle" fill="#888888" font-size="12">lifecycle and progress events are emitted during the call; one final tool_result returns to messages[]</text>
<!-- Main session loop -->
<rect x="20" y="68" width="920" height="132" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="40" y="88" fill="#1a1a1a" font-size="13" font-weight="700">Main session loop</text>
<path d="M 818 118 L 818 100 L 110 100 L 110 118" fill="none" stroke="#22c55e" stroke-width="1.5" stroke-dasharray="6,3" marker-end="url(#arrow-green)"/>
<text x="464" y="95" text-anchor="middle" fill="#22c55e" font-size="10" font-weight="600">append one tool_result to messages[]</text>
<rect x="42" y="118" width="136" height="54" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="110" y="141" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700" font-family="monospace">messages[]</text>
<text x="110" y="159" text-anchor="middle" fill="#888888" font-size="9">message history</text>
<line x1="178" y1="145" x2="218" y2="145" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="220" y="118" width="92" height="54" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="266" y="141" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">LLM</text>
<text x="266" y="159" text-anchor="middle" fill="#888888" font-size="9">tool_use?</text>
<line x1="312" y1="145" x2="352" y2="145" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="354" y="118" width="220" height="54" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="464" y="140" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700" font-family="monospace">Workflow({script, args})</text>
<text x="464" y="159" text-anchor="middle" fill="#888888" font-size="8.5" font-family="monospace">resume_from_run_id?</text>
<rect x="715" y="110" width="205" height="70" rx="6" fill="#fafafa" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="818" y="134" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">tool_result</text>
<text x="818" y="153" text-anchor="middle" fill="#22c55e" font-size="9.5" font-weight="600" font-family="monospace">launched + result + task</text>
<text x="818" y="168" text-anchor="middle" fill="#888888" font-size="8.5">one return after the run</text>
<!-- Complete WorkflowTool.call lifecycle -->
<rect x="20" y="232" width="920" height="350" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="40" y="253" fill="#1a1a1a" font-size="13" font-weight="700">WorkflowTool.call — complete workflow task lifecycle</text>
<rect x="45" y="272" width="180" height="76" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="135" y="294" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700" font-family="monospace">WorkflowTool.call</text>
<text x="135" y="314" text-anchor="middle" fill="#888888" font-size="9">validate meta · permission</text>
<text x="135" y="331" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">runId · taskId · envelope</text>
<line x1="225" y1="310" x2="263" y2="310" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="265" y="272" width="180" height="76" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="355" y="294" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Emit lifecycle</text>
<text x="355" y="314" text-anchor="middle" fill="#22c55e" font-size="9.5" font-weight="600" font-family="monospace">async_launched</text>
<text x="355" y="331" text-anchor="middle" fill="#888888" font-size="9.5" font-family="monospace">task_started</text>
<line x1="445" y1="310" x2="483" y2="310" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="485" y="272" width="180" height="76" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="575" y="294" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Execute script</text>
<text x="575" y="314" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">phase · agent()</text>
<text x="575" y="331" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">parallel · pipeline</text>
<line x1="665" y1="310" x2="703" y2="310" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="705" y="272" width="210" height="76" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="810" y="294" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Finalize task</text>
<text x="810" y="314" text-anchor="middle" fill="#888888" font-size="9">write output · save last run</text>
<text x="810" y="331" text-anchor="middle" fill="#22c55e" font-size="9.5" font-weight="600" font-family="monospace">task_notification</text>
<!-- Script execution details -->
<line x1="575" y1="348" x2="575" y2="388" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="588" y="371" fill="#22c55e" font-size="9" font-weight="600">agent()</text>
<rect x="475" y="390" width="190" height="64" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="570" y="413" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Subagents × N</text>
<text x="570" y="432" text-anchor="middle" fill="#888888" font-size="9">schema validation · token budget</text>
<text x="570" y="447" text-anchor="middle" fill="#888888" font-size="8.5">parallel work, structured results</text>
<line x1="665" y1="422" x2="703" y2="422" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="684" y="414" text-anchor="middle" fill="#22c55e" font-size="8.5" font-weight="600">record</text>
<rect x="705" y="390" width="190" height="64" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="800" y="413" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Journal</text>
<text x="800" y="432" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">semantic key → result</text>
<text x="800" y="447" text-anchor="middle" fill="#888888" font-size="8.5">resume returns cached calls</text>
<path d="M 705 441 L 680 441 L 680 372 L 635 372 L 635 348" fill="none" stroke="#888888" stroke-width="1.5" stroke-dasharray="5,3" marker-end="url(#arrow-gray)"/>
<text x="670" y="365" text-anchor="end" fill="#888888" font-size="8.5">cached</text>
<!-- Events remain within the call; the call returns once -->
<rect x="45" y="490" width="470" height="58" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="280" y="512" text-anchor="middle" fill="#1a1a1a" font-size="10.5" font-weight="700">Lifecycle + progress events emitted during the call</text>
<text x="280" y="532" text-anchor="middle" fill="#888888" font-size="8.8" font-family="monospace">async_launched · task_started · workflow_phase / agent / log · task_notification</text>
<path d="M 810 348 L 810 472 L 738 472 L 738 488" fill="none" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="560" y="490" width="355" height="58" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="738" y="513" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700" font-family="monospace">return { launched, result, task }</text>
<text x="738" y="532" text-anchor="middle" fill="#888888" font-size="9">after task_notification</text>
<!-- Cross-lane call and return -->
<path d="M 464 172 L 464 215 L 135 215 L 135 270" fill="none" stroke="#22c55e" stroke-width="1.5" stroke-dasharray="6,3" marker-end="url(#arrow-green)"/>
<text x="250" y="209" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">execute complete run</text>
<path d="M 915 519 L 934 519 L 934 211 L 818 211 L 818 180" fill="none" stroke="#22c55e" stroke-width="1.8" marker-end="url(#arrow-green)"/>
<text x="928" y="380" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600" transform="rotate(-90 928 380)">return once</text>
<text x="480" y="616" text-anchor="middle" fill="#888888" font-size="10">One return boundary: async_launched is a lifecycle event; launched + result + task return together.</text>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -1,120 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 580" font-family="system-ui, -apple-system, sans-serif">
<defs>
<marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#22c55e"/>
</marker>
<marker id="arrow-gray" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#888888"/>
</marker>
</defs>
<!-- Background -->
<rect width="960" height="580" rx="8" fill="#ffffff"/>
<!-- Title -->
<text x="480" y="30" text-anchor="middle" fill="#1a1a1a" font-size="19" font-weight="700">Workflow Runtime — one tool_use launches a background orchestration</text>
<text x="480" y="50" text-anchor="middle" fill="#888888" font-size="12">the main loop calls Workflow like any tool; a deterministic runtime fans out subagents in the background and can resume</text>
<!-- ===== Lane 1: Main session loop (canonical agent loop) ===== -->
<rect x="20" y="66" width="920" height="160" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="40" y="86" fill="#1a1a1a" font-size="13" font-weight="700">Main session loop</text>
<!-- loop-back over the top: back into messages[] -->
<path d="M 828 130 L 828 102 L 99 102 L 99 130" fill="none" stroke="#22c55e" stroke-width="1.5" stroke-dasharray="6,3" marker-end="url(#arrow-green)"/>
<text x="463" y="97" text-anchor="middle" fill="#22c55e" font-size="10" font-weight="600">append tool_result / notification -&gt; messages[] (loop continues)</text>
<circle cx="828" cy="130" r="3" fill="#22c55e"/>
<circle cx="99" cy="130" r="3" fill="#22c55e"/>
<!-- messages[] -->
<rect x="40" y="130" width="118" height="52" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="99" y="152" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700" font-family="monospace">messages[]</text>
<text x="99" y="169" text-anchor="middle" fill="#888888" font-size="9">message history</text>
<line x1="158" y1="156" x2="176" y2="156" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<!-- LLM -->
<rect x="178" y="130" width="86" height="52" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="221" y="152" text-anchor="middle" fill="#1a1a1a" font-size="13" font-weight="700">LLM</text>
<text x="221" y="169" text-anchor="middle" fill="#888888" font-size="9">tool_use?</text>
<line x1="264" y1="156" x2="282" y2="156" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<!-- Workflow tool_use -->
<rect x="284" y="130" width="196" height="52" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="382" y="151" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700" font-family="monospace">Workflow({script, args})</text>
<text x="382" y="169" text-anchor="middle" fill="#888888" font-size="8.5" font-family="monospace">(or name | script) · resume_from_run_id</text>
<line x1="480" y1="156" x2="518" y2="156" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<!-- tool_result -->
<rect x="520" y="130" width="156" height="52" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="598" y="151" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">tool_result</text>
<text x="598" y="169" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">async_launched</text>
<!-- later (dashed gap) -->
<line x1="676" y1="156" x2="734" y2="156" stroke="#888888" stroke-width="1.5" stroke-dasharray="5,3" marker-end="url(#arrow-gray)"/>
<text x="705" y="148" text-anchor="middle" fill="#888888" font-size="8">later</text>
<!-- task_notification -->
<rect x="738" y="130" width="180" height="52" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="828" y="151" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">task_notification</text>
<text x="828" y="169" text-anchor="middle" fill="#888888" font-size="9">completed · final report</text>
<!-- ===== Lane 2: Background workflow runtime ===== -->
<rect x="20" y="270" width="920" height="244" rx="8" fill="#ffffff" stroke="#d0d0d0" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="40" y="290" fill="#1a1a1a" font-size="13" font-weight="700">Background workflow runtime — local_workflow</text>
<!-- spine: WorkflowTool.call -> LocalWorkflowTask -> Script VM -->
<rect x="44" y="316" width="158" height="66" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="123" y="338" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700" font-family="monospace">WorkflowTool.call</text>
<text x="123" y="355" text-anchor="middle" fill="#888888" font-size="9">validate meta · permission</text>
<text x="123" y="370" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">runId · taskId</text>
<line x1="202" y1="349" x2="220" y2="349" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="222" y="316" width="158" height="66" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="301" y="338" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">LocalWorkflowTask</text>
<text x="301" y="355" text-anchor="middle" fill="#888888" font-size="9">status · usage</text>
<text x="301" y="370" text-anchor="middle" fill="#888888" font-size="9">progress events</text>
<line x1="380" y1="349" x2="398" y2="349" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<rect x="400" y="316" width="200" height="66" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5" stroke-dasharray="6,3"/>
<text x="500" y="338" text-anchor="middle" fill="#1a1a1a" font-size="12" font-weight="700">Script VM — runs the script</text>
<text x="500" y="356" text-anchor="middle" fill="#888888" font-size="9.5" font-family="monospace">phase · agent()</text>
<text x="500" y="371" text-anchor="middle" fill="#888888" font-size="9.5" font-family="monospace">parallel · pipeline</text>
<!-- agent() cycle: VM -> Subagents -> Journal -> (resume) -> VM -->
<!-- Subagents (× N, fan-out: stacked) -->
<rect x="666" y="308" width="170" height="58" rx="6" fill="#f3f4f6" stroke="#d0d0d0" stroke-width="1.2"/>
<rect x="662" y="312" width="170" height="58" rx="6" fill="#ffffff" stroke="#1a1a1a" stroke-width="1.5"/>
<text x="747" y="334" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Subagents × N</text>
<text x="747" y="350" text-anchor="middle" fill="#888888" font-size="9">isolated ctx</text>
<text x="747" y="363" text-anchor="middle" fill="#888888" font-size="9">schema output</text>
<!-- Journal -->
<rect x="662" y="420" width="170" height="58" rx="6" fill="#fafafa" stroke="#d0d0d0" stroke-width="1.5"/>
<text x="747" y="442" text-anchor="middle" fill="#1a1a1a" font-size="11" font-weight="700">Journal</text>
<text x="747" y="458" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">started / result</text>
<text x="747" y="471" text-anchor="middle" fill="#888888" font-size="9" font-family="monospace">per agent()</text>
<!-- VM -> Subagents: agent() spawns -->
<line x1="600" y1="341" x2="660" y2="341" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="630" y="333" text-anchor="middle" fill="#22c55e" font-size="9" font-weight="600">agent()</text>
<text x="630" y="356" text-anchor="middle" fill="#888888" font-size="8">spawns</text>
<!-- Subagents -> Journal: record -->
<line x1="747" y1="370" x2="747" y2="418" stroke="#22c55e" stroke-width="2" marker-end="url(#arrow-green)"/>
<text x="757" y="398" fill="#22c55e" font-size="9" font-weight="600">record</text>
<!-- Journal -> Script VM: resume cached -->
<path d="M 662 449 L 500 449 L 500 382" fill="none" stroke="#888888" stroke-width="1.5" stroke-dasharray="5,3" marker-end="url(#arrow-gray)"/>
<text x="556" y="443" text-anchor="middle" fill="#888888" font-size="9" font-weight="600">resume_from_run_id -&gt; cached agent()</text>
<!-- ===== Cross arrows between lanes ===== -->
<!-- launch (outer Workflow tool_use -> inner runtime), left side -->
<path d="M 382 182 L 382 248 L 123 248 L 123 316" fill="none" stroke="#22c55e" stroke-width="1.5" stroke-dasharray="6,3" marker-end="url(#arrow-green)"/>
<text x="152" y="242" fill="#22c55e" font-size="9" font-weight="600">launch (async)</text>
<!-- progress / notification (inner task -> outer notification), routed just below launch -->
<path d="M 301 316 L 301 256 L 828 256 L 828 182" fill="none" stroke="#888888" stroke-width="1.5" stroke-dasharray="5,3" marker-end="url(#arrow-gray)"/>
<text x="600" y="250" text-anchor="middle" fill="#888888" font-size="9" font-weight="600">task_progress: workflow_phase · workflow_agent · workflow_log</text>
<!-- ===== Bottom note ===== -->
<text x="480" y="548" text-anchor="middle" fill="#888888" font-size="10">The runtime result stays on the task (scriptPath · transcripts · journal · output) — only the launch + final notification re-enter messages[].</text>
</svg>

Before

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -25,8 +25,6 @@ import s16Annotations from "@/data/annotations/s16.json";
import s17Annotations from "@/data/annotations/s17.json";
import s18Annotations from "@/data/annotations/s18.json";
import s19Annotations from "@/data/annotations/s19.json";
import s20Annotations from "@/data/annotations/s20.json";
import s21Annotations from "@/data/annotations/s21.json";
interface Decision {
id: string;
@@ -62,8 +60,6 @@ const ANNOTATIONS: Record<string, AnnotationFile> = {
s17: s17Annotations as AnnotationFile,
s18: s18Annotations as AnnotationFile,
s19: s19Annotations as AnnotationFile,
s20: s20Annotations as AnnotationFile,
s21: s21Annotations as AnnotationFile,
};
interface DesignDecisionsProps {

View File

@@ -28,8 +28,6 @@ const scenarioModules: Record<string, () => Promise<{ default: Scenario }>> = {
s17: () => import("@/data/scenarios/s17.json") as Promise<{ default: Scenario }>,
s18: () => import("@/data/scenarios/s18.json") as Promise<{ default: Scenario }>,
s19: () => import("@/data/scenarios/s19.json") as Promise<{ default: Scenario }>,
s20: () => import("@/data/scenarios/s20.json") as Promise<{ default: Scenario }>,
s21: () => import("@/data/scenarios/s21.json") as Promise<{ default: Scenario }>,
};
interface AgentLoopSimulatorProps {

View File

@@ -21,11 +21,9 @@ const visualizations: Record<
s12: lazy(() => import("./s07-task-system")),
s13: lazy(() => import("./s08-background-tasks")),
s14: lazy(() => import("./s14-cron-scheduler")),
s15: lazy(() => import("./s10-team-protocols")),
s16: lazy(() => import("./s11-autonomous-agents")),
s17: lazy(() => import("./s12-worktree-task-isolation")),
s18: lazy(() => import("./s19-mcp-tools")),
s19: lazy(() => import("./s20-comprehensive")),
s15: lazy(() => import("./s15-team-runtime")),
s16: lazy(() => import("./s16-mcp-tools")),
s17: lazy(() => import("./s17-integrated-harness")),
};
export function SessionVisualization({ version }: { version: string }) {

View File

@@ -1,238 +0,0 @@
"use client";
import { AnimatePresence, motion } from "framer-motion";
import { Inbox, MessageSquareText, UsersRound } from "lucide-react";
import { StepControls } from "@/components/visualizations/shared/step-controls";
import { useSteppedVisualization } from "@/hooks/useSteppedVisualization";
import { cn } from "@/lib/utils";
type AgentId = "lead" | "coder" | "reviewer";
interface Mail {
id: string;
from: AgentId;
to: AgentId;
subject: string;
body: string;
appearsAt: number;
consumedAt?: number;
}
const AGENTS: { id: AgentId; label: string; role: string }[] = [
{ id: "lead", label: "Lead", role: "splits work and reads results" },
{ id: "coder", label: "Coder", role: "implements one slice" },
{ id: "reviewer", label: "Reviewer", role: "checks the result" },
];
const MAIL: Mail[] = [
{
id: "assign",
from: "lead",
to: "coder",
subject: "Build login UI",
body: "Please implement the login form and report back.",
appearsAt: 1,
consumedAt: 2,
},
{
id: "result",
from: "coder",
to: "reviewer",
subject: "Login UI done",
body: "Files changed, ready for review.",
appearsAt: 4,
consumedAt: 5,
},
{
id: "feedback",
from: "reviewer",
to: "lead",
subject: "Review passed",
body: "No blockers. One small polish note.",
appearsAt: 5,
},
];
const STEPS = [
{
title: "A Team Is Mailboxes",
desc: "Each agent has its own inbox file. The team does not need shared memory to coordinate.",
},
{
title: "Lead Drops a Card",
desc: "Assigning work means appending a message to the coder's inbox.",
},
{
title: "Coder Reads Before Thinking",
desc: "Before its next model call, the coder drains its inbox and turns messages into context.",
},
{
title: "Coder Works Alone",
desc: "The coder now runs its own loop. The lead does not have to hold the full context.",
},
{
title: "Result Becomes Mail",
desc: "The coder sends a result card to the reviewer through the same mailbox mechanism.",
},
{
title: "Reviewer Sends Feedback",
desc: "Review feedback is just another card. The lead reads it from its inbox.",
},
{
title: "Files Are the Coordination Layer",
desc: "The whole team is inspectable as append-only inbox files: lead.jsonl, coder.jsonl, reviewer.jsonl.",
},
] as const;
function visibleMail(agent: AgentId, step: number) {
return MAIL.filter((mail) => mail.to === agent && mail.appearsAt <= step && (mail.consumedAt === undefined || step < mail.consumedAt));
}
function agentState(agent: AgentId, step: number): "waiting" | "reading" | "working" | "reviewing" | "done" {
if (agent === "lead" && step === 1) return "working";
if (agent === "coder" && step === 2) return "reading";
if (agent === "coder" && (step === 3 || step === 4)) return "working";
if (agent === "reviewer" && step === 5) return "reviewing";
if (agent === "lead" && step >= 5) return "reading";
if (step === 6) return "done";
return "waiting";
}
function stateClass(state: ReturnType<typeof agentState>) {
if (state === "working") return "border-blue-300 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/30";
if (state === "reading" || state === "reviewing") return "border-amber-300 bg-amber-50 dark:border-amber-800 dark:bg-amber-950/30";
if (state === "done") return "border-emerald-300 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950/30";
return "border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900";
}
function MailCard({ mail }: { mail: Mail }) {
return (
<motion.div
layout
initial={{ opacity: 0, y: 8, scale: 0.98 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -6, scale: 0.98 }}
transition={{ duration: 0.22 }}
className="rounded-md border border-amber-200 bg-amber-50 p-3 text-amber-900 shadow-sm dark:border-amber-900 dark:bg-amber-950/40 dark:text-amber-100"
>
<div className="mb-1 flex items-center justify-between gap-2">
<span className="font-mono text-[11px] font-semibold">{mail.from} -&gt; {mail.to}</span>
<MessageSquareText size={14} />
</div>
<div className="text-sm font-semibold leading-snug">{mail.subject}</div>
<div className="mt-1 text-xs leading-relaxed opacity-85">{mail.body}</div>
</motion.div>
);
}
function AgentPanel({ agent, step }: { agent: (typeof AGENTS)[number]; step: number }) {
const state = agentState(agent.id, step);
const inbox = visibleMail(agent.id, step);
return (
<div className={cn("rounded-lg border p-3 transition-colors", stateClass(state))}>
<div className="mb-3 flex items-start justify-between gap-2">
<div>
<div className="text-base font-bold text-zinc-900 dark:text-zinc-100">{agent.label}</div>
<div className="text-xs leading-relaxed text-zinc-500 dark:text-zinc-400">{agent.role}</div>
</div>
<span className="rounded-md bg-white px-2 py-1 text-[11px] font-semibold capitalize text-zinc-600 shadow-sm dark:bg-zinc-900 dark:text-zinc-300">
{state}
</span>
</div>
<div className="rounded-md border border-zinc-200 bg-white p-3 dark:border-zinc-700 dark:bg-zinc-900">
<div className="mb-2 flex items-center gap-2 text-sm font-semibold text-zinc-800 dark:text-zinc-100">
<Inbox size={15} />
{agent.id}.jsonl
</div>
<div className="min-h-[118px] space-y-2">
<AnimatePresence mode="popLayout">
{inbox.length > 0 ? (
inbox.map((mail) => <MailCard key={mail.id} mail={mail} />)
) : (
<motion.div
key="empty"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="rounded-md border border-dashed border-zinc-300 px-3 py-8 text-center text-xs text-zinc-500 dark:border-zinc-700 dark:text-zinc-400"
>
inbox empty
</motion.div>
)}
</AnimatePresence>
</div>
</div>
</div>
);
}
function ActivityLog({ step }: { step: number }) {
const items = [
"team config creates lead, coder, reviewer",
"lead appends task card to coder.jsonl",
"coder drains inbox before model call",
"coder works in its own loop",
"coder appends result to reviewer.jsonl",
"reviewer appends feedback to lead.jsonl",
"all coordination remains visible on disk",
].slice(0, step + 1);
return (
<div className="rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-800/70">
<div className="mb-2 flex items-center gap-2 text-sm font-semibold text-zinc-800 dark:text-zinc-100">
<UsersRound size={16} />
What changed
</div>
<div className="space-y-2">
{items.map((item) => (
<motion.div
key={item}
initial={{ opacity: 0, x: 8 }}
animate={{ opacity: 1, x: 0 }}
className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-xs text-zinc-700 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-200"
>
{item}
</motion.div>
))}
</div>
</div>
);
}
export default function AgentTeams({ title }: { title?: string }) {
const vis = useSteppedVisualization({ totalSteps: STEPS.length, autoPlayInterval: 2500 });
const step = vis.currentStep;
const current = STEPS[step];
return (
<section className="min-h-[500px] space-y-4">
<h2 className="text-xl font-semibold text-zinc-900 dark:text-zinc-100">
{title || "Agent Team Mailboxes"}
</h2>
<div className="rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900">
<div className="grid gap-3 xl:grid-cols-[1fr_1fr_1fr_0.9fr]">
{AGENTS.map((agent) => (
<AgentPanel key={agent.id} agent={agent} step={step} />
))}
<ActivityLog step={step} />
</div>
<StepControls
className="mt-4"
currentStep={vis.currentStep}
totalSteps={vis.totalSteps}
onPrev={vis.prev}
onNext={vis.next}
onReset={vis.reset}
isPlaying={vis.isPlaying}
onToggleAutoPlay={vis.toggleAutoPlay}
stepTitle={current.title}
stepDescription={current.desc}
/>
</div>
</section>
);
}

View File

@@ -42,7 +42,7 @@ const MEMORY_FILES: MemoryFile[] = [
title: "Verification commands",
filename: "lcc_test_commands.md",
description: "Useful smoke checks for the course website.",
body: "Run npm run build, then browser-check /zh/s09 and /zh/s20.",
body: "Run npm run build, then browser-check /zh/s09 and /zh/s19.",
},
];

View File

@@ -1,363 +0,0 @@
"use client";
import { useState, type ReactNode } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { ArrowRight, CheckCircle2, ClipboardCheck, FileText, LockKeyhole, UserCheck } from "lucide-react";
import { StepControls } from "@/components/visualizations/shared/step-controls";
import { useSteppedVisualization } from "@/hooks/useSteppedVisualization";
import { cn } from "@/lib/utils";
type Protocol = "shutdown" | "plan";
const REQUEST_ID = "req_abc";
const SHUTDOWN_STEPS = [
{
title: "Agree on a Small Form",
desc: "A protocol is just a shared card shape: request type, request_id, and the expected answer.",
},
{
title: "Leader Files a Request",
desc: "The leader writes a shutdown request card instead of force-stopping the teammate.",
},
{
title: "Teammate Chooses",
desc: "The teammate can approve or reject, and the request_id keeps the answer attached to the right request.",
},
{
title: "Clean Exit",
desc: "The approved response returns to the leader, and the teammate exits cleanly.",
},
];
const PLAN_STEPS = [
{
title: "Work Is Locked",
desc: "In plan mode, implementation stays locked until a plan card is approved.",
},
{
title: "Submit the Plan Card",
desc: "The teammate sends a concrete plan with the same request-response shape.",
},
{
title: "Approval Unlocks Action",
desc: "The leader approves the card, then implementation can begin.",
},
];
const PROTOCOL_STATES: Record<Protocol, { label: string; detail: string }[]> = {
shutdown: [
{ label: "drafted", detail: "Lead creates request_id" },
{ label: "pending", detail: "card waits in inbox" },
{ label: "deciding", detail: "teammate replies" },
{ label: "closed", detail: "Lead matches response" },
],
plan: [
{ label: "locked", detail: "work cannot start" },
{ label: "submitted", detail: "plan card is sent" },
{ label: "approved", detail: "implementation unlocks" },
],
};
function ToggleButton({
active,
onClick,
children,
}: {
active: boolean;
onClick: () => void;
children: ReactNode;
}) {
return (
<button
onClick={onClick}
className={cn(
"rounded-md px-3 py-1.5 text-xs font-medium transition-colors active:scale-95",
active
? "bg-blue-500 text-white"
: "bg-zinc-100 text-zinc-600 hover:bg-zinc-200 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700"
)}
>
{children}
</button>
);
}
function StateRail({
states,
currentStep,
}: {
states: { label: string; detail: string }[];
currentStep: number;
}) {
return (
<div className="mb-4 rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-800/70">
<div className="mb-3 flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between">
<div className="text-sm font-semibold text-zinc-800 dark:text-zinc-100">
Protocol state
</div>
<div className="break-words font-mono text-[11px] text-zinc-500 dark:text-zinc-400">
request_id: {REQUEST_ID}
</div>
</div>
<div className="flex flex-col gap-2 sm:flex-row sm:items-stretch">
{states.map((state, index) => {
const active = index === currentStep;
const done = index < currentStep;
return (
<div key={state.label} className="flex min-w-0 flex-1 items-stretch gap-2">
<motion.div
layout
animate={active ? { y: [0, -2, 0] } : { y: 0 }}
transition={{ duration: 0.8, repeat: active ? Infinity : 0 }}
className={cn(
"min-w-0 flex-1 rounded-md border px-3 py-2 transition-colors",
active
? "border-blue-300 bg-blue-50 text-blue-800 dark:border-blue-800 dark:bg-blue-950/35 dark:text-blue-200"
: done
? "border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900 dark:bg-emerald-950/30 dark:text-emerald-200"
: "border-zinc-200 bg-white text-zinc-500 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-400"
)}
>
<div className="break-words text-sm font-semibold">{state.label}</div>
<div className="mt-1 break-words text-[11px] leading-snug opacity-80">
{state.detail}
</div>
</motion.div>
{index < states.length - 1 && (
<div className="hidden items-center text-zinc-300 dark:text-zinc-600 sm:flex">
<ArrowRight size={15} />
</div>
)}
</div>
);
})}
</div>
</div>
);
}
function Desk({
title,
icon,
active,
children,
}: {
title: string;
icon: ReactNode;
active: boolean;
children: ReactNode;
}) {
return (
<div
className={cn(
"min-h-[260px] rounded-lg border p-3 transition-colors",
active
? "border-blue-300 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/30"
: "border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900"
)}
>
<div className="mb-3 flex min-w-0 items-center gap-2 text-sm font-semibold text-zinc-800 dark:text-zinc-100">
<span
className={cn(
"flex h-7 w-7 items-center justify-center rounded-md",
active
? "bg-blue-500 text-white"
: "bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-300"
)}
>
{icon}
</span>
<span className="min-w-0 break-words">{title}</span>
</div>
{children}
</div>
);
}
function ProtocolCard({
title,
rows,
tone = "blue",
}: {
title: string;
rows: string[];
tone?: "blue" | "amber" | "emerald" | "zinc";
}) {
const toneClass = {
blue: "border-blue-200 bg-blue-50 text-blue-800 dark:border-blue-900 dark:bg-blue-950/40 dark:text-blue-200",
amber: "border-amber-200 bg-amber-50 text-amber-800 dark:border-amber-900 dark:bg-amber-950/40 dark:text-amber-200",
emerald:
"border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900 dark:bg-emerald-950/40 dark:text-emerald-200",
zinc: "border-zinc-200 bg-zinc-50 text-zinc-700 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-200",
}[tone];
return (
<motion.div
layout
initial={{ opacity: 0, y: 10, scale: 0.98 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -8, scale: 0.98 }}
transition={{ duration: 0.25 }}
className={cn("rounded-md border p-3 shadow-sm", toneClass)}
>
<div className="break-words font-mono text-xs font-semibold">{title}</div>
<div className="mt-2 space-y-1 font-mono text-[11px] opacity-85">
{rows.map((row) => (
<div key={row} className="break-words">
{row}
</div>
))}
</div>
</motion.div>
);
}
function EmptyTray({ label }: { label: string }) {
return (
<div className="rounded-md border border-dashed border-zinc-300 px-3 py-5 text-center text-xs text-zinc-500 dark:border-zinc-700 dark:text-zinc-400">
{label}
</div>
);
}
export default function TeamProtocols({ title }: { title?: string }) {
const [protocol, setProtocol] = useState<Protocol>("shutdown");
const steps = protocol === "shutdown" ? SHUTDOWN_STEPS : PLAN_STEPS;
const vis = useSteppedVisualization({ totalSteps: steps.length, autoPlayInterval: 2500 });
const step = vis.currentStep;
const switchProtocol = (value: Protocol) => {
setProtocol(value);
vis.reset();
};
const isPlan = protocol === "plan";
return (
<section className="min-h-[500px] space-y-4">
<h2 className="text-xl font-semibold text-zinc-900 dark:text-zinc-100">
{title || "Team Protocol Cards"}
</h2>
<div className="rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900">
<div className="mb-4 flex justify-center gap-2">
<ToggleButton active={!isPlan} onClick={() => switchProtocol("shutdown")}>
Shutdown
</ToggleButton>
<ToggleButton active={isPlan} onClick={() => switchProtocol("plan")}>
Plan Approval
</ToggleButton>
</div>
<StateRail states={PROTOCOL_STATES[protocol]} currentStep={step} />
<div className="grid gap-3 lg:grid-cols-3">
<Desk
title="Leader desk"
icon={<UserCheck size={15} />}
active={(!isPlan && (step === 1 || step === 3)) || (isPlan && step === 2)}
>
<div className="space-y-3">
<AnimatePresence mode="popLayout">
{!isPlan && step >= 1 && (
<ProtocolCard
key="shutdown-request"
title="shutdown_request"
rows={[`request_id: ${REQUEST_ID}`, "target: teammate", "mode: polite"]}
tone={step >= 3 ? "zinc" : "blue"}
/>
)}
{!isPlan && step >= 3 && (
<ProtocolCard
key="shutdown-response"
title="shutdown_response"
rows={[`request_id: ${REQUEST_ID}`, "approve: true", "status: closed"]}
tone="emerald"
/>
)}
{isPlan && step >= 2 && (
<ProtocolCard
key="plan-approved"
title="plan_approval_response"
rows={[`request_id: ${REQUEST_ID}`, "approve: true", "unlock: implementation"]}
tone="emerald"
/>
)}
</AnimatePresence>
{((!isPlan && step === 0) || (isPlan && step < 2)) && (
<EmptyTray label="waiting for a protocol card" />
)}
</div>
</Desk>
<Desk
title="Shared card shape"
icon={<ClipboardCheck size={15} />}
active={(!isPlan && step === 0) || (isPlan && step === 0)}
>
<div className="space-y-3">
<ProtocolCard
title="protocol fields"
rows={["type", "request_id", "payload", "response"]}
tone="amber"
/>
<div className="rounded-md border border-zinc-200 bg-zinc-50 px-3 py-2 text-xs text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300">
The key idea is correlation, not ceremony.
</div>
{isPlan && (
<div className="flex items-center gap-2 rounded-md border border-zinc-200 bg-white px-3 py-2 text-xs text-zinc-600 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300">
<LockKeyhole size={14} />
implementation locked until approval
</div>
)}
</div>
</Desk>
<Desk
title="Teammate desk"
icon={isPlan ? <FileText size={15} /> : <CheckCircle2 size={15} />}
active={(!isPlan && step === 2) || (isPlan && step === 1)}
>
<div className="space-y-3">
<AnimatePresence mode="popLayout">
{!isPlan && step >= 2 && (
<ProtocolCard
key="teammate-decision"
title="decision card"
rows={[`request_id: ${REQUEST_ID}`, "choice: approve", step >= 3 ? "state: exited" : "state: deciding"]}
tone={step >= 3 ? "emerald" : "amber"}
/>
)}
{isPlan && step >= 1 && (
<ProtocolCard
key="plan-card"
title="exit_plan_mode"
rows={[`request_id: ${REQUEST_ID}`, "1. edit module", "2. run tests", "3. report diff"]}
tone={step >= 2 ? "emerald" : "blue"}
/>
)}
</AnimatePresence>
{((!isPlan && step < 2) || (isPlan && step === 0)) && (
<EmptyTray label={isPlan ? "draft plan not submitted" : "no request received"} />
)}
</div>
</Desk>
</div>
<StepControls
className="mt-4"
currentStep={vis.currentStep}
totalSteps={vis.totalSteps}
onPrev={vis.prev}
onNext={vis.next}
onReset={vis.reset}
isPlaying={vis.isPlaying}
onToggleAutoPlay={vis.toggleAutoPlay}
stepTitle={steps[step].title}
stepDescription={steps[step].desc}
/>
</div>
</section>
);
}

View File

@@ -1,277 +0,0 @@
"use client";
import { AnimatePresence, motion } from "framer-motion";
import { CheckCircle2, ClipboardList, Hourglass, UserRoundCog } from "lucide-react";
import { StepControls } from "@/components/visualizations/shared/step-controls";
import { useSteppedVisualization } from "@/hooks/useSteppedVisualization";
import { cn } from "@/lib/utils";
type AgentPhase = "idle" | "polling" | "claiming" | "working" | "done";
type TaskStatus = "open" | "claimed" | "complete";
interface AgentState {
id: string;
phase: AgentPhase;
timer: number;
task?: string;
}
interface TaskState {
id: string;
title: string;
status: TaskStatus;
owner?: string;
}
const STEPS = [
{
title: "Quiet Agents",
desc: "Autonomous agents start by waiting. The important mental model is a work board, not a central dispatcher.",
},
{
title: "Idle Timer Fills",
desc: "An agent watches its own idle timer. When it waits long enough, it decides to look for work.",
},
{
title: "Read the Board",
desc: "The agent polls the shared task board and looks for an open card.",
},
{
title: "Claim One Card",
desc: "Claiming writes the agent name onto one task, making ownership visible.",
},
{
title: "Work Independently",
desc: "The claimed task moves into the agent workspace. No coordinator has to babysit it.",
},
{
title: "Others Join In",
desc: "A second agent can claim a different card through the same simple habit.",
},
{
title: "Finish and Free Up",
desc: "Completed work goes back to the board as done, and the agent returns to waiting.",
},
{
title: "Self Organization",
desc: "Timers plus visible ownership let a small group organize itself without a manager loop.",
},
] as const;
const TASKS = [
{ id: "T1", title: "Fix auth bug" },
{ id: "T2", title: "Add rate limiter" },
{ id: "T3", title: "Write docs" },
{ id: "T4", title: "Clean tests" },
];
function getAgents(step: number): AgentState[] {
if (step === 0) {
return [
{ id: "A", phase: "idle", timer: 0.1 },
{ id: "B", phase: "idle", timer: 0 },
{ id: "C", phase: "idle", timer: 0 },
];
}
if (step === 1) {
return [
{ id: "A", phase: "idle", timer: 0.85 },
{ id: "B", phase: "idle", timer: 0.25 },
{ id: "C", phase: "idle", timer: 0 },
];
}
if (step === 2) {
return [
{ id: "A", phase: "polling", timer: 1 },
{ id: "B", phase: "idle", timer: 0.25 },
{ id: "C", phase: "idle", timer: 0 },
];
}
if (step === 3) {
return [
{ id: "A", phase: "claiming", timer: 0, task: "T1" },
{ id: "B", phase: "idle", timer: 0.45 },
{ id: "C", phase: "idle", timer: 0.1 },
];
}
if (step === 4) {
return [
{ id: "A", phase: "working", timer: 0, task: "T1" },
{ id: "B", phase: "idle", timer: 0.65 },
{ id: "C", phase: "idle", timer: 0.2 },
];
}
if (step === 5) {
return [
{ id: "A", phase: "working", timer: 0, task: "T1" },
{ id: "B", phase: "claiming", timer: 0, task: "T2" },
{ id: "C", phase: "idle", timer: 0.35 },
];
}
if (step === 6) {
return [
{ id: "A", phase: "done", timer: 0, task: "T1" },
{ id: "B", phase: "working", timer: 0, task: "T2" },
{ id: "C", phase: "idle", timer: 0.6 },
];
}
return [
{ id: "A", phase: "idle", timer: 0.15 },
{ id: "B", phase: "working", timer: 0, task: "T2" },
{ id: "C", phase: "claiming", timer: 0, task: "T3" },
];
}
function getTasks(step: number): TaskState[] {
return TASKS.map((task) => {
if (task.id === "T1" && step >= 6) {
return { ...task, status: "complete", owner: "A" };
}
if (task.id === "T1" && step >= 3) {
return { ...task, status: "claimed", owner: "A" };
}
if (task.id === "T2" && step >= 5) {
return { ...task, status: "claimed", owner: "B" };
}
if (task.id === "T3" && step >= 7) {
return { ...task, status: "claimed", owner: "C" };
}
return { ...task, status: "open" };
});
}
function phaseClass(phase: AgentPhase): string {
if (phase === "working") return "border-emerald-300 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950/30";
if (phase === "claiming" || phase === "polling") return "border-amber-300 bg-amber-50 dark:border-amber-800 dark:bg-amber-950/30";
if (phase === "done") return "border-blue-300 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/30";
return "border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900";
}
function statusClass(status: TaskStatus): string {
if (status === "complete") return "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300";
if (status === "claimed") return "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300";
return "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300";
}
function AgentCard({ agent }: { agent: AgentState }) {
const timerPercent = Math.round(agent.timer * 100);
return (
<motion.div
layout
animate={agent.phase !== "idle" ? { y: [0, -2, 0] } : { y: 0 }}
transition={{ duration: 0.9, repeat: agent.phase !== "idle" ? Infinity : 0 }}
className={cn("rounded-lg border p-3 transition-colors", phaseClass(agent.phase))}
>
<div className="mb-2 flex items-center justify-between gap-2">
<div className="flex items-center gap-2">
<span className="flex h-8 w-8 items-center justify-center rounded-md bg-zinc-900 text-sm font-bold text-white dark:bg-zinc-100 dark:text-zinc-900">
{agent.id}
</span>
<div>
<div className="text-sm font-semibold text-zinc-800 dark:text-zinc-100">Agent {agent.id}</div>
<div className="text-[11px] capitalize text-zinc-500 dark:text-zinc-400">{agent.phase}</div>
</div>
</div>
{agent.phase === "done" ? (
<CheckCircle2 size={18} className="text-emerald-500" />
) : (
<UserRoundCog size={18} className="text-zinc-400" />
)}
</div>
<div className="mb-2 h-2 overflow-hidden rounded-full bg-zinc-100 dark:bg-zinc-800">
<motion.div
className="h-full rounded-full bg-amber-400"
initial={{ width: 0 }}
animate={{ width: `${timerPercent}%` }}
transition={{ duration: 0.35 }}
/>
</div>
<div className="font-mono text-[11px] text-zinc-500 dark:text-zinc-400">
{agent.task ? `task: ${agent.task}` : `idle timer: ${timerPercent}%`}
</div>
</motion.div>
);
}
export default function AutonomousAgents({ title }: { title?: string }) {
const vis = useSteppedVisualization({ totalSteps: STEPS.length, autoPlayInterval: 2500 });
const step = vis.currentStep;
const agents = getAgents(step);
const tasks = getTasks(step);
const current = STEPS[step];
return (
<section className="min-h-[500px] space-y-4">
<h2 className="text-xl font-semibold text-zinc-900 dark:text-zinc-100">
{title || "Autonomous Work Board"}
</h2>
<div className="rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900">
<div className="grid gap-3 lg:grid-cols-[1fr_1.2fr]">
<div className="space-y-3">
<div className="flex items-center gap-2 text-sm font-semibold text-zinc-800 dark:text-zinc-100">
<Hourglass size={16} />
Agents watch their own idle timer
</div>
<div className="grid gap-2 sm:grid-cols-3 lg:grid-cols-1">
{agents.map((agent) => (
<AgentCard key={`${agent.id}-${agent.phase}-${agent.task ?? "none"}-${step}`} agent={agent} />
))}
</div>
</div>
<div className="rounded-lg border border-zinc-200 bg-zinc-50 p-3 dark:border-zinc-700 dark:bg-zinc-800/70">
<div className="mb-3 flex items-center gap-2 text-sm font-semibold text-zinc-800 dark:text-zinc-100">
<ClipboardList size={16} />
Shared task board
</div>
<div className="grid gap-2 sm:grid-cols-2">
<AnimatePresence mode="popLayout">
{tasks.map((task) => (
<motion.div
layout
key={`${task.id}-${task.status}-${task.owner ?? "open"}`}
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.96 }}
transition={{ duration: 0.2 }}
className="rounded-md border border-zinc-200 bg-white p-3 text-xs shadow-sm dark:border-zinc-700 dark:bg-zinc-900"
>
<div className="mb-2 flex items-center justify-between gap-2">
<span className="font-mono font-semibold text-zinc-500 dark:text-zinc-400">{task.id}</span>
<span className={cn("rounded px-1.5 py-0.5 text-[10px] font-semibold", statusClass(task.status))}>
{task.status}
</span>
</div>
<div className="font-medium text-zinc-800 dark:text-zinc-100">{task.title}</div>
<div className="mt-2 font-mono text-[11px] text-zinc-500 dark:text-zinc-400">
owner: {task.owner ?? "-"}
</div>
</motion.div>
))}
</AnimatePresence>
</div>
<div className="mt-3 rounded-md border border-zinc-200 bg-white px-3 py-2 text-xs text-zinc-600 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300">
Nobody assigns tasks directly; agents claim visible open cards when their timers wake them.
</div>
</div>
</div>
<StepControls
className="mt-4"
currentStep={vis.currentStep}
totalSteps={vis.totalSteps}
onPrev={vis.prev}
onNext={vis.next}
onReset={vis.reset}
isPlaying={vis.isPlaying}
onToggleAutoPlay={vis.toggleAutoPlay}
stepTitle={current.title}
stepDescription={current.desc}
/>
</div>
</section>
);
}

View File

@@ -1,278 +0,0 @@
"use client";
import { motion } from "framer-motion";
import { useSteppedVisualization } from "@/hooks/useSteppedVisualization";
import { StepControls } from "@/components/visualizations/shared/step-controls";
type TaskStatus = "pending" | "in_progress" | "completed";
interface TaskRow {
id: number;
subject: string;
status: TaskStatus;
worktree: string;
}
interface WorktreeRow {
name: string;
branch: string;
task: string;
state: "none" | "active" | "kept" | "removed";
}
interface Lane {
name: string;
files: string[];
highlight?: boolean;
}
interface StepState {
title: string;
desc: string;
tasks: TaskRow[];
worktrees: WorktreeRow[];
lanes: Lane[];
op: string;
}
const STEPS: StepState[] = [
{
title: "Single Workspace Pain",
desc: "Two tasks are active, but both edits would hit one directory and collide.",
op: "task_create x2",
tasks: [
{ id: 1, subject: "Auth refactor", status: "in_progress", worktree: "" },
{ id: 2, subject: "UI login polish", status: "in_progress", worktree: "" },
],
worktrees: [],
lanes: [
{ name: "main", files: ["auth/service.py", "ui/Login.tsx"], highlight: true },
{ name: "wt/auth-refactor", files: [] },
{ name: "wt/ui-login", files: [] },
],
},
{
title: "Allocate Lane for Task 1",
desc: "Create a worktree lane and associate it with task 1 for clear ownership.",
op: "worktree_create(name='auth-refactor', task_id=1)",
tasks: [
{ id: 1, subject: "Auth refactor", status: "in_progress", worktree: "auth-refactor" },
{ id: 2, subject: "UI login polish", status: "in_progress", worktree: "" },
],
worktrees: [
{ name: "auth-refactor", branch: "wt/auth-refactor", task: "#1", state: "active" },
],
lanes: [
{ name: "main", files: ["ui/Login.tsx"] },
{ name: "wt/auth-refactor", files: ["auth/service.py"], highlight: true },
{ name: "wt/ui-login", files: [] },
],
},
{
title: "Allocate Lane for Task 2",
desc: "Lane creation and task association can be separate. Here task 2 binds after lane creation.",
op: "worktree_create(name='ui-login')\ntask_bind_worktree(task_id=2, worktree='ui-login')",
tasks: [
{ id: 1, subject: "Auth refactor", status: "in_progress", worktree: "auth-refactor" },
{ id: 2, subject: "UI login polish", status: "in_progress", worktree: "ui-login" },
],
worktrees: [
{ name: "auth-refactor", branch: "wt/auth-refactor", task: "#1", state: "active" },
{ name: "ui-login", branch: "wt/ui-login", task: "#2", state: "active" },
],
lanes: [
{ name: "main", files: [] },
{ name: "wt/auth-refactor", files: ["auth/service.py"] },
{ name: "wt/ui-login", files: ["ui/Login.tsx"], highlight: true },
],
},
{
title: "Run Commands in Isolated Lanes",
desc: "Each command routes by selected lane directory, not by the shared root.",
op: "worktree_run('auth-refactor', 'pytest tests/auth -q')",
tasks: [
{ id: 1, subject: "Auth refactor", status: "in_progress", worktree: "auth-refactor" },
{ id: 2, subject: "UI login polish", status: "in_progress", worktree: "ui-login" },
],
worktrees: [
{ name: "auth-refactor", branch: "wt/auth-refactor", task: "#1", state: "active" },
{ name: "ui-login", branch: "wt/ui-login", task: "#2", state: "active" },
],
lanes: [
{ name: "main", files: [] },
{ name: "wt/auth-refactor", files: ["auth/service.py", "tests/auth/test_login.py"], highlight: true },
{ name: "wt/ui-login", files: ["ui/Login.tsx", "ui/Login.css"] },
],
},
{
title: "Keep One Lane, Close Another",
desc: "Closeout can mix decisions: keep ui-login active for follow-up, remove auth-refactor and complete task 1.",
op: "worktree_keep('ui-login')\nworktree_remove('auth-refactor', complete_task=true)\nworktree_events(limit=10)",
tasks: [
{ id: 1, subject: "Auth refactor", status: "completed", worktree: "" },
{ id: 2, subject: "UI login polish", status: "in_progress", worktree: "ui-login" },
],
worktrees: [
{ name: "auth-refactor", branch: "wt/auth-refactor", task: "#1", state: "removed" },
{ name: "ui-login", branch: "wt/ui-login", task: "#2", state: "kept" },
],
lanes: [
{ name: "main", files: [] },
{ name: "wt/auth-refactor", files: [] },
{ name: "wt/ui-login", files: ["ui/Login.tsx"], highlight: true },
],
},
{
title: "Isolation + Coordination + Events",
desc: "The board tracks shared truth, worktree lanes isolate execution, and events provide auditable side-channel traces.",
op: "task_list + worktree_list + worktree_events",
tasks: [
{ id: 1, subject: "Auth refactor", status: "completed", worktree: "" },
{ id: 2, subject: "UI login polish", status: "in_progress", worktree: "ui-login" },
],
worktrees: [
{ name: "auth-refactor", branch: "wt/auth-refactor", task: "#1", state: "removed" },
{ name: "ui-login", branch: "wt/ui-login", task: "#2", state: "kept" },
],
lanes: [
{ name: "main", files: [] },
{ name: "wt/auth-refactor", files: [] },
{ name: "wt/ui-login", files: ["ui/Login.tsx"], highlight: true },
],
},
];
function statusClass(status: TaskStatus): string {
if (status === "completed") return "bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-300";
if (status === "in_progress") return "bg-amber-100 text-amber-700 dark:bg-amber-900/30 dark:text-amber-300";
return "bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300";
}
function worktreeClass(state: WorktreeRow["state"]): string {
if (state === "active") return "border-emerald-300 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-900/20";
if (state === "kept") return "border-sky-300 bg-sky-50 dark:border-sky-800 dark:bg-sky-900/20";
if (state === "removed") return "border-zinc-200 bg-zinc-100 opacity-70 dark:border-zinc-700 dark:bg-zinc-800";
return "border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900";
}
export default function WorktreeTaskIsolation({ title }: { title?: string }) {
const vis = useSteppedVisualization({ totalSteps: STEPS.length, autoPlayInterval: 2600 });
const step = STEPS[vis.currentStep];
return (
<section className="min-h-[500px] space-y-4">
<h2 className="text-xl font-semibold text-zinc-900 dark:text-zinc-100">
{title || "Worktree Task Isolation"}
</h2>
<div className="rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900">
<div className="mb-3 rounded-md border border-blue-200 bg-blue-50 px-3 py-2 font-mono text-xs text-blue-700 dark:border-blue-900 dark:bg-blue-950/30 dark:text-blue-300">
{step.op}
</div>
<div className="grid gap-3 lg:grid-cols-3">
<div className="rounded-md border border-zinc-200 dark:border-zinc-700">
<div className="border-b border-zinc-200 bg-zinc-50 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300">
Task Board (.tasks)
</div>
<div className="space-y-2 p-2">
{step.tasks.map((task) => (
<motion.div
key={`${task.id}-${task.status}-${task.worktree}`}
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25 }}
className="rounded border border-zinc-200 p-2 text-xs dark:border-zinc-700"
>
<div className="flex items-center justify-between gap-2">
<span className="font-mono text-zinc-500 dark:text-zinc-400">#{task.id}</span>
<span className={`rounded px-1.5 py-0.5 text-[10px] font-semibold ${statusClass(task.status)}`}>
{task.status}
</span>
</div>
<div className="mt-1 font-medium text-zinc-800 dark:text-zinc-100">{task.subject}</div>
<div className="mt-1 font-mono text-[10px] text-zinc-500 dark:text-zinc-400">
worktree: {task.worktree || "-"}
</div>
</motion.div>
))}
</div>
</div>
<div className="rounded-md border border-zinc-200 dark:border-zinc-700">
<div className="border-b border-zinc-200 bg-zinc-50 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300">
Worktree Index (.worktrees/index.json)
</div>
<div className="space-y-2 p-2">
{step.worktrees.length === 0 && (
<div className="rounded border border-dashed border-zinc-300 px-3 py-4 text-center text-xs text-zinc-500 dark:border-zinc-700 dark:text-zinc-400">
no worktrees yet
</div>
)}
{step.worktrees.map((wt) => (
<motion.div
key={`${wt.name}-${wt.state}`}
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25 }}
className={`rounded border p-2 text-xs ${worktreeClass(wt.state)}`}
>
<div className="font-mono text-[11px] font-semibold text-zinc-800 dark:text-zinc-100">{wt.name}</div>
<div className="font-mono text-[10px] text-zinc-500 dark:text-zinc-400">{wt.branch}</div>
<div className="mt-1 text-[10px] text-zinc-600 dark:text-zinc-300">task: {wt.task}</div>
</motion.div>
))}
</div>
</div>
<div className="rounded-md border border-zinc-200 dark:border-zinc-700">
<div className="border-b border-zinc-200 bg-zinc-50 px-3 py-2 text-xs font-semibold uppercase tracking-wide text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300">
Execution Lanes
</div>
<div className="space-y-2 p-2">
{step.lanes.map((lane) => (
<motion.div
key={`${lane.name}-${lane.files.join(",")}`}
initial={{ opacity: 0, x: -4 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.25 }}
className={`rounded border p-2 text-xs ${
lane.highlight
? "border-blue-300 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20"
: "border-zinc-200 bg-white dark:border-zinc-700 dark:bg-zinc-900"
}`}
>
<div className="font-mono text-[11px] font-semibold text-zinc-800 dark:text-zinc-100">{lane.name}</div>
<div className="mt-1 space-y-1 font-mono text-[10px] text-zinc-500 dark:text-zinc-400">
{lane.files.length === 0 ? (
<div>(no changes)</div>
) : (
lane.files.map((f) => <div key={f}>{f}</div>)
)}
</div>
</motion.div>
))}
</div>
</div>
</div>
<div className="mt-4 rounded-md border border-zinc-200 bg-zinc-50 px-3 py-2 text-sm dark:border-zinc-700 dark:bg-zinc-800/60">
<div className="font-medium text-zinc-800 dark:text-zinc-100">{step.title}</div>
<div className="text-zinc-600 dark:text-zinc-300">{step.desc}</div>
</div>
</div>
<StepControls
currentStep={vis.currentStep}
totalSteps={vis.totalSteps}
onPrev={vis.prev}
onNext={vis.next}
onReset={vis.reset}
isPlaying={vis.isPlaying}
onToggleAutoPlay={vis.toggleAutoPlay}
stepTitle={step.title}
stepDescription={step.desc}
/>
</section>
);
}

View File

@@ -0,0 +1,289 @@
"use client";
import { motion } from "framer-motion";
import {
CheckCircle2,
ClipboardList,
GitBranch,
Inbox,
LockKeyhole,
Search,
Terminal,
UsersRound,
} from "lucide-react";
import { StepControls } from "@/components/visualizations/shared/step-controls";
import { useSteppedVisualization } from "@/hooks/useSteppedVisualization";
import { cn } from "@/lib/utils";
const STEPS = [
{
title: "Confirm a Small Team",
desc: "The Lead proposes focused roles and waits for the user before starting persistent teammates.",
event: "user confirmed: backend + tests",
},
{
title: "Deliver a Typed Assignment",
desc: "The runtime writes the assignment to a mailbox and correlates plan approval with a request id.",
event: "plan_response(req_7, approved=true)",
},
{
title: "Idle Teammates Scan the Board",
desc: "A teammate with no direct message looks only for pending, unowned work whose dependencies are complete.",
event: "scan_ready_tasks(backend) -> task_auth",
},
{
title: "Claim Under One Lock",
desc: "Ownership and status change atomically, so another teammate cannot take the same task.",
event: "task_lock: task_auth -> backend",
},
{
title: "Route Tools to the Task Directory",
desc: "The claimed task carries its worktree binding; bash, read, and write derive their cwd from that record.",
event: "cwd -> .worktrees/auth-refactor",
},
{
title: "Return the Result, Keep the Teammate",
desc: "The runtime delivers the result to the Lead and moves the teammate back to IDLE for newly ready work.",
event: "result(auth complete) -> idle_notification",
},
] as const;
const EVENTS = STEPS.map((step) => step.event);
function StateBadge({
label,
tone,
}: {
label: string;
tone: "zinc" | "blue" | "amber" | "emerald";
}) {
const classes = {
zinc: "bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300",
blue: "bg-blue-100 text-blue-700 dark:bg-blue-950/50 dark:text-blue-200",
amber: "bg-amber-100 text-amber-700 dark:bg-amber-950/50 dark:text-amber-200",
emerald:
"bg-emerald-100 text-emerald-700 dark:bg-emerald-950/50 dark:text-emerald-200",
}[tone];
return (
<span className={cn("shrink-0 whitespace-nowrap rounded px-2 py-1 text-[11px] font-semibold", classes)}>
{label}
</span>
);
}
function RuntimePanel({ step }: { step: number }) {
const state =
step === 0 ? "awaiting confirmation" : step === 1 ? "working" : step === 5 ? "idle" : "active";
const tone = step === 0 ? "zinc" : step === 5 ? "emerald" : "blue";
return (
<div className="min-h-[250px] rounded-lg border border-zinc-200 bg-white p-3 dark:border-zinc-700 dark:bg-zinc-900">
<div className="flex items-center justify-between gap-2">
<div className="flex min-w-0 items-center gap-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<UsersRound size={16} className="shrink-0 text-blue-500" />
<span className="break-words">Team runtime</span>
</div>
<StateBadge label={state} tone={tone} />
</div>
<div className="mt-4 grid grid-cols-[88px_minmax(0,1fr)] gap-x-2 gap-y-3 text-xs">
<span className="text-zinc-500 dark:text-zinc-400">Lead</span>
<span className="break-words font-medium text-zinc-800 dark:text-zinc-200">
{step === 0 ? "proposes roles" : step === 5 ? "receives result" : "coordinates"}
</span>
<span className="text-zinc-500 dark:text-zinc-400">Teammate</span>
<span className="break-words font-medium text-zinc-800 dark:text-zinc-200">
backend
</span>
<span className="text-zinc-500 dark:text-zinc-400">Protocol</span>
<span className="break-all font-mono text-zinc-700 dark:text-zinc-300">
{step < 1 ? "-" : "request_id=req_7"}
</span>
</div>
<div className="mt-4 flex min-h-[72px] items-start gap-2 rounded-md border border-blue-200 bg-blue-50 p-3 text-xs text-blue-800 dark:border-blue-900 dark:bg-blue-950/30 dark:text-blue-200">
<Inbox size={15} className="mt-0.5 shrink-0" />
<span className="break-words leading-relaxed">
{step === 0
? "No mailbox is created before confirmation."
: step === 1
? "Assignment and plan approval travel through typed messages."
: step === 5
? "The result wakes the Lead; IDLE is a reusable state."
: "The runtime owns delivery while the teammate works."}
</span>
</div>
</div>
);
}
function TaskPanel({ step }: { step: number }) {
const status = step < 3 ? "pending" : step < 5 ? "in_progress" : "completed";
const owner = step < 3 ? "-" : "backend";
const tone = status === "pending" ? "zinc" : status === "in_progress" ? "amber" : "emerald";
return (
<div className="min-h-[250px] rounded-lg border border-zinc-200 bg-white p-3 dark:border-zinc-700 dark:bg-zinc-900">
<div className="flex items-center justify-between gap-2">
<div className="flex min-w-0 items-center gap-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<ClipboardList size={16} className="shrink-0 text-amber-500" />
<span>Task board</span>
</div>
<StateBadge label={status} tone={tone} />
</div>
<div className="mt-4 rounded-md border border-zinc-200 p-3 dark:border-zinc-700">
<div className="font-mono text-[11px] text-zinc-500 dark:text-zinc-400">
task_auth
</div>
<div className="mt-1 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
Refactor authentication
</div>
<div className="mt-3 grid grid-cols-[76px_minmax(0,1fr)] gap-2 text-xs">
<span className="text-zinc-500 dark:text-zinc-400">owner</span>
<span className="font-mono text-zinc-700 dark:text-zinc-300">{owner}</span>
<span className="text-zinc-500 dark:text-zinc-400">blockedBy</span>
<span className="font-mono text-zinc-700 dark:text-zinc-300">[]</span>
</div>
</div>
<div
className={cn(
"mt-3 flex min-h-[56px] items-center gap-2 rounded-md border px-3 py-2 text-xs",
step === 2 || step === 3
? "border-amber-300 bg-amber-50 text-amber-800 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-200"
: "border-zinc-200 bg-zinc-50 text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300"
)}
>
{step < 3 ? <Search size={15} className="shrink-0" /> : <LockKeyhole size={15} className="shrink-0" />}
<span className="break-words">
{step < 2
? "Waiting for the teammate loop."
: step === 2
? "Ready filter: pending + unowned + dependencies complete."
: "The claim check and update share one lock."}
</span>
</div>
</div>
);
}
function WorkspacePanel({ step }: { step: number }) {
const bound = step >= 4;
return (
<div className="min-h-[250px] rounded-lg border border-zinc-200 bg-white p-3 dark:border-zinc-700 dark:bg-zinc-900">
<div className="flex items-center justify-between gap-2">
<div className="flex min-w-0 items-center gap-2 text-sm font-semibold text-zinc-900 dark:text-zinc-100">
<GitBranch size={16} className="shrink-0 text-emerald-500" />
<span>Task directory</span>
</div>
<StateBadge label={bound ? "bound" : "reserved"} tone={bound ? "emerald" : "zinc"} />
</div>
<div className="mt-4 space-y-2">
<div
className={cn(
"rounded-md border p-3 transition-colors",
!bound
? "border-blue-300 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/30"
: "border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-800"
)}
>
<div className="font-mono text-xs font-semibold text-zinc-800 dark:text-zinc-200">
repository root
</div>
<div className="mt-1 text-[11px] text-zinc-500 dark:text-zinc-400">
coordination state
</div>
</div>
<motion.div
animate={bound ? { y: [0, -2, 0] } : { y: 0 }}
transition={{ duration: 0.8, repeat: bound ? Infinity : 0 }}
className={cn(
"rounded-md border p-3 transition-colors",
bound
? "border-emerald-300 bg-emerald-50 dark:border-emerald-800 dark:bg-emerald-950/30"
: "border-dashed border-zinc-300 bg-white dark:border-zinc-700 dark:bg-zinc-900"
)}
>
<div className="break-all font-mono text-xs font-semibold text-zinc-800 dark:text-zinc-200">
.worktrees/auth-refactor
</div>
<div className="mt-1 text-[11px] text-zinc-500 dark:text-zinc-400">
{bound ? "bash / read / write cwd" : "task.worktree binding"}
</div>
</motion.div>
</div>
<div className="mt-3 flex items-center gap-2 text-xs text-zinc-600 dark:text-zinc-300">
{bound ? <Terminal size={15} /> : <GitBranch size={15} />}
<span>{bound ? "Tools follow the claimed task." : "No implicit directory switching."}</span>
</div>
</div>
);
}
export default function TeamRuntime({ title }: { title?: string }) {
const vis = useSteppedVisualization({ totalSteps: STEPS.length, autoPlayInterval: 2800 });
const step = vis.currentStep;
const current = STEPS[step];
return (
<section className="min-h-[500px] space-y-4">
<h2 className="text-xl font-semibold text-zinc-900 dark:text-zinc-100">
{title || "Agent Team Runtime"}
</h2>
<div className="rounded-lg border border-zinc-200 bg-zinc-50 p-4 dark:border-zinc-700 dark:bg-zinc-950">
<div className="grid gap-3 lg:grid-cols-3">
<RuntimePanel step={step} />
<TaskPanel step={step} />
<WorkspacePanel step={step} />
</div>
<div className="mt-3 rounded-lg border border-zinc-200 bg-white p-3 dark:border-zinc-700 dark:bg-zinc-900">
<div className="mb-2 flex items-center gap-2 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
<CheckCircle2 size={14} />
Runtime events
</div>
<div className="grid gap-2 md:grid-cols-2 xl:grid-cols-3">
{EVENTS.map((event, index) => {
const visible = index <= step;
return (
<motion.div
key={event}
initial={false}
animate={{ opacity: visible ? 1 : 0.18, y: 0 }}
aria-hidden={!visible}
className={cn(
"break-all rounded-md border px-2 py-1.5 font-mono text-[10px]",
index === step
? "border-blue-300 bg-blue-50 text-blue-700 dark:border-blue-800 dark:bg-blue-950/30 dark:text-blue-200"
: "border-zinc-200 bg-zinc-50 text-zinc-600 dark:border-zinc-700 dark:bg-zinc-800 dark:text-zinc-300"
)}
>
{event}
</motion.div>
);
})}
</div>
</div>
<StepControls
className="mt-4"
currentStep={vis.currentStep}
totalSteps={vis.totalSteps}
onPrev={vis.prev}
onNext={vis.next}
onReset={vis.reset}
isPlaying={vis.isPlaying}
onToggleAutoPlay={vis.toggleAutoPlay}
stepTitle={current.title}
stepDescription={current.desc}
/>
</div>
</section>
);
}

View File

@@ -56,7 +56,7 @@ const STAGES: {
{
id: "execute",
label: "Execute",
detail: "local tools, teams, worktrees",
detail: "local tools, teams, task-bound worktrees",
icon: <Wrench size={15} />,
},
{
@@ -82,7 +82,7 @@ const STAGES: {
const SURFACES = [
{ label: "background", icon: <Clock3 size={14} />, text: "slow commands can finish later" },
{ label: "team", icon: <Network size={14} />, text: "teammates work through mailboxes" },
{ label: "worktree", icon: <GitBranch size={14} />, text: "risky edits stay isolated" },
{ label: "worktree", icon: <GitBranch size={14} />, text: "task-bound cwd selects a separate checkout" },
{ label: "MCP", icon: <Blocks size={14} />, text: "external tools are normalized" },
];

View File

@@ -18,15 +18,15 @@
{
"id": "runtime-owned-delivery",
"title": "Message Delivery Belongs to the Runtime",
"description": "MessageBus stores each handoff in JSONL, while the runtime watches the Lead mailbox and injects new team events into the next turn. The model does not need an inbox polling tool.",
"description": "The MessageBus persists each handoff, while the runtime watches the Lead mailbox and injects new team events into the next turn. The model does not spend turns polling an inbox.",
"alternatives": "A model-visible check_inbox tool is easy to add, but wastes turns and can leave completed work unnoticed.",
"zh": {
"title": "消息投递由运行时负责",
"description": "MessageBus 每次交接写入 JSONL,运行时监听 Lead 邮箱,并把新的团队事件送入下一轮上下文。模型不需要调用邮箱轮询工具。"
"description": "MessageBus 持久化每次交接,运行时监听 Lead 邮箱,并把新的团队事件送入下一轮上下文。模型不需要浪费轮次轮询收件箱。"
},
"ja": {
"title": "メッセージ配信はランタイムが担う",
"description": "MessageBus 各ハンドオフを JSONL に保存し、ランタイムが Lead のメールボックスを監視して新しい team event を次の turn に注入する。モデル受信箱確認ツールは要らない。"
"description": "MessageBus 各ハンドオフを永続化し、ランタイムが Lead の受信箱を監視して新しい team event を次の turn に注入する。モデル受信箱のポーリングに turn を費やさない。"
}
},
{
@@ -46,15 +46,57 @@
{
"id": "plan-approval-is-a-gate",
"title": "Plan Approval Is an Execution Gate",
"description": "When the Lead requests a plan, mutating tools remain blocked until the matching plan is approved. Rejection requires a new submission, and an idle teammate remains available for later assignments until a typed shutdown completes.",
"alternatives": "Treating approval as a conversational suggestion cannot prevent an early write or shell command.",
"description": "When the Lead requests a plan, mutating tools remain blocked until the matching plan is approved. Rejection requires a new submission rather than a conversational workaround.",
"alternatives": "Treating approval as a suggestion cannot prevent an early write or shell command.",
"zh": {
"title": "计划审批是执行闸门",
"description": "Lead 请求计划后,修改类工具会保持阻塞,直到对应计划通过。被拒绝的计划必须重新提交;空闲队友会继续保留,直到类型化关机协议完成。"
"description": "Lead 请求计划后,修改类工具会保持阻塞,直到对应计划通过。被拒绝的计划必须重新提交,不能靠对话绕过。"
},
"ja": {
"title": "プラン承認を実行ゲートにする",
"description": "Lead がプランを要求すると、対応するプランが承認されるまで変更系ツールをブロックする。却下後は再提出が必要で、待機中のチームメイトは型付き終了プロトコルが完了するまで残る。"
"description": "Lead がプランを要求すると、対応するプランが承認されるまで変更系ツールをブロックする。却下後は会話で迂回せず再提出が必要になる。"
}
},
{
"id": "idle-claim-is-atomic",
"title": "Idle Discovery and Claiming Form One Safe Path",
"description": "An idle teammate scans only pending, unowned tasks whose dependencies are complete. The ownership check and pending-to-in_progress update happen under one lock, so two teammates cannot claim the same work.",
"alternatives": "Central dispatch keeps assignment simple, while an unlocked scan can assign the same task twice.",
"zh": {
"title": "空闲发现与原子认领组成一条安全路径",
"description": "空闲队友只扫描 pending、未分配且依赖已完成的任务。所有权检查与 pending 到 in_progress 的更新在同一把锁内完成,因此两个队友不会认领同一任务。"
},
"ja": {
"title": "待機中の探索と原子的な認領を一つの安全な経路にする",
"description": "待機中のチームメイトは pending、未所有、依存解決済みのタスクだけを探す。所有権確認と pending から in_progress への更新を同じ lock 内で行い、二重認領を防ぐ。"
}
},
{
"id": "task-bound-worktree",
"title": "The Working Directory Is a Task Property",
"description": "A task records its worktree binding, and a teammate's bash, read, and write tools derive their working directory from the claimed task. This is explicit cwd routing for parallel edits, not a security sandbox or a second orchestration system.",
"alternatives": "Letting agents switch directories implicitly is shorter, but makes the cwd boundary invisible and easy to lose.",
"zh": {
"title": "工作目录是任务的显式属性",
"description": "任务记录自己的 worktree 绑定,队友的 bash、read、write 工具从已认领任务推导工作目录。这是为并行编辑提供的显式 cwd 路由,不是安全沙箱,也不是第二套编排系统。"
},
"ja": {
"title": "作業ディレクトリをタスクの明示的な属性にする",
"description": "タスクが worktree の紐付けを保持し、チームメイトの bash、read、write は認領したタスクから作業ディレクトリを決める。これは並行編集のための明示的な cwd routing であり、security sandbox や第二の編成システムではない。"
}
},
{
"id": "worktree-cleanup-fails-closed",
"title": "Worktree Cleanup Fails Closed",
"description": "Creation binds a task only after git succeeds. Removal accepts only a known path under the worktree root and refuses unverifiable or dirty state unless discard is explicit; it never completes the task as a side effect.",
"alternatives": "Unconditional force removal is convenient, but can destroy unreviewed work and blur task completion with directory cleanup.",
"zh": {
"title": "Worktree 清理默认拒绝不安全操作",
"description": "只有 git 创建成功后才绑定任务。删除仅接受 worktree 根目录下的已知路径;状态无法验证或存在未保存改动时,除非明确选择丢弃,否则拒绝删除,并且不会顺带完成任务。"
},
"ja": {
"title": "Worktree の片付けは安全側に失敗する",
"description": "git の作成成功後にだけタスクを紐付ける。削除は worktree ルート配下の既知パスだけを受け付け、状態を確認できない場合や変更が残る場合は明示的な破棄なしに拒否し、タスクを副作用で完了させない。"
}
}
]

View File

@@ -2,45 +2,45 @@
"version": "s16",
"decisions": [
{
"id": "idle-state-discovers-work",
"title": "Idle Teammates Look for Ready Work",
"description": "s15 already keeps teammates alive in IDLE. s16 gives that state one more input: after waiting for messages, a teammate scans the shared task board for pending, unowned, unblocked work.",
"alternatives": "The Lead could dispatch every assignment, but then an idle teammate cannot help with work that becomes ready later.",
"id": "normalized-mcp-namespace",
"title": "MCP Tools Use a Normalized Namespace",
"description": "Discovered tools are exposed as mcp__server__tool. The prefix makes the source explicit and avoids collisions with built-in tools or tools from another server.",
"alternatives": "Using the raw tool name is shorter, but search from two servers could overwrite each other.",
"zh": {
"title": "空闲队友主动寻找就绪任务",
"description": "s15 已经让队友在 IDLE 中保持存活。s16 为这个状态增加任务板入口:等待消息后,队友会扫描 pending、未分配且依赖已完成的任务。"
"title": "MCP 工具使用规范化命名空间",
"description": "发现到的工具会暴露为 mcp__server__tool。前缀让工具来源明确也避免和内置工具或其他服务器工具冲突。"
},
"ja": {
"title": "待機中のチームメイトが実行可能な仕事を探す",
"description": "s15 ですでにチームメイトは IDLE のまま残る。s16 はその状態にタスクボード入口を追加し、メッセージ待機後に pending、未所有、依存解決済みのタスクを探す。"
"title": "MCP ツールは正規化された名前空間を使う",
"description": "発見されたツールは mcp__server__tool として公開されます。接頭辞により出所が明確になり、組み込みツールや別サーバーのツールとの衝突を避けます。"
}
},
{
"id": "atomic-claim",
"title": "Claiming Is Atomic",
"description": "The ownership check and task update run under one lock. When two teammates see the same ready task, only one can move it from pending to in_progress.",
"alternatives": "Scanning and writing without a shared lock can assign the same task twice.",
"id": "dynamic-tool-pool",
"title": "Tool Discovery Updates the Active Tool Pool",
"description": "After connecting to a server, the runtime assembles a new tool pool for the next LLM call. The model can only use MCP tools after discovery has made them visible.",
"alternatives": "Preloading every possible MCP tool would create a huge prompt and expose capabilities the user did not request.",
"zh": {
"title": "任务认领必须原子化",
"description": "所有权检查与任务更新在同一把锁内完成。两个队友同时看到一个就绪任务时,只有一个能把它从 pending 推进到 in_progress。"
"title": "工具发现会更新活动工具池",
"description": "连接服务器后,运行时会为下一次 LLM 调用组装新的工具池。模型只有在发现阶段让 MCP 工具可见之后,才能调用它们。"
},
"ja": {
"title": "タスク認領を原子的に行う",
"description": "所有権確認とタスク更新を同じ lock の中で行う。二つのチームメイトが同じ実行可能タスクを見ても、pending から in_progress へ進められるのは一方だけである。"
"title": "ツール発見がアクティブなツールプールを更新する",
"description": "サーバー接続後、ランタイムは次の LLM 呼び出し用に新しいツールプールを組み立てます。MCP ツールは発見で可視化された後にのみモデルが利用できます。"
}
},
{
"id": "dependencies-filter-readiness",
"title": "Dependencies Define Readiness",
"description": "The scan returns a task only when every blockedBy dependency is completed. A teammate with nothing ready remains idle instead of starting work out of order.",
"alternatives": "Ignoring dependencies increases utilization, but produces work against unfinished inputs.",
"id": "external-results-append-like-tools",
"title": "External Results Reuse the Tool Result Path",
"description": "MCP responses are appended to the conversation like ordinary tool results. This keeps the agent loop unchanged while still letting external systems participate.",
"alternatives": "A separate external-response channel would make MCP feel special and require extra loop logic.",
"zh": {
"title": "依赖关系决定任务是否就绪",
"description": "只有 blockedBy 中的依赖全部完成,扫描才会返回该任务。没有就绪任务的队友继续保持 IDLE不会越过依赖提前开工。"
"title": "外部结果复用 Tool Result 路径",
"description": "MCP 响应会像普通 tool result 一样追加到对话中。这样 agent 循环无需改变,同时外部系统仍然可以参与。"
},
"ja": {
"title": "依存関係が実行可能性を決める",
"description": "blockedBy の依存がすべて完了したタスクだけを走査結果に含める。実行可能な仕事がなければ IDLE を維持し、順序を飛ばして開始しない。"
"title": "外部結果は tool result 経路を再利用する",
"description": "MCP の応答は通常の tool result と同じように会話へ追加されます。エージェントループを変えずに外部システムを参加させられます。"
}
}
]

View File

@@ -2,45 +2,45 @@
"version": "s17",
"decisions": [
{
"id": "worktree-name-validation",
"title": "Worktree Names Are Validated Before Git Runs",
"description": "The tool validates names before creating branches or directories, so unsafe user input never reaches git or filesystem operations.",
"alternatives": "Passing names directly to git is shorter, but it turns a collaboration feature into an injection hazard.",
"id": "composition-over-new-loop",
"title": "The Harness Composes Previous Layers",
"description": "The integrated harness does not replace the loop with a new architecture. It composes memory, tasks, skills, background work, teams, worktrees, and MCP around the same core model-tool-result cycle.",
"alternatives": "A new orchestration framework would look more impressive, but it would hide the continuity across the course.",
"zh": {
"title": "运行 Git 前先校验 Worktree 名称",
"description": "工具在创建分支或目录前先校验名称,不让不安全的用户输入进入 git 或文件系统操作。"
"title": "Harness 组合既有层,而不是换掉循环",
"description": "集成后的 Harness 没有用新架构替换循环,而是把 memory、task、skill、后台任务、团队、worktree、MCP 组合到同一个模型-工具-结果循环周围。"
},
"ja": {
"title": "git 実行前に worktree 名を検証する",
"description": "ブランチやディレクトリ作成前に名前を検証し、危険なユーザー入力が git やファイルシステム操作へ流れないようにします。"
"title": "Harness は既存レイヤーを統合する",
"description": "統合された Harness はループを新しい構造で置き換えません。memory、task、skill、バックグラウンド処理、チーム、worktree、MCP を同じ model-tool-result サイクルの周囲に合成します。"
}
},
{
"id": "task-bound-worktree",
"title": "The Task Record Owns the Worktree Binding",
"description": "A task stores its assigned worktree so future commands know where to run. The binding is explicit data, not a hidden convention based on naming or current working directory.",
"alternatives": "Deriving the worktree path from branch names is convenient, but brittle when tasks are renamed or moved.",
"id": "single-source-of-runtime-truth",
"title": "Runtime State Has Named Sources",
"description": "Context assembly pulls from named sources such as memory, task graph, skills, tool registry, and policy. This keeps a large agent debuggable because each piece of prompt context has an owner.",
"alternatives": "Dumping everything into one prompt string is shorter, but it becomes impossible to tell which subsystem caused a bad decision.",
"zh": {
"title": "任务记录持有 Worktree 绑定关系",
"description": "任务会记录自己分配到的 worktree因此后续命令知道应该在哪里运行。这个绑定是显式数据而不是依赖命名或当前目录的隐藏约定。"
"title": "运行时状态来自具名来源",
"description": "上下文组装从 memory、task graph、skills、tool registry、policy 等具名来源读取。大型 agent 因此仍可调试,因为每块 prompt context 都有清晰归属。"
},
"ja": {
"title": "タスクレコードが worktree の紐付けを持つ",
"description": "タスクは割り当てられた worktree を保持し、後続コマンドは実行場所を把握できます。この紐付けは命名や現在ディレクトリに依存する暗黙の規約ではなく、明示的なデータです。"
"title": "ランタイム状態には名前付きの出所がある",
"description": "コンテキスト組み立ては memory、task graph、skills、tool registry、policy などの名前付きソースから取得します。各 prompt context に所有者があるため、大きなエージェントでもデバッグ可能です。"
}
},
{
"id": "lifecycle-event-stream",
"title": "Lifecycle Events Stay Separate from Tool Results",
"description": "Creation, status, keep, and removal events are emitted to a side-channel log. That makes worktree state observable without overloading the conversational transcript.",
"alternatives": "Only returning tool results is simpler, but later debugging needs a durable audit trail of worktree lifecycle changes.",
"id": "recovery-is-first-class",
"title": "Recovery Is Part of the Main Flow",
"description": "Compaction, error recovery, and asynchronous result collection are normal loop behavior. The harness handles recovery and resumption through named paths instead of scattered exception branches.",
"alternatives": "Leaving recovery at the edges makes it harder to see which state is safe to resume.",
"zh": {
"title": "生命周期事件与工具结果分离",
"description": "创建、状态、保留和移除事件会写入旁路日志。这样 worktree 状态可观察,同时不会把对话 transcript 塞满运行时事件。"
"title": "恢复能力是一等流程",
"description": "压缩、错误恢复和异步结果收集都属于正常循环。Harness 通过明确的路径处理恢复与续跑,而不是把逻辑散落在异常分支中。"
},
"ja": {
"title": "ライフサイクルイベントをツール結果から分離する",
"description": "作成、状態、保持、削除のイベントはサイドチャネルログへ出力します。会話 transcript をランタイムイベントで埋めずに worktree 状態を観測できます。"
"title": "リカバリは主要フローの一部",
"description": "圧縮、エラー回復、非同期結果収集を通常のループ動作として扱います。Harness は回復と再開を名前付きの経路にまとめ、例外分岐へ散らしません。"
}
}
]

View File

@@ -2,45 +2,45 @@
"version": "s18",
"decisions": [
{
"id": "normalized-mcp-namespace",
"title": "MCP Tools Use a Normalized Namespace",
"description": "Discovered tools are exposed as mcp__server__tool. The prefix makes the source explicit and avoids collisions with built-in tools or tools from another server.",
"alternatives": "Using the raw tool name is shorter, but search from two servers could overwrite each other.",
"id": "script-owns-fixed-orchestration",
"title": "Code Owns Fixed Orchestration",
"description": "When the stages and aggregation rules are known in advance, a workflow script makes the process parallel, reproducible, and inspectable without changing the main agent loop.",
"alternatives": "Letting the model choose every next step is more flexible, but slower and harder to resume for a fixed procedure.",
"zh": {
"title": "MCP 工具使用规范化命名空间",
"description": "发现到的工具会暴露为 mcp__server__tool。前缀让工具来源明确也避免和内置工具或其他服务器工具冲突。"
"title": "固定编排由代码负责",
"description": "当阶段与汇总规则事先确定时workflow 脚本能让流程并行、可复现、可检查,同时不修改主 Agent 循环。"
},
"ja": {
"title": "MCP ツールは正規化された名前空間を使う",
"description": "発見されたツールは mcp__server__tool として公開されます。接頭辞により出所が明確になり、組み込みツールや別サーバーのツールとの衝突を避けます。"
"title": "固定された編成はコードが担う",
"description": "段階と集約ルールが事前に決まっているなら、workflow script は main Agent loop を変えずに処理を並列化し、再現可能で検査可能にする。"
}
},
{
"id": "dynamic-tool-pool",
"title": "Tool Discovery Updates the Active Tool Pool",
"description": "After connecting to a server, the runtime assembles a new tool pool for the next LLM call. The model can only use MCP tools after discovery has made them visible.",
"alternatives": "Preloading every possible MCP tool would create a huge prompt and expose capabilities the user did not request.",
"id": "semantic-journal-keys",
"title": "Semantic Keys Make Resume Independent of Completion Order",
"description": "Journal entries use stable call content rather than a shared completion counter. Concurrent calls can finish in any order and still map to the correct cached result.",
"alternatives": "Indexing by completion order is simpler, but replays the wrong result as soon as concurrent timing changes.",
"zh": {
"title": "工具发现会更新活动工具池",
"description": "连接服务器后,运行时会为下一次 LLM 调用组装新的工具池。模型只有在发现阶段让 MCP 工具可见之后,才能调用它们。"
"title": "语义键让恢复不依赖完成顺序",
"description": "Journal 用稳定的调用内容作为 key而不是共享完成计数器。并发调用无论以什么顺序结束都能命中正确缓存。"
},
"ja": {
"title": "ツール発見がアクティブなツールプールを更新する",
"description": "サーバー接続後、ランタイムは次の LLM 呼び出し用に新しいツールプールを組み立てます。MCP ツールは発見で可視化された後にのみモデルが利用できます。"
"title": "意味キーで完了順序に依存せず再開する",
"description": "Journal は共有完了カウンタではなく安定した call 内容を key にする。並行 call の終了順が変わっても正しい cache result に対応できる。"
}
},
{
"id": "external-results-append-like-tools",
"title": "External Results Reuse the Tool Result Path",
"description": "MCP responses are appended to the conversation like ordinary tool results. This keeps the agent loop unchanged while still letting external systems participate.",
"alternatives": "A separate external-response channel would make MCP feel special and require extra loop logic.",
"id": "fail-the-workflow",
"title": "Orchestration Failures Propagate",
"description": "A failed stage, invalid structured result, corrupt journal, or exceeded run-wide limit fails the workflow instead of silently dropping an item and reporting success.",
"alternatives": "Best-effort collection can be useful for optional work, but it must be explicit rather than the default.",
"zh": {
"title": "外部结果复用 Tool Result 路径",
"description": "MCP 响应会像普通 tool result 一样追加到对话中。这样 agent 循环无需改变,同时外部系统仍然可以参与。"
"title": "编排故障必须向上传播",
"description": "阶段失败、结构化结果不合法、journal 损坏或超过全局限制时workflow 直接失败,而不是静默丢项后仍报告成功。"
},
"ja": {
"title": "外部結果は tool result 経路を再利用する",
"description": "MCP の応答は通常の tool result と同じように会話へ追加されます。エージェントループを変えずに外部システムを参加させられます。"
"title": "編成の失敗は上位へ伝播させる",
"description": "stage failure、無効な structured result、破損 journal、run-wide limit 超過は workflow を失敗させ、項目を黙って落として成功扱いしない。"
}
}
]

View File

@@ -2,45 +2,45 @@
"version": "s19",
"decisions": [
{
"id": "composition-over-new-loop",
"title": "The Harness Composes Previous Layers",
"description": "The integrated harness does not replace the loop with a new architecture. It composes memory, tasks, skills, background work, teams, worktrees, and MCP around the same core model-tool-result cycle.",
"alternatives": "A new orchestration framework would look more impressive, but it would hide the continuity across the course.",
"id": "host-owns-completion-gate",
"title": "The Host Owns the Completion Gate",
"description": "The working model may request to stop, but GoalController evaluates the active goal before AgentSession returns. The gate sits at the existing turn boundary.",
"alternatives": "Asking the working model whether it is finished is simpler, but lets the same actor make and verify its own claim.",
"zh": {
"title": "Harness 组合既有层,而不是换掉循环",
"description": "集成后的 Harness 没有用新架构替换循环,而是把 memory、task、skill、后台任务、团队、worktree、MCP 组合到同一个模型-工具-结果循环周围。"
"title": "完成闸门由宿主持有",
"description": "工作模型可以请求停止,但 GoalController 会在 AgentSession 返回前评估 active goal。这个闸门就在原有的轮次边界上。"
},
"ja": {
"title": "Harness は既存レイヤーを統合する",
"description": "統合された Harness はループを新しい構造で置き換えません。memory、task、skill、バックグラウンド処理、チーム、worktree、MCP を同じ model-tool-result サイクルの周囲に合成します。"
"title": "完了ゲートはホストが所有する",
"description": "作業モデルは停止を要求できますが、GoalController は AgentSession が return する前に active goal を評価します。この gate は既存の turn 境界に置かれます。"
}
},
{
"id": "single-source-of-runtime-truth",
"title": "Runtime State Has Named Sources",
"description": "Context assembly pulls from named sources such as memory, task graph, skills, tool registry, and policy. This keeps a large agent debuggable because each piece of prompt context has an owner.",
"alternatives": "Dumping everything into one prompt string is shorter, but it becomes impossible to tell which subsystem caused a bad decision.",
"id": "conversation-is-evaluator-input",
"title": "The Conversation Is the Evaluator's Input",
"description": "The evaluator receives the active condition and the current conversation, including tool results reported there. It has no tools of its own and judges only what the conversation contains.",
"alternatives": "Letting the evaluator rerun commands would turn a completion check into another worker and create a second execution path.",
"zh": {
"title": "运行时状态来自具名来源",
"description": "上下文组装从 memory、task graph、skills、tool registry、policy 等具名来源读取。大型 agent 因此仍可调试,因为每块 prompt context 都有清晰归属。"
"title": "对话记录就是判断器的输入",
"description": "判断器接收 active condition 和当前对话,其中也包括已经写入的工具结果。它自己没有工具,只能根据对话中已有的内容判断。"
},
"ja": {
"title": "ランタイム状態には名前付きの出所がある",
"description": "コンテキスト組み立ては memory、task graph、skills、tool registry、policy などの名前付きソースから取得します。各 prompt context に所有者があるため、大きなエージェントでもデバッグ可能です。"
"title": "conversation が evaluator の入力になる",
"description": "evaluator は active condition と現在の conversation を受け取り、そこに記録された tool result も読みます。自身では tool を使えず、conversation にある内容だけで判断します。"
}
},
{
"id": "recovery-is-first-class",
"title": "Recovery Is Part of the Main Flow",
"description": "Compaction, error recovery, and asynchronous result collection are normal loop behavior. The harness handles recovery and resumption through named paths instead of scattered exception branches.",
"alternatives": "Leaving recovery at the edges makes it harder to see which state is safe to resume.",
"id": "continuation-limits-preserve-goal",
"title": "Limits Return Control Without Clearing the Goal",
"description": "When a goal is unmet, the controller appends the evaluator's reason to messages[] and continues the same loop. The Stop-hook block cap or global turn limit returns control to the user while leaving the goal active.",
"alternatives": "Continuing without any limit can hold one request forever; marking the goal complete or clearing it at the limit would lose unfinished work.",
"zh": {
"title": "恢复能力是一等流程",
"description": "压缩、错误恢复和异步结果收集都属于正常循环。Harness 通过明确的路径处理恢复与续跑,而不是把逻辑散落在异常分支中。"
"title": "达到限制时交还控制权,但保留目标",
"description": "目标未满足时controller 把判断理由追加到 messages[]并在同一个循环里继续。Stop hook 的连续阻止上限或全局轮次上限会把控制权交还用户,同时让目标保持 active。"
},
"ja": {
"title": "リカバリは主要フローの一部",
"description": "圧縮、エラー回復、非同期結果収集を通常のループ動作として扱います。Harness は回復と再開を名前付きの経路にまとめ、例外分岐へ散らしません。"
"title": "上限では control を返し、goal は維持する",
"description": "goal が未達なら、controller は evaluator の理由を messages[] に追加し、同じ loop を続けます。Stop hook の連続 block 上限または global turn limit に達すると、goal を active のまま user に control を返します。"
}
}
]

View File

@@ -1,47 +0,0 @@
{
"version": "s20",
"decisions": [
{
"id": "script-owns-fixed-orchestration",
"title": "Code Owns Fixed Orchestration",
"description": "When the stages and aggregation rules are known in advance, a workflow script makes the process parallel, reproducible, and inspectable without changing the main agent loop.",
"alternatives": "Letting the model choose every next step is more flexible, but slower and harder to resume for a fixed procedure.",
"zh": {
"title": "固定编排由代码负责",
"description": "当阶段与汇总规则事先确定时workflow 脚本能让流程并行、可复现、可检查,同时不修改主 Agent 循环。"
},
"ja": {
"title": "固定された編成はコードが担う",
"description": "段階と集約ルールが事前に決まっているなら、workflow script は main Agent loop を変えずに処理を並列化し、再現可能で検査可能にする。"
}
},
{
"id": "semantic-journal-keys",
"title": "Semantic Keys Make Resume Independent of Completion Order",
"description": "Journal entries use stable call content rather than a shared completion counter. Concurrent calls can finish in any order and still map to the correct cached result.",
"alternatives": "Indexing by completion order is simpler, but replays the wrong result as soon as concurrent timing changes.",
"zh": {
"title": "语义键让恢复不依赖完成顺序",
"description": "Journal 用稳定的调用内容作为 key而不是共享完成计数器。并发调用无论以什么顺序结束都能命中正确缓存。"
},
"ja": {
"title": "意味キーで完了順序に依存せず再開する",
"description": "Journal は共有完了カウンタではなく安定した call 内容を key にする。並行 call の終了順が変わっても正しい cache result に対応できる。"
}
},
{
"id": "fail-the-workflow",
"title": "Orchestration Failures Propagate",
"description": "A failed stage, invalid structured result, corrupt journal, or exceeded run-wide limit fails the workflow instead of silently dropping an item and reporting success.",
"alternatives": "Best-effort collection can be useful for optional work, but it must be explicit rather than the default.",
"zh": {
"title": "编排故障必须向上传播",
"description": "阶段失败、结构化结果不合法、journal 损坏或超过全局限制时workflow 直接失败,而不是静默丢项后仍报告成功。"
},
"ja": {
"title": "編成の失敗は上位へ伝播させる",
"description": "stage failure、無効な structured result、破損 journal、run-wide limit 超過は workflow を失敗させ、項目を黙って落として成功扱いしない。"
}
}
]
}

View File

@@ -1,47 +0,0 @@
{
"version": "s21",
"decisions": [
{
"id": "host-owns-completion-gate",
"title": "The Host Owns the Completion Gate",
"description": "The working model may request to stop, but the harness evaluates the active goal before returning. Completion is a program decision at the turn boundary.",
"alternatives": "Asking the working model whether it is finished is simpler, but lets the same actor make and verify its own claim.",
"zh": {
"title": "完成闸门由宿主持有",
"description": "工作模型可以请求停止,但 harness 会在 return 前评估 active goal。是否完成是轮次边界上的程序决策。"
},
"ja": {
"title": "完了ゲートはホストが所有する",
"description": "作業モデルは停止を要求できるが、harness は return 前に active goal を評価する。完了は turn 境界でのプログラム判断である。"
}
},
{
"id": "host-assigned-evidence-origins",
"title": "Evidence Trust Comes from the Ingress Path",
"description": "Ordinary submit calls cannot attach trusted labels. Only an allowlisted host-event channel can deliver task or monitor evidence, so user and model prose cannot certify itself.",
"alternatives": "Trusting text content or caller-supplied labels makes the evidence boundary forgeable.",
"zh": {
"title": "证据信任来自入口路径",
"description": "普通 submit 不能附加可信标签;只有白名单宿主事件通道能送入 task 或 monitor 证据,因此用户与模型文本不能自证完成。"
},
"ja": {
"title": "証拠の信頼は入力経路から得る",
"description": "通常の submit は trusted label を付けられず、allowlist 済み host event channel だけが task や monitor evidence を届ける。ユーザーやモデルの文章は自己証明できない。"
}
},
{
"id": "bounded-continuation",
"title": "Every Automatic Continuation Needs a Budget",
"description": "An unmet goal queues another turn only while budget remains. Exhaustion marks the goal blocked and releases the gate instead of creating an infinite loop.",
"alternatives": "An unbounded goal is persistent, but an impossible condition can consume resources forever.",
"zh": {
"title": "每次自动续轮都必须有预算",
"description": "目标未满足时只在预算剩余时继续;耗尽后将目标标记为 blocked 并释放闸门,避免无限循环。"
},
"ja": {
"title": "自動継続には必ず予算を置く",
"description": "goal 未達時は予算が残る間だけ次の turn を追加する。使い切れば blocked にして gate を解放し、無限 loop を防ぐ。"
}
}
]
}

View File

@@ -370,88 +370,38 @@ export const EXECUTION_FLOWS: Record<string, FlowDefinition> = {
nodes: [
{ id: "start", label: "User Requirement", type: "start", x: COL_CENTER, y: 30 },
{ id: "lead", label: "Lead Proposes\nSmall Team", type: "process", x: COL_CENTER, y: 110 },
{ id: "team_tool", label: "User Confirms?", type: "decision", x: COL_CENTER, y: 200 },
{ id: "spawn", label: "Spawn Persistent\nTeammates", type: "subprocess", x: COL_LEFT, y: 300 },
{ id: "send", label: "Assignment /\nTyped Request", type: "subprocess", x: COL_LEFT, y: 400 },
{ id: "bus", label: "MessageBus\nJSONL Mailboxes", type: "process", x: COL_CENTER, y: 500 },
{ id: "teammate", label: "Teammate\nWORK / IDLE", type: "process", x: COL_RIGHT, y: 400 },
{ id: "tools", label: "Scoped Tools /\nPlan Gate", type: "subprocess", x: COL_RIGHT, y: 500 },
{ id: "inbox", label: "Runtime Delivery", type: "process", x: COL_CENTER, y: 600 },
{ id: "append", label: "Append Team Events", type: "process", x: COL_LEFT, y: 690 },
{ id: "end", label: "Continue Alone", type: "end", x: COL_RIGHT, y: 300 },
{ id: "confirm", label: "User Confirms?", type: "decision", x: COL_CENTER, y: 190 },
{ id: "spawn", label: "Spawn Persistent\nTeammate", type: "subprocess", x: COL_LEFT, y: 280 },
{ id: "bus", label: "MessageBus\nTyped Requests", type: "process", x: COL_CENTER, y: 370 },
{ id: "teammate", label: "Teammate\nWORK / IDLE", type: "process", x: COL_RIGHT, y: 280 },
{ id: "gate", label: "Plan Approved?", type: "decision", x: COL_RIGHT, y: 370 },
{ id: "scan", label: "Scan Ready Tasks", type: "subprocess", x: COL_CENTER, y: 470 },
{ id: "ready", label: "Ready Task?", type: "decision", x: COL_CENTER, y: 560 },
{ id: "claim", label: "Atomic Claim\ntask_lock", type: "subprocess", x: COL_LEFT, y: 650 },
{ id: "cwd", label: "Task Worktree\nTool cwd", type: "process", x: COL_RIGHT, y: 650 },
{ id: "result", label: "Result + IDLE\nRuntime Delivery", type: "process", x: COL_CENTER, y: 740 },
{ id: "end", label: "Continue Alone", type: "end", x: COL_RIGHT, y: 190 },
],
edges: [
{ from: "start", to: "lead" },
{ from: "lead", to: "team_tool" },
{ from: "team_tool", to: "spawn", label: "yes" },
{ from: "team_tool", to: "end", label: "no" },
{ from: "spawn", to: "send" },
{ from: "send", to: "bus" },
{ from: "lead", to: "confirm" },
{ from: "confirm", to: "spawn", label: "yes" },
{ from: "confirm", to: "end", label: "no" },
{ from: "spawn", to: "bus", label: "assignment" },
{ from: "bus", to: "teammate" },
{ from: "teammate", to: "tools" },
{ from: "tools", to: "bus", label: "result / protocol reply" },
{ from: "bus", to: "inbox", label: "wake Lead" },
{ from: "inbox", to: "append" },
{ from: "append", to: "lead" },
{ from: "teammate", to: "gate" },
{ from: "gate", to: "bus", label: "waiting" },
{ from: "gate", to: "scan", label: "approved / idle" },
{ from: "scan", to: "ready" },
{ from: "ready", to: "bus", label: "no: wait" },
{ from: "ready", to: "claim", label: "yes" },
{ from: "claim", to: "cwd" },
{ from: "cwd", to: "result" },
{ from: "result", to: "bus", label: "reply + wake Lead" },
{ from: "bus", to: "lead", label: "runtime delivery" },
],
},
s16: {
nodes: [
{ id: "start", label: "Teammate IDLE", type: "start", x: COL_CENTER, y: 30 },
{ id: "idle", label: "Wait for Messages", type: "process", x: COL_CENTER, y: 110 },
{ id: "scan", label: "Scan Ready Tasks", type: "subprocess", x: COL_CENTER, y: 190 },
{ id: "claimable", label: "Ready Task?", type: "decision", x: COL_CENTER, y: 280 },
{ id: "claim", label: "Atomic Claim\ntask_lock", type: "subprocess", x: COL_LEFT, y: 380 },
{ id: "work", label: "WORK State", type: "process", x: COL_LEFT, y: 470 },
{ id: "complete", label: "complete_task", type: "subprocess", x: COL_LEFT, y: 560 },
{ id: "inbox", label: "No Ready Task", type: "process", x: COL_RIGHT, y: 380 },
{ id: "shutdown", label: "Remain IDLE", type: "process", x: COL_RIGHT, y: 470 },
{ id: "done", label: "Result + IDLE Event", type: "process", x: COL_CENTER, y: 650 },
],
edges: [
{ from: "start", to: "idle" },
{ from: "idle", to: "scan" },
{ from: "scan", to: "claimable" },
{ from: "claimable", to: "claim", label: "yes" },
{ from: "claimable", to: "inbox", label: "no" },
{ from: "claim", to: "work" },
{ from: "work", to: "complete" },
{ from: "complete", to: "done" },
{ from: "done", to: "idle" },
{ from: "inbox", to: "shutdown" },
{ from: "shutdown", to: "idle" },
],
},
s17: {
nodes: [
{ id: "start", label: "Task Selected", type: "start", x: COL_CENTER, y: 30 },
{ id: "create", label: "create_worktree", type: "subprocess", x: COL_CENTER, y: 110 },
{ id: "validate", label: "Validate Name", type: "process", x: COL_CENTER, y: 190 },
{ id: "git", label: "git worktree add", type: "subprocess", x: COL_LEFT, y: 290 },
{ id: "bind", label: "Bind Task\nworktree field", type: "process", x: COL_LEFT, y: 380 },
{ id: "run", label: "Run in Isolated\nDirectory", type: "subprocess", x: COL_CENTER, y: 470 },
{ id: "events", label: "Lifecycle Events\n.events.jsonl", type: "process", x: COL_RIGHT, y: 190 },
{ id: "close", label: "keep / remove", type: "decision", x: COL_CENTER, y: 560 },
{ id: "cleanup", label: "remove_worktree", type: "subprocess", x: COL_LEFT, y: 650 },
{ id: "keep", label: "keep_worktree", type: "process", x: COL_RIGHT, y: 650 },
{ id: "end", label: "Task Result", type: "end", x: COL_CENTER, y: 740 },
],
edges: [
{ from: "start", to: "create" },
{ from: "create", to: "validate" },
{ from: "validate", to: "git" },
{ from: "git", to: "bind" },
{ from: "bind", to: "run" },
{ from: "create", to: "events", label: "emit" },
{ from: "run", to: "events", label: "status" },
{ from: "run", to: "close" },
{ from: "close", to: "cleanup", label: "remove" },
{ from: "close", to: "keep", label: "keep" },
{ from: "cleanup", to: "end" },
{ from: "keep", to: "end" },
],
},
s18: {
nodes: [
{ id: "start", label: "User Input", type: "start", x: COL_CENTER, y: 30 },
{ id: "llm", label: "LLM Call", type: "process", x: COL_CENTER, y: 110 },
@@ -478,7 +428,7 @@ export const EXECUTION_FLOWS: Record<string, FlowDefinition> = {
{ from: "append", to: "llm" },
],
},
s19: {
s17: {
nodes: [
{ id: "start", label: "User Input", type: "start", x: COL_CENTER, y: 30 },
{ id: "context", label: "Assemble Context\nmemory + tasks", type: "process", x: COL_CENTER, y: 115 },
@@ -512,7 +462,7 @@ export const EXECUTION_FLOWS: Record<string, FlowDefinition> = {
{ from: "recover", to: "context" },
],
},
s20: {
s18: {
nodes: [
{ id: "start", label: "Workflow Tool Call", type: "start", x: COL_CENTER, y: 30 },
{ id: "validate", label: "Validate Meta +\nPermission", type: "process", x: COL_CENTER, y: 120 },
@@ -536,28 +486,34 @@ export const EXECUTION_FLOWS: Record<string, FlowDefinition> = {
{ from: "output", to: "notify" },
],
},
s21: {
s19: {
nodes: [
{ id: "start", label: "Model Wants to Stop", type: "start", x: COL_CENTER, y: 30 },
{ id: "active", label: "Active Goal?", type: "decision", x: COL_CENTER, y: 120 },
{ id: "evidence", label: "Read Trusted\nEvidence Window", type: "process", x: COL_CENTER, y: 220 },
{ id: "evaluate", label: "Goal Satisfied?", type: "decision", x: COL_CENTER, y: 320 },
{ id: "complete", label: "goal_completed", type: "end", x: COL_RIGHT, y: 430 },
{ id: "budget", label: "Budget Left?", type: "decision", x: COL_LEFT, y: 430 },
{ id: "continue", label: "Queue Goal\nContinuation", type: "process", x: COL_LEFT, y: 540 },
{ id: "loop", label: "Next Agent Turn", type: "subprocess", x: COL_LEFT, y: 650 },
{ id: "blocked", label: "goal_blocked", type: "end", x: COL_CENTER, y: 540 },
{ id: "background", label: "Background Work\nRunning?", type: "decision", x: COL_CENTER, y: 215 },
{ id: "defer", label: "defer\nGoal Stays Active", type: "end", x: COL_RIGHT, y: 215 },
{ id: "conversation", label: "Evaluator Reads\nConversation", type: "process", x: COL_CENTER, y: 315 },
{ id: "evaluate", label: "Evaluator Result?", type: "decision", x: COL_CENTER, y: 415 },
{ id: "complete", label: "achieved\nGoal Cleared", type: "end", x: COL_RIGHT, y: 415 },
{ id: "failed", label: "failed\nGoal Cleared", type: "end", x: COL_RIGHT, y: 520 },
{ id: "cap", label: "Stop-Block Cap\nReached?", type: "decision", x: COL_LEFT, y: 520 },
{ id: "continue", label: "Append Reason\nto messages[]", type: "process", x: COL_LEFT, y: 625 },
{ id: "loop", label: "Next Agent Turn", type: "subprocess", x: COL_LEFT, y: 730 },
{ id: "limit", label: "limit\nGoal Stays Active", type: "end", x: COL_CENTER, y: 520 },
{ id: "return", label: "Return", type: "end", x: COL_RIGHT, y: 120 },
],
edges: [
{ from: "start", to: "active" },
{ from: "active", to: "return", label: "no" },
{ from: "active", to: "evidence", label: "yes" },
{ from: "evidence", to: "evaluate" },
{ from: "evaluate", to: "complete", label: "yes" },
{ from: "evaluate", to: "budget", label: "no" },
{ from: "budget", to: "continue", label: "yes" },
{ from: "budget", to: "blocked", label: "no" },
{ from: "active", to: "background", label: "yes" },
{ from: "background", to: "defer", label: "yes" },
{ from: "background", to: "conversation", label: "no" },
{ from: "conversation", to: "evaluate" },
{ from: "evaluate", to: "complete", label: "ok" },
{ from: "evaluate", to: "failed", label: "impossible" },
{ from: "evaluate", to: "cap", label: "not yet" },
{ from: "cap", to: "limit", label: "yes" },
{ from: "cap", to: "continue", label: "no" },
{ from: "continue", to: "loop" },
{ from: "loop", to: "start" },
],

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,60 +1,105 @@
{
"version": "s15",
"title": "Agent Teams",
"description": "The Lead proposes a team for a normal user request, waits for confirmation, then coordinates persistent teammates through runtime-delivered events.",
"title": "Agent Team Runtime",
"description": "The Lead coordinates persistent teammates while the runtime owns message delivery, atomic task claims, and task-bound worktree directories.",
"steps": [
{
"type": "user_message",
"content": "Refactor the configuration loader and authentication flow, then update the tests.",
"annotation": "The user describes the goal without designing a team."
"content": "Refactor authentication and update its dependent tests in parallel without mixing the edits.",
"annotation": "The user states the outcome and parallel-edit boundary, not an implementation-specific worktree procedure."
},
{
"type": "assistant_text",
"content": "These areas can be handled in parallel. I propose one teammate for configuration and authentication, and another for tests. Shall I start that team?",
"annotation": "The Lead chooses a small team and makes the extra-agent decision visible."
"content": "I propose a backend teammate for authentication and a test teammate that picks up the dependent checks once they are ready. Shall I start the team?",
"annotation": "The Lead makes the extra-agent decision visible before spawning."
},
{
"type": "user_message",
"content": "Yes, go ahead.",
"annotation": "Teammates start only after explicit confirmation."
"annotation": "The team starts only after explicit confirmation."
},
{
"type": "tool_call",
"toolName": "create_task",
"content": "{\"subject\":\"Refactor authentication\"}",
"annotation": "The shared task board remains the source of ownership and status."
},
{
"type": "tool_result",
"toolName": "create_task",
"content": "Created task_1712345678_0042: Refactor authentication",
"annotation": "The runtime-generated task ID is carried into every later operation on this task."
},
{
"type": "tool_call",
"toolName": "create_worktree",
"content": "{\"name\":\"auth-refactor\",\"task_id\":\"task_1712345678_0042\"}",
"annotation": "The worktree directory is recorded on the task instead of managed as a separate workflow or security sandbox."
},
{
"type": "tool_call",
"toolName": "create_task",
"content": "{\"subject\":\"Update authentication tests\",\"blockedBy\":[\"task_1712345678_0042\"]}",
"annotation": "The task graph keeps dependent work from starting early."
},
{
"type": "tool_result",
"toolName": "create_task",
"content": "Created task_1712345678_0043: Update authentication tests (blockedBy: task_1712345678_0042)",
"annotation": "The second generated ID names the dependent task that the test teammate will later claim."
},
{
"type": "tool_call",
"toolName": "spawn_teammate",
"content": "{\"name\":\"backend\",\"role\":\"backend engineer\",\"prompt\":\"Refactor configuration and authentication while preserving interfaces.\"}",
"annotation": "The first persistent teammate enters WORK with a focused assignment."
"content": "{\"name\":\"backend\",\"role\":\"backend engineer\",\"prompt\":\"Claim the authentication task and propose a plan.\"}",
"annotation": "A persistent teammate receives focused work through the team runtime."
},
{
"type": "tool_call",
"toolName": "spawn_teammate",
"content": "{\"name\":\"tests\",\"role\":\"test engineer\",\"prompt\":\"Update and run tests for the refactor.\"}",
"annotation": "The second teammate gets an independent slice."
"content": "{\"name\":\"tests\",\"role\":\"test engineer\",\"prompt\":\"Watch the board and claim the dependent test task when it becomes ready.\"}",
"annotation": "A second persistent teammate can wait in IDLE without another direct dispatch."
},
{
"type": "system_event",
"content": "backend -> Lead: result(refactor complete) -> idle_notification",
"content": "plan_request(req_plan_7) -> plan_response(req_plan_7, approved=true)",
"annotation": "Typed correlation and an approval gate protect mutating tools."
},
{
"type": "system_event",
"content": "claim_next_task(backend) -> task_1712345678_0042; task_lock commits owner=backend",
"annotation": "The ownership check and state transition are atomic."
},
{
"type": "system_event",
"content": "backend tool cwd -> .worktrees/auth-refactor",
"annotation": "Bash, read, and write derive their directory from the claimed task binding."
},
{
"type": "tool_call",
"toolName": "complete_task",
"content": "{\"task_id\":\"task_1712345678_0042\"}",
"annotation": "Completing the first task makes its dependent test task ready."
},
{
"type": "system_event",
"content": "backend -> Lead: result(auth refactor complete) -> idle_notification",
"annotation": "Result and idle state are separate events; the teammate remains available."
},
{
"type": "system_event",
"content": "tests -> Lead: result(test suite passed) -> idle_notification",
"annotation": "The runtime observes mailbox writes and wakes the Lead without a polling tool."
},
{
"type": "assistant_text",
"content": "Both parts are complete. The interfaces were preserved and the updated tests pass.",
"annotation": "The Lead combines teammate results into one user-facing answer."
},
{
"type": "tool_call",
"toolName": "request_shutdown",
"content": "{\"teammate\":\"backend\"}",
"annotation": "A typed request with a request id closes the persistent teammate cleanly."
"content": "claim_next_task(tests) -> task_1712345678_0043; task_lock commits owner=tests",
"annotation": "An idle teammate discovers newly ready work without another direct assignment."
},
{
"type": "system_event",
"content": "shutdown_response(request_id=req_42, approve=true)",
"annotation": "The matching response resolves the pending protocol request."
"content": "tests -> Lead: result(test suite passed) -> idle_notification",
"annotation": "The runtime wakes the Lead when mailbox events arrive instead of asking the model to poll."
},
{
"type": "assistant_text",
"content": "Authentication was refactored in its task-bound worktree and the dependent tests pass.",
"annotation": "The Lead combines parallel results into one user-facing outcome."
}
]
}

View File

@@ -1,50 +1,46 @@
{
"version": "s16",
"title": "Autonomous Agents",
"description": "Idle teammates discover ready tasks on a shared board and use an atomic claim before starting work.",
"title": "MCP Tools",
"description": "The agent discovers external MCP tools and exposes them through a normalized tool namespace.",
"steps": [
{
"type": "user_message",
"content": "Update the API examples, then add tests that use the final examples.",
"annotation": "The request contains two tasks with a clear dependency."
"content": "Search the documentation for deployment guidance.",
"annotation": "The user asks for a tool source outside the built-in set."
},
{
"type": "tool_call",
"toolName": "create_task",
"content": "{\"subject\":\"Update API examples\"}",
"annotation": "The Lead creates the first task in the shared graph."
"toolName": "connect_mcp",
"content": "{\"name\":\"docs\"}",
"annotation": "The runtime creates an MCP client for the named server."
},
{
"type": "system_event",
"content": "normalize_mcp_name(\"docs\", \"search\") -> mcp__docs__search",
"annotation": "External tools are namespaced to avoid collisions."
},
{
"type": "tool_result",
"toolName": "connect_mcp",
"content": "Connected to MCP server 'docs'. Discovered 2 tools: search, get_version",
"annotation": "Tool discovery expands the active tool pool."
},
{
"type": "tool_call",
"toolName": "create_task",
"content": "{\"subject\":\"Add example tests\",\"blockedBy\":[\"task_examples\"]}",
"annotation": "The second task cannot start until the examples are complete."
"toolName": "mcp__docs__search",
"content": "{\"query\":\"deployment\"}",
"annotation": "The LLM can now call the discovered tool by its normalized name."
},
{
"type": "system_event",
"content": "alice, bob: state=IDLE -> scan_unclaimed_tasks()",
"annotation": "Existing IDLE teammates scan the board after waiting for messages."
"type": "tool_result",
"toolName": "mcp__docs__search",
"content": "[docs] Found 3 results for 'deployment'",
"annotation": "The external result is appended like any other tool result."
},
{
"type": "system_event",
"content": "claim_next_task(alice) -> task_examples; task_lock commits owner=alice",
"annotation": "The ownership check and pending-to-in_progress update are atomic."
},
{
"type": "system_event",
"content": "claim_next_task(bob) -> no ready task; remain IDLE",
"annotation": "The test task is still blocked, so Bob does not start it early."
},
{
"type": "tool_call",
"toolName": "complete_task",
"content": "{\"task_id\":\"task_examples\"}",
"annotation": "Completing the examples unblocks the dependent test task."
},
{
"type": "system_event",
"content": "claim_next_task(bob) -> task_tests; task_lock commits owner=bob",
"annotation": "Bob claims the newly ready work without another direct assignment."
"type": "assistant_text",
"content": "The docs server found three matches for deployment guidance.",
"annotation": "The agent summarizes external tool output for the user."
}
]
}

View File

@@ -1,45 +1,97 @@
{
"version": "s17",
"title": "Worktree Isolation",
"description": "A task can be bound to an isolated git worktree so concurrent agents avoid stepping on each other.",
"title": "Integrated Harness",
"description": "The harness composes context assembly, tools, memory, teams, background work, cron, worktrees, and MCP.",
"steps": [
{
"type": "user_message",
"content": "Update the docs and parser in parallel without letting the changes interfere.",
"annotation": "Concurrent edits need isolated working directories."
"content": "Prepare this project for release. Check the code, update the docs, and report deployment readiness.",
"annotation": "One ordinary request needs several earlier capabilities to work together."
},
{
"type": "system_event",
"content": "assemble_prompt: memory + task graph + skills + available tools + policy",
"annotation": "The runtime builds the prompt from layered sources of context."
},
{
"type": "assistant_text",
"content": "I suggest a docs teammate while I run the release checks and inspect deployment status. Shall I start that team?",
"annotation": "The Lead proposes the team before adding another persistent agent."
},
{
"type": "user_message",
"content": "Yes. Start the docs teammate and continue.",
"annotation": "User confirmation opens the team boundary inherited from S15."
},
{
"type": "tool_call",
"toolName": "load_skill",
"content": "{\"name\":\"code-review\"}",
"annotation": "Skills contribute procedural context before execution."
},
{
"type": "tool_call",
"toolName": "create_task",
"content": "{\"subject\":\"Update release notes\",\"description\":\"Prepare release documentation and report the result.\"}",
"annotation": "The shared task board gives the docs work a stable owner and lifecycle."
},
{
"type": "tool_result",
"toolName": "create_task",
"content": "Created task_1712345678_0042: Update release notes",
"annotation": "The task ID connects the assignment to its working directory."
},
{
"type": "tool_call",
"toolName": "create_worktree",
"content": "{\"task_id\":\"task_docs\",\"name\":\"docs-fix\"}",
"annotation": "The tool validates a safe worktree name before touching git."
},
{
"type": "system_event",
"content": "git worktree add .worktrees/docs-fix -b agent/docs-fix",
"annotation": "A separate branch and checkout are created for that task."
"content": "{\"name\":\"release-docs\",\"task_id\":\"task_1712345678_0042\"}",
"annotation": "The pending docs task receives a separate checkout before it is claimed."
},
{
"type": "tool_result",
"toolName": "create_worktree",
"content": "task_docs bound to .worktrees/docs-fix",
"annotation": "The task record stores the assigned worktree path."
},
{
"type": "system_event",
"content": ".worktrees/events.jsonl <- {event:\"created\", task:\"task_docs\", worktree:\"docs-fix\"}",
"annotation": "Lifecycle events are emitted as a side channel."
"content": "Worktree 'release-docs' created for task_1712345678_0042",
"annotation": "The task now carries the checkout used by its eventual owner."
},
{
"type": "tool_call",
"toolName": "keep_worktree",
"content": "{\"task_id\":\"task_docs\",\"reason\":\"needs human review\"}",
"annotation": "Closeout can preserve a worktree instead of deleting it immediately."
"toolName": "spawn_teammate",
"content": "{\"name\":\"docs\",\"role\":\"documentation engineer\",\"prompt\":\"Claim task_1712345678_0042, update the release notes in its task-bound worktree, and report the result.\"}",
"annotation": "Team delegation handles a parallel slice of the release."
},
{
"type": "tool_call",
"toolName": "bash",
"content": "{\"command\":\"npm run lint && npm run test\",\"run_in_background\":true}",
"annotation": "Long-running validation goes through the background task path."
},
{
"type": "tool_call",
"toolName": "connect_mcp",
"content": "{\"name\":\"deploy\"}",
"annotation": "External capabilities are added only when needed."
},
{
"type": "tool_call",
"toolName": "mcp__deploy__status",
"content": "{\"service\":\"web\"}",
"annotation": "Connecting discovers the tool; a separate call performs the status check."
},
{
"type": "tool_result",
"toolName": "mcp__deploy__status",
"content": "[deploy] web: running (v1.4.2)",
"annotation": "The readiness statement now comes from the MCP tool result rather than the connection event."
},
{
"type": "system_event",
"content": "recover: background task done, teammate replied, deploy status result appended",
"annotation": "The integrated runtime folds asynchronous results back into the loop."
},
{
"type": "assistant_text",
"content": "The docs task now has an isolated worktree and can be reviewed independently from parser changes.",
"annotation": "The user sees the isolation boundary, not just a raw git command."
"content": "Release preparation is ready: checks passed, docs are updated in the teammate worktree, and deployment status is available.",
"annotation": "The integrated harness returns a single user-facing outcome."
}
]
}

View File

@@ -1,46 +1,54 @@
{
"version": "s18",
"title": "MCP Tools",
"description": "The agent discovers external MCP tools and exposes them through a normalized tool namespace.",
"title": "Workflow Runtime",
"description": "A fixed review pipeline executes inside one Workflow call, records a journal, emits lifecycle and progress events, and returns one final tool result.",
"steps": [
{
"type": "user_message",
"content": "Search the documentation for deployment guidance.",
"annotation": "The user asks for a tool source outside the built-in set."
"content": "Review this change across correctness, security, performance, and style.",
"annotation": "The goal is open-ended, but the review procedure has a fixed shape."
},
{
"type": "tool_call",
"toolName": "connect_mcp",
"content": "{\"server\":\"docs\",\"command\":\"mock-docs-server\"}",
"annotation": "The runtime creates an MCP client for the named server."
"toolName": "Workflow",
"content": "{\"name\":\"review-changes\",\"description\":\"Review changed files across dimensions and verify each finding\",\"phases\":[\"Review\",\"Verify\"]}",
"annotation": "One tool call hands deterministic orchestration to the workflow runtime."
},
{
"type": "system_event",
"content": "normalize_mcp_name(\"docs\", \"search\") -> mcp__docs__search",
"annotation": "External tools are namespaced to avoid collisions."
"content": "async_launched(runId=wf_review-changes_6779) -> task_started",
"annotation": "The runtime emits launch lifecycle events before it executes the script; this is not a tool result."
},
{
"type": "system_event",
"content": "phase=Review -> pipeline([correctness, security, performance, style])",
"annotation": "Each item advances independently through the scripted stages."
},
{
"type": "system_event",
"content": "phase=Verify -> adversarial checks run in parallel",
"annotation": "Structured results cross a validation boundary before aggregation."
},
{
"type": "system_event",
"content": "workflow_agent status=done -> journal append",
"annotation": "Every completed agent call is checkpointed as the script runs."
},
{
"type": "system_event",
"content": "task_notification(status=completed, outputFile=.runtime/wf_review-changes_6779.output.json)",
"annotation": "The task emits its final lifecycle event after output is written."
},
{
"type": "tool_result",
"toolName": "connect_mcp",
"content": "Connected docs with tools: mcp__docs__search, mcp__docs__read",
"annotation": "Tool discovery expands the active tool pool."
"toolName": "Workflow",
"content": "{\"launched\":{\"status\":\"async_launched\",\"runId\":\"wf_review-changes_6779\"},\"result\":{\"confirmed\":[]},\"task\":{\"status\":\"completed\"}}",
"annotation": "The completed call returns once, with launch metadata, the workflow result, and task state together."
},
{
"type": "tool_call",
"toolName": "mcp__docs__search",
"content": "{\"query\":\"deployment\"}",
"annotation": "The LLM can now call the discovered tool by its normalized name."
},
{
"type": "tool_result",
"toolName": "mcp__docs__search",
"content": "[\"Deploy with npm run build\", \"Use environment variables for tokens\"]",
"annotation": "The external result is appended like any other tool result."
},
{
"type": "assistant_text",
"content": "The docs server says to build first and keep tokens in environment variables.",
"annotation": "The agent summarizes external tool output for the user."
"type": "system_event",
"content": "append Workflow tool_result -> messages[]",
"annotation": "The main loop receives that single result and continues with the updated conversation."
}
]
}

View File

@@ -1,57 +1,49 @@
{
"version": "s19",
"title": "Integrated Harness",
"description": "The harness composes context assembly, tools, memory, teams, background work, cron, worktrees, and MCP.",
"title": "Goal Loop",
"description": "A separate evaluator reads the conversation at the end of a turn and sends unfinished work back through the same loop.",
"steps": [
{
"type": "user_message",
"content": "Prepare this project for release. Check the code, update the docs, and report deployment readiness.",
"annotation": "One ordinary request needs several earlier capabilities to work together."
},
{
"type": "system_event",
"content": "assemble_prompt: memory + task graph + skills + available tools + policy",
"annotation": "The runtime builds the prompt from layered sources of context."
"content": "/goal pytest tests/auth exits with code 0",
"annotation": "The command stores an active completion condition and starts the work."
},
{
"type": "assistant_text",
"content": "I'll inspect the task graph, delegate docs, start the slow scan in the background, and use the release checklist skill.",
"annotation": "The model chooses multiple mechanisms while keeping one coherent plan."
"content": "The authentication code looks correct. The tests should pass now.",
"annotation": "With no more tool calls, the session asks the evaluator whether the active goal is complete."
},
{
"type": "tool_call",
"toolName": "load_skill",
"content": "{\"name\":\"release-check\"}",
"annotation": "Skills contribute procedural context before execution."
"type": "system_event",
"content": "goal_evaluated ok=false -> block",
"annotation": "The evaluator finds no test exit code in the conversation."
},
{
"type": "tool_call",
"toolName": "spawn_teammate",
"content": "{\"name\":\"docs\",\"role\":\"Update release notes in its worktree.\"}",
"annotation": "Team delegation handles a parallel slice of the release."
"type": "system_event",
"content": "[Goal still active] Run pytest tests/auth and surface the exit code.",
"annotation": "The controller appends the reason to messages[] and continues the same loop; no queue is involved."
},
{
"type": "tool_call",
"toolName": "bash",
"content": "npm run lint && npm run test",
"toolInput": "{\"background\":true}",
"annotation": "Long-running validation goes through the background task path."
"content": "pytest tests/auth",
"annotation": "The next agent turn runs the missing check."
},
{
"type": "tool_call",
"toolName": "connect_mcp",
"content": "{\"server\":\"deploy\",\"command\":\"mock-deploy-server\"}",
"annotation": "External capabilities are added only when needed."
},
{
"type": "system_event",
"content": "recover: background task done, teammate replied, MCP deploy status ready",
"annotation": "The integrated runtime folds asynchronous results back into the loop."
"type": "tool_result",
"toolName": "bash",
"content": "exit_code=0\n12 passed in 0.42s",
"annotation": "The concrete command result enters the same conversation."
},
{
"type": "assistant_text",
"content": "Release preparation is ready: checks passed, docs are updated in the teammate worktree, and deployment status is available.",
"annotation": "The integrated harness returns a single user-facing outcome."
"content": "pytest tests/auth exited 0: 12 tests passed.",
"annotation": "A turn with no further tool call reaches the Stop hook again."
},
{
"type": "system_event",
"content": "goal_evaluated ok=true -> achieved",
"annotation": "The controller records success, clears the active goal, and returns."
}
]
}

View File

@@ -1,43 +0,0 @@
{
"version": "s20",
"title": "Workflow Runtime",
"description": "A fixed review pipeline runs in parallel, records a journal, and resumes completed agent calls from cache.",
"steps": [
{
"type": "user_message",
"content": "Review this change across correctness, security, performance, and style.",
"annotation": "The goal is open-ended, but the review procedure has a fixed shape."
},
{
"type": "tool_call",
"toolName": "Workflow",
"content": "{\"name\":\"review-changes\",\"phases\":[\"Review\",\"Verify\"]}",
"annotation": "One tool call hands deterministic orchestration to the workflow runtime."
},
{
"type": "tool_result",
"content": "{\"status\":\"async_launched\",\"runId\":\"wf_review-changes_6779\"}",
"annotation": "The product runtime returns a claim ticket while work continues in the background."
},
{
"type": "system_event",
"content": "phase=Review -> pipeline([correctness, security, performance, style])",
"annotation": "Each item advances independently through the scripted stages."
},
{
"type": "system_event",
"content": "phase=Verify -> adversarial checks run in parallel",
"annotation": "Structured results cross a validation boundary before aggregation."
},
{
"type": "system_event",
"content": "journal append -> task_notification(status=completed)",
"annotation": "Every completed agent call is checkpointed before the final notification."
},
{
"type": "system_event",
"content": "resumeFromRunId -> unchanged calls status=cached",
"annotation": "Semantic keys reuse completed work without depending on concurrency order."
}
]
}

View File

@@ -1,37 +0,0 @@
{
"version": "s21",
"title": "Goal Loop",
"description": "A host-owned completion gate keeps the turn alive until trusted evidence satisfies the active goal.",
"steps": [
{
"type": "user_message",
"content": "/goal until tests passed and deploy green",
"annotation": "The command defines the condition but sits outside the evidence window."
},
{
"type": "system_event",
"content": "goal_started -> evidence window reset",
"annotation": "The harness, not the working model, owns the completion gate."
},
{
"type": "assistant_text",
"content": "Tests passed and deployment is green.",
"annotation": "Assistant prose is not trusted completion evidence."
},
{
"type": "system_event",
"content": "goal_evaluated satisfied=false -> continuation queued",
"annotation": "An unmet condition pushes the loop into another bounded turn."
},
{
"type": "tool_result",
"content": "<task_notification>tests passed; deploy green</task_notification>",
"annotation": "Only an allowlisted host event can attach a trusted evidence origin."
},
{
"type": "system_event",
"content": "goal_evaluated satisfied=true -> goal_completed",
"annotation": "Trusted evidence closes the goal and releases the stop gate."
}
]
}

View File

@@ -1,10 +1,10 @@
{
"meta": { "title": "Learn Claude Code", "description": "Build a nano Claude Code-like agent from 0 to 1, one mechanism at a time" },
"nav": { "home": "Home", "timeline": "Timeline", "compare": "Compare", "layers": "Layers", "github": "GitHub" },
"home": { "hero_title": "Learn Claude Code", "hero_subtitle": "Build a nano Claude Code-like agent from 0 to 1, one mechanism at a time", "start": "Start Learning", "core_pattern": "The Core Pattern", "core_pattern_desc": "Every AI coding agent shares the same loop: call the model, execute tools, feed results back. The harness adds policy, permissions, memory, coordination, and lifecycle control around it.", "learning_path": "Learning Path", "learning_path_desc": "21 progressive sessions, from a simple loop to deterministic orchestration and goal closure", "layers_title": "Architectural Layers", "layers_desc": "Five orthogonal concerns that compose into a complete agent", "loc": "LOC", "learn_more": "Learn More", "versions_in_layer": "versions", "message_flow": "Message Growth", "message_flow_desc": "Watch the messages array grow as the agent loop executes" },
"home": { "hero_title": "Learn Claude Code", "hero_subtitle": "Build a nano Claude Code-like agent from 0 to 1, one mechanism at a time", "start": "Start Learning", "core_pattern": "The Core Pattern", "core_pattern_desc": "Every AI coding agent shares the same loop: call the model, execute tools, feed results back. The harness adds policy, permissions, memory, coordination, and lifecycle control around it.", "learning_path": "Learning Path", "learning_path_desc": "19 progressive sessions, from a simple loop to deterministic orchestration and goal closure", "layers_title": "Architectural Layers", "layers_desc": "Five orthogonal concerns that compose into a complete agent", "loc": "LOC", "learn_more": "Learn More", "versions_in_layer": "versions", "message_flow": "Message Growth", "message_flow_desc": "Watch the messages array grow as the agent loop executes" },
"version": { "loc": "lines of code", "tools": "tools", "new": "New", "prev": "Previous", "next": "Next", "view_source": "View Source", "view_diff": "View Diff", "design_decisions": "Design Decisions", "whats_new": "What's New", "tutorial": "Tutorial", "simulator": "Agent Loop Simulator", "execution_flow": "Execution Flow", "architecture": "Architecture", "concept_viz": "Concept Visualization", "alternatives": "Alternatives Considered", "tab_learn": "Learn", "tab_simulate": "Simulate", "tab_code": "Code", "tab_deep_dive": "Deep Dive" },
"sim": { "play": "Play", "pause": "Pause", "step": "Step", "reset": "Reset", "speed": "Speed", "step_of": "of" },
"timeline": { "title": "Learning Path", "subtitle": "s01 to s21: Progressive Agent Harness Design", "layer_legend": "Layer Legend", "loc_growth": "LOC Growth", "learn_more": "Learn More" },
"timeline": { "title": "Learning Path", "subtitle": "s01 to s19: Progressive Agent Harness Design", "layer_legend": "Layer Legend", "loc_growth": "LOC Growth", "learn_more": "Learn More" },
"layers": {
"title": "Architectural Layers",
"subtitle": "Five orthogonal concerns that compose into a complete agent",
@@ -12,7 +12,7 @@
"planning": "How work is organized. From simple todo lists to dependency-aware task boards shared across agents.",
"memory": "Keeping context within limits. Compression strategies that let agents work infinitely without losing coherence.",
"concurrency": "Non-blocking execution. Background threads and notification buses for parallel work.",
"collaboration": "Multi-agent coordination. Teams, messaging, and autonomous teammates that think for themselves."
"collaboration": "Multi-agent coordination. Teams, messaging, atomic task claims, and task-bound worktree directories."
},
"compare": {
"title": "Compare Versions",
@@ -53,13 +53,11 @@
"s12": "Task System",
"s13": "Background Tasks",
"s14": "Cron Scheduler",
"s15": "Agent Teams",
"s16": "Autonomous Agents",
"s17": "Worktree Isolation",
"s18": "MCP Tools",
"s19": "Integrated Harness",
"s20": "Workflow Runtime",
"s21": "Goal Loop"
"s15": "Agent Team Runtime",
"s16": "MCP Tools",
"s17": "Integrated Harness",
"s18": "Workflow Runtime",
"s19": "Goal Loop"
},
"layer_labels": {
"tools": "Tools & Execution",
@@ -83,12 +81,10 @@
"s12": "Task Board Dependencies",
"s13": "Background Task Lanes",
"s14": "Cron Scheduler",
"s15": "Agent Teams and Protocols",
"s16": "Autonomous Agent Cycle",
"s17": "Worktree Task Isolation",
"s18": "MCP Tool Bridge",
"s19": "Integrated Harness Turn",
"s20": "Workflow Runtime",
"s21": "Goal Completion Gate"
"s15": "Team Runtime: Message, Claim, Bind",
"s16": "MCP Tool Bridge",
"s17": "Integrated Harness Turn",
"s18": "Workflow Runtime",
"s19": "Goal Completion Gate"
}
}

View File

@@ -1,10 +1,10 @@
{
"meta": { "title": "Learn Claude Code", "description": "0 から 1 へ nano Claude Code-like agent を構築し、毎回 1 つの仕組みを追加" },
"nav": { "home": "ホーム", "timeline": "学習パス", "compare": "バージョン比較", "layers": "アーキテクチャ層", "github": "GitHub" },
"home": { "hero_title": "Learn Claude Code", "hero_subtitle": "0 から 1 へ nano Claude Code-like agent を構築し、毎回 1 つの仕組みを追加", "start": "学習を始める", "core_pattern": "コアパターン", "core_pattern_desc": "すべての AI コーディングエージェントは同じループを共有するモデルを呼び出し、ツールを実行し、結果を返す。Harness はその周囲にポリシー、権限、記憶、協調、ライフサイクル制御を加える。", "learning_path": "学習パス", "learning_path_desc": "21の段階的セッション、シンプルなループから決定的な編成と目標完了まで", "layers_title": "アーキテクチャ層", "layers_desc": "5つの直交する関心事が完全なエージェントを構成", "loc": "行", "learn_more": "詳細を見る", "versions_in_layer": "バージョン", "message_flow": "メッセージの増加", "message_flow_desc": "エージェントループ実行時のメッセージ配列の成長を観察" },
"home": { "hero_title": "Learn Claude Code", "hero_subtitle": "0 から 1 へ nano Claude Code-like agent を構築し、毎回 1 つの仕組みを追加", "start": "学習を始める", "core_pattern": "コアパターン", "core_pattern_desc": "すべての AI コーディングエージェントは同じループを共有するモデルを呼び出し、ツールを実行し、結果を返す。Harness はその周囲にポリシー、権限、記憶、協調、ライフサイクル制御を加える。", "learning_path": "学習パス", "learning_path_desc": "19の段階的セッション、シンプルなループから決定的な編成と目標完了まで", "layers_title": "アーキテクチャ層", "layers_desc": "5つの直交する関心事が完全なエージェントを構成", "loc": "行", "learn_more": "詳細を見る", "versions_in_layer": "バージョン", "message_flow": "メッセージの増加", "message_flow_desc": "エージェントループ実行時のメッセージ配列の成長を観察" },
"version": { "loc": "行のコード", "tools": "ツール", "new": "新規", "prev": "前のバージョン", "next": "次のバージョン", "view_source": "ソースを見る", "view_diff": "差分を見る", "design_decisions": "設計判断", "whats_new": "新機能", "tutorial": "チュートリアル", "simulator": "エージェントループシミュレーター", "execution_flow": "実行フロー", "architecture": "アーキテクチャ", "concept_viz": "コンセプト可視化", "alternatives": "検討された代替案", "tab_learn": "学習", "tab_simulate": "シミュレーション", "tab_code": "ソースコード", "tab_deep_dive": "詳細分析" },
"sim": { "play": "再生", "pause": "一時停止", "step": "ステップ", "reset": "リセット", "speed": "速度", "step_of": "/" },
"timeline": { "title": "学習パス", "subtitle": "s01からs21へ段階的エージェント Harness 設計", "layer_legend": "レイヤー凡例", "loc_growth": "コード量の推移", "learn_more": "詳細を見る" },
"timeline": { "title": "学習パス", "subtitle": "s01からs19へ:段階的エージェント Harness 設計", "layer_legend": "レイヤー凡例", "loc_growth": "コード量の推移", "learn_more": "詳細を見る" },
"layers": {
"title": "アーキテクチャ層",
"subtitle": "5つの直交する関心事が完全なエージェントを構成",
@@ -12,7 +12,7 @@
"planning": "作業の組織化。シンプルなToDoリストからエージェント間で共有される依存関係対応タスクボードまで。",
"memory": "コンテキスト制限内での記憶保持。圧縮戦略によりエージェントが一貫性を失わずに無限に作業可能。",
"concurrency": "ノンブロッキング実行。バックグラウンドスレッドと通知バスによる並列作業。",
"collaboration": "マルチエージェント連携。チーム、メッセージング、自律的に考えるチームメイト。"
"collaboration": "マルチエージェント連携。チーム、メッセージング、原子的なタスク認領、タスクに紐付く worktree ディレクトリ。"
},
"compare": {
"title": "バージョン比較",
@@ -53,13 +53,11 @@
"s12": "タスクシステム",
"s13": "バックグラウンドタスク",
"s14": "Cron スケジューラー",
"s15": "Agent Teams",
"s16": "自律エージェント",
"s17": "Worktree 分離",
"s18": "MCP ツール",
"s19": "Integrated Harness",
"s20": "Workflow Runtime",
"s21": "Goal Loop"
"s15": "Agent Team Runtime",
"s16": "MCP ツール",
"s17": "Integrated Harness",
"s18": "Workflow Runtime",
"s19": "Goal Loop"
},
"layer_labels": {
"tools": "ツールと実行",
@@ -83,12 +81,10 @@
"s12": "タスクボード依存関係",
"s13": "バックグラウンドタスクレーン",
"s14": "Cron スケジューラー",
"s15": "Agent Teams と協調プロトコル",
"s16": "自律エージェントサイクル",
"s17": "Worktree タスク分離",
"s18": "MCP ツールブリッジ",
"s19": "Integrated Harness のターン",
"s20": "Workflow Runtime",
"s21": "目標完了ゲート"
"s15": "Team Runtimeメッセージ・認領・ディレクトリ紐付け",
"s16": "MCP ツールブリッジ",
"s17": "Integrated Harness のターン",
"s18": "Workflow Runtime",
"s19": "目標完了ゲート"
}
}

View File

@@ -1,10 +1,10 @@
{
"meta": { "title": "Learn Claude Code", "description": "从 0 到 1 构建 nano Claude Code-like agent每次只加一个机制" },
"nav": { "home": "首页", "timeline": "学习路径", "compare": "版本对比", "layers": "架构层", "github": "GitHub" },
"home": { "hero_title": "Learn Claude Code", "hero_subtitle": "从 0 到 1 构建 nano Claude Code-like agent每次只加一个机制", "start": "开始学习", "core_pattern": "核心模式", "core_pattern_desc": "所有 AI 编程 Agent 共享同一个循环调用模型、执行工具、回传结果。Harness 在循环周围加入策略、权限、记忆、协作与生命周期控制。", "learning_path": "学习路径", "learning_path_desc": "21 个渐进式课程,从简单循环到确定性编排与目标闭环", "layers_title": "架构层次", "layers_desc": "五个正交关注点组合成完整的 Agent", "loc": "行", "learn_more": "了解更多", "versions_in_layer": "个版本", "message_flow": "消息增长", "message_flow_desc": "观察 Agent 循环执行时消息数组的增长" },
"home": { "hero_title": "Learn Claude Code", "hero_subtitle": "从 0 到 1 构建 nano Claude Code-like agent每次只加一个机制", "start": "开始学习", "core_pattern": "核心模式", "core_pattern_desc": "所有 AI 编程 Agent 共享同一个循环调用模型、执行工具、回传结果。Harness 在循环周围加入策略、权限、记忆、协作与生命周期控制。", "learning_path": "学习路径", "learning_path_desc": "19 个渐进式课程,从简单循环到确定性编排与目标闭环", "layers_title": "架构层次", "layers_desc": "五个正交关注点组合成完整的 Agent", "loc": "行", "learn_more": "了解更多", "versions_in_layer": "个版本", "message_flow": "消息增长", "message_flow_desc": "观察 Agent 循环执行时消息数组的增长" },
"version": { "loc": "行代码", "tools": "个工具", "new": "新增", "prev": "上一版", "next": "下一版", "view_source": "查看源码", "view_diff": "查看变更", "design_decisions": "设计决策", "whats_new": "新增内容", "tutorial": "教程", "simulator": "Agent 循环模拟器", "execution_flow": "执行流程", "architecture": "架构", "concept_viz": "概念可视化", "alternatives": "替代方案", "tab_learn": "学习", "tab_simulate": "模拟", "tab_code": "源码", "tab_deep_dive": "深入探索" },
"sim": { "play": "播放", "pause": "暂停", "step": "单步", "reset": "重置", "speed": "速度", "step_of": "/" },
"timeline": { "title": "学习路径", "subtitle": "s01 到 s21渐进式 Agent Harness 设计", "layer_legend": "层次图例", "loc_growth": "代码量增长", "learn_more": "了解更多" },
"timeline": { "title": "学习路径", "subtitle": "s01 到 s19:渐进式 Agent Harness 设计", "layer_legend": "层次图例", "loc_growth": "代码量增长", "learn_more": "了解更多" },
"layers": {
"title": "架构层次",
"subtitle": "五个正交关注点组合成完整的 Agent",
@@ -12,7 +12,7 @@
"planning": "如何组织工作。从简单的待办列表到跨 Agent 共享的依赖感知任务板。",
"memory": "在上下文限制内保持记忆。压缩策略让 Agent 可以无限工作而不失去连贯性。",
"concurrency": "非阻塞执行。后台线程和通知总线实现并行工作。",
"collaboration": "多 Agent 协作。团队、消息传递和能独立思考的自主队友。"
"collaboration": "多 Agent 协作。团队、消息传递、原子任务认领与任务绑定的 worktree 目录。"
},
"compare": {
"title": "版本对比",
@@ -53,13 +53,11 @@
"s12": "Task System",
"s13": "Background Tasks",
"s14": "Cron Scheduler",
"s15": "Agent Teams",
"s16": "Autonomous Agents",
"s17": "Worktree Isolation",
"s18": "MCP Tools",
"s19": "Agent Harness 集成",
"s20": "Workflow Runtime",
"s21": "Goal Loop"
"s15": "Agent Team Runtime",
"s16": "MCP Tools",
"s17": "Agent Harness 集成",
"s18": "Workflow Runtime",
"s19": "Goal Loop"
},
"layer_labels": {
"tools": "工具与执行",
@@ -83,12 +81,10 @@
"s12": "任务看板依赖",
"s13": "Background Task Lanes",
"s14": "Cron Scheduler",
"s15": "Agent Teams 与协作协议",
"s16": "Autonomous Agent Cycle",
"s17": "Worktree Task Isolation",
"s18": "MCP Tool Bridge",
"s19": "Agent Harness 集成流程",
"s20": "Workflow Runtime",
"s21": "目标完成闸门"
"s15": "团队运行时:消息、认领与目录绑定",
"s16": "MCP Tool Bridge",
"s17": "Agent Harness 集成流程",
"s18": "Workflow Runtime",
"s19": "目标完成闸门"
}
}

View File

@@ -20,8 +20,6 @@ export const VERSION_ORDER = [
"s17",
"s18",
"s19",
"s20",
"s21",
] as const;
export const LEARNING_PATH = VERSION_ORDER;
@@ -149,60 +147,44 @@ export const VERSION_META: Record<string, {
prevVersion: "s13",
},
s15: {
title: "Agent Teams",
subtitle: "Persistent Teammates and Coordination Protocols",
coreAddition: "Team runtime and typed protocols",
keyInsight: "A Lead can coordinate persistent teammates when message delivery, approval, and shutdown belong to the runtime.",
title: "Agent Team Runtime",
subtitle: "Persistent Teammates, Atomic Claims, Task-Bound Worktrees",
coreAddition: "Team runtime with task-bound worktrees",
keyInsight: "Persistent teammates can reliably discover and execute parallel work when the runtime owns messaging, atomic claims, and task-bound working directories.",
layer: "collaboration",
prevVersion: "s14",
},
s16: {
title: "Autonomous Agents",
subtitle: "Check the Board, Claim the Task",
coreAddition: "Autonomous task claiming",
keyInsight: "Idle teammates can discover ready work when claiming is atomic and respects task dependencies.",
layer: "collaboration",
prevVersion: "s15",
},
s17: {
title: "Worktree Isolation",
subtitle: "Separate Directories, No Conflicts",
coreAddition: "Worktree lifecycle",
keyInsight: "Parallel agents need isolated filesystems as much as isolated conversations.",
layer: "collaboration",
prevVersion: "s16",
},
s18: {
title: "MCP Tools",
subtitle: "External Tools, Standard Protocol",
coreAddition: "MCP tool bridge",
keyInsight: "External services can become agent tools through a standard discovery and call protocol.",
layer: "collaboration",
prevVersion: "s17",
prevVersion: "s15",
},
s19: {
s17: {
title: "Integrated Harness",
subtitle: "Many Mechanisms, One Loop",
coreAddition: "Integrated harness",
keyInsight: "The integrated harness is still one loop, surrounded by the systems introduced across the course.",
layer: "collaboration",
prevVersion: "s18",
prevVersion: "s16",
},
s20: {
s18: {
title: "Workflow Runtime",
subtitle: "Scripts Own Fixed Orchestration",
coreAddition: "Resumable workflow runtime",
keyInsight: "When orchestration has a fixed shape, code can make it parallel, deterministic, and resumable.",
layer: "concurrency",
prevVersion: "s19",
prevVersion: "s17",
},
s21: {
s19: {
title: "Goal Loop",
subtitle: "Trusted Evidence Decides When to Stop",
subtitle: "Independent Evaluation Decides When to Stop",
coreAddition: "Goal completion gate",
keyInsight: "A durable goal keeps the loop working until trusted evidence satisfies an explicit condition.",
keyInsight: "A durable goal keeps the loop working until an independent evaluator finds the completion condition satisfied in the conversation.",
layer: "planning",
prevVersion: "s20",
prevVersion: "s18",
},
};
@@ -217,7 +199,7 @@ export const LAYERS = [
id: "planning" as const,
label: "Planning & Control",
color: "#10B981",
versions: ["s05", "s06", "s07", "s10", "s11", "s21"],
versions: ["s05", "s06", "s07", "s10", "s11", "s19"],
},
{
id: "memory" as const,
@@ -229,12 +211,12 @@ export const LAYERS = [
id: "concurrency" as const,
label: "Concurrency & Scheduling",
color: "#F59E0B",
versions: ["s13", "s14", "s20"],
versions: ["s13", "s14", "s18"],
},
{
id: "collaboration" as const,
label: "Multi-Agent Platform",
color: "#EF4444",
versions: ["s12", "s15", "s16", "s17", "s18", "s19"],
versions: ["s12", "s15", "s16", "s17"],
},
] as const;