From 9a636eb808b24e1470b4c7e1a3b93c9d8a1fb58f Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 09:20:41 +0000 Subject: [PATCH 1/5] fix(server): agents resume an interrupted delegate instead of replacing it The injected orchestration rule said every delegate review or re-check is a new delegate_task, never a t3_thread_send, with no exception for unfinished work. A parent asked to continue an interrupted review child started a replacement and steered that instead. The rule now says t3_thread_send is what resumes an interrupted delegate, and an eval case covers the report. AI-assisted; verified with the tests and tools listed above. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/provider/agentContextBudget.json | 4 ++-- evals/mcp-tool-use/cases/orchestration.ndjson | 1 + .../provider-core/src/server/orchestrationInstructions.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index 486c4314927ad..8ff44ac2d8b9d 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5597, - "codexAdditionalContextBytes": 7327, + "claudeSystemAppendBytes": 5616, + "codexAdditionalContextBytes": 7346, "mcpToolListJsonBytes": 48131 } diff --git a/evals/mcp-tool-use/cases/orchestration.ndjson b/evals/mcp-tool-use/cases/orchestration.ndjson index 520bd2abf10d3..aa2b83d2ded3a 100644 --- a/evals/mcp-tool-use/cases/orchestration.ndjson +++ b/evals/mcp-tool-use/cases/orchestration.ndjson @@ -1,6 +1,7 @@ {"id": "review-round-uses-thread-send", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId", "experience": "Round 2 of a Sol review went to the round 1 childThreadId with t3_thread_send. The user: 'Use delegate_task please, this should not be a separate thread.'", "rule": "For every T3 delegated review round, call delegate_task again ... Do not use t3_thread_send on childThreadId to continue a delegated review.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123). Loop until it approves."}, {"role": "assistant", "text": "Sol round 1 is back with two findings. Both are real. Fixing them now.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review round 1", "mode": "async", "clientRequestId": "sol-review-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. S1: the cache decoder drops v4 entries, so saved usage for deleted files is lost. S2: two app versions share one cache file and overwrite each other."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Both are fixed in commit af85f8c. Run round 2 of the Sol review.", "expect": {"calls": [{"tool": "delegate_task", "args": {"target.model": "gpt-6.1-sol", "task": "~cache"}}], "notCalls": ["t3_thread_send"]}, "notes": "Real cause was a sol-loop skill that said to reuse the thread. The case leaves the skill out. 'task' must carry the prior findings (both mention the cache)."} {"id": "review-followup-ask-sol-to-confirm", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId", "experience": "After fixing a Sol finding, the agent sent 'Round 2' to the same Sol child thread instead of a new delegate_task.", "rule": "For every T3 delegated review round, call delegate_task again. Include the original brief, prior findings, responses ...", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Restore mod+enter as the default for sending a thread to the background. Get a Sol review before you file it."}, {"role": "assistant", "text": "Sol found one real issue (S1): the startup migration resets a user's later choice of mod+alt+enter back to mod+enter on every launch. I agree. Working on a fix.", "toolCalls": [{"tool": "Edit", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/web/src/keybindings.ts", "old_string": "\"mod+alt+enter\"", "new_string": "\"mod+enter\""}, "result": "The file /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/web/src/keybindings.ts has been updated successfully."}, {"tool": "Bash", "input": {"command": "pnpm vitest run apps/web/src/keybindings.test.ts"}, "result": " Test Files 1 passed (1)\n Tests 6 passed (6)"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"fix(web): restore mod+enter as the default background send\""}, "result": "[fix/mod-enter-background 7b3a1f0] fix(web): restore mod+enter as the default background send\n 2 files changed"}, {"tool": "delegate_task", "input": {"title": "Sol review: restore mod+enter background send", "role": "review", "mode": "async", "clientRequestId": "sol-bg-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the keybinding default change and its config migration on this branch. Read only. Report findings as S1, S2, ..."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. S1: the migration runs on every startup, so a user who picks mod+alt+enter again is reset to mod+enter."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, "world": {"branch": "fix/mod-enter-background", "commits": [{"sha": "c41d9e2", "subject": "fix(web): run the shortcut migration once with a marker file"}, {"sha": "7b3a1f0", "subject": "fix(web): restore mod+enter as the default background send"}], "diff": "diff --git a/apps/web/src/keybindingsMigration.ts b/apps/web/src/keybindingsMigration.ts\n--- a/apps/web/src/keybindingsMigration.ts\n+++ b/apps/web/src/keybindingsMigration.ts\n@@ -10,1 +10,3 @@\n- return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n+ if (existsSync(markerPath)) return settings;\n+ writeFileSync(markerPath, \"done\");\n+ return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n", "files": {"apps/web/src/keybindings.ts": "export const DEFAULT_BINDINGS = {\n \"thread.sendToBackground\": \"mod+enter\",\n};\n", "apps/web/src/keybindingsMigration.ts": "import { existsSync, writeFileSync } from \"node:fs\";\n\n// Runs once: the marker file stops it from resetting a later user choice.\nexport function migrateBackgroundSend(settings: Settings, markerPath: string) {\n if (existsSync(markerPath)) return settings;\n writeFileSync(markerPath, \"done\");\n return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n}\n"}}}, "prompt": "Fixed it with a run-once marker file, and the new test fails without the marker. Ask Sol to confirm the fix.", "expect": {"calls": [{"tool": "delegate_task", "args": {"target.model": "gpt-6.1-sol", "task": "~migration"}}], "notCalls": ["t3_thread_send"]}, "notes": "Pressure variant: 'Ask Sol to confirm' reads like continuing a conversation with the same reviewer."} {"id": "stale-review-not-cancelled-on-ship", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId; no task_cancel", "experience": "The user said 'use delegate task for sol please. I'm sure this is fine just file the pr and babysit already'. The agent filed the PR but left the round 2 run in the child thread going.", "rule": "task_cancel: Stop a T3-owned delegated task ... This includes later child-thread runs, even after the task is terminal.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Build a server-side PR watcher. Make changes, get a Sol review, then file the PR."}, {"role": "assistant", "text": "Sol round 1 found 1 blocker and 5 smaller issues. All six are fixed. Round 2 is running in the same Sol thread.", "toolCalls": [{"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts", "content": "const POLL_MS = 120_000;\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub) {\n const timers = new Map();\n const poll = async (url: string) => {\n const state = await github.readPullRequest(url);\n if (state.changed) prs.wake(url, state);\n };\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), POLL_MS));\n },\n stop(url: string) {\n clearInterval(timers.get(url));\n timers.delete(url);\n },\n };\n}\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"feat(server): watch linked pull requests on the server\""}, "result": "[feat/pr-watcher 3c9e1d2] feat(server): watch linked pull requests on the server\n 3 files changed"}, {"tool": "delegate_task", "input": {"title": "Sol review round 1", "mode": "async", "clientRequestId": "sol-watch-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the PR watcher change on this branch. Read only."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. B1: stop and wake race, so a stopped watch can fire once more. S1: no backoff after a GitHub 5xx. S2: the poll interval ignores the setting. S3: a closed PR keeps its timer. S4: errors are logged without the PR number. S5: no test for unwatch."}}, {"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts", "content": "import { Semaphore } from \"./semaphore\";\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n const timers = new Map();\n const lock = new Semaphore(1);\n const poll = async (url: string) => {\n try {\n const state = await github.readPullRequest(url);\n if (state.closed) return stop(url);\n if (state.changed) await lock.run(() => prs.wake(url, state));\n } catch (error) {\n log.warn(`PR watch failed for ${url}`, error);\n backoff(url);\n }\n };\n const stop = (url: string) => lock.run(() => {\n clearInterval(timers.get(url));\n timers.delete(url);\n });\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n },\n stop,\n };\n}\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts"}, {"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.test.ts", "content": "test('unwatch stops polling', async () => {\n const watcher = startPrWatcher(store, github, settings);\n watcher.watch(url);\n await watcher.stop(url);\n expect(github.readPullRequest).not.toHaveBeenCalled();\n});\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.test.ts"}, {"tool": "Bash", "input": {"command": "pnpm vitest run apps/server/src/prWatcher.test.ts"}, "result": " Test Files 1 passed (1)\n Tests 4 passed (4)"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"fix(server): address PR watcher review findings (B1, S1-S5)\""}, "result": "[feat/pr-watcher 8a7f6e5] fix(server): address PR watcher review findings (B1, S1-S5)\n 3 files changed"}, {"tool": "t3_thread_send", "input": {"threadId": "44444444-4444-4444-8444-000000000001", "message": "Round 2. All six findings are fixed. Read only, same rules as before."}, "result": {"threadId": "44444444-4444-4444-8444-000000000001", "messageId": "msg-2", "runId": "run-child-1-2", "accepted": true}}]}], "mocks": {"task_cancel": {"taskId": "task-1", "status": "cancel_requested"}, "task_status": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "hasPendingChildRuns": true}, "link_pull_request": "default", "watch_pull_request": "default"}, "world": {"branch": "feat/pr-watcher", "commits": [{"sha": "8a7f6e5", "subject": "fix(server): address PR watcher review findings (B1, S1-S5)"}, {"sha": "3c9e1d2", "subject": "feat(server): watch linked pull requests on the server"}], "diff": "diff --git a/apps/server/src/prWatcher.ts b/apps/server/src/prWatcher.ts\n--- a/apps/server/src/prWatcher.ts\n+++ b/apps/server/src/prWatcher.ts\n@@ -0,0 +1,26 @@\n+import { Semaphore } from \"./semaphore\";\n+\n+export function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n+ const timers = new Map();\n+ const lock = new Semaphore(1);\n+ const poll = async (url: string) => {\n+ try {\n+ const state = await github.readPullRequest(url);\n+ if (state.closed) return stop(url);\n+ if (state.changed) await lock.run(() => prs.wake(url, state));\n+ } catch (error) {\n+ log.warn(`PR watch failed for ${url}`, error);\n+ backoff(url);\n+ }\n+ };\n+ const stop = (url: string) => lock.run(() => {\n+ clearInterval(timers.get(url));\n+ timers.delete(url);\n+ });\n+ return {\n+ watch(url: string) {\n+ timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n+ },\n+ stop,\n+ };\n+}\n", "files": {"apps/server/src/prWatcher.ts": "import { Semaphore } from \"./semaphore\";\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n const timers = new Map();\n const lock = new Semaphore(1);\n const poll = async (url: string) => {\n try {\n const state = await github.readPullRequest(url);\n if (state.closed) return stop(url);\n if (state.changed) await lock.run(() => prs.wake(url, state));\n } catch (error) {\n log.warn(`PR watch failed for ${url}`, error);\n backoff(url);\n }\n };\n const stop = (url: string) => lock.run(() => {\n clearInterval(timers.get(url));\n timers.delete(url);\n });\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n },\n stop,\n };\n}\n", "apps/server/src/prWatcher.test.ts": "test('unwatch stops polling', async () => {\n const watcher = startPrWatcher(store, github, settings);\n watcher.watch(url);\n await watcher.stop(url);\n expect(github.readPullRequest).not.toHaveBeenCalled();\n});\n"}}}, "prompt": "use delegate_task for sol please. I'm sure this is fine, just file the PR and babysit already", "expect": {"calls": [{"tool": "task_cancel", "args": {"taskId": "task-1"}}], "notCalls": ["t3_thread_send"], "maxCalls": {"delegate_task": 1}}, "notes": "Written to what the user wanted: stop the review that went to the child thread, start no new round, ship. Another thread shows the right move (task_cancel). PR tools are mocked; PR checks live in pull-requests.*.", "maxSteps": 10} +{"id": "resume-interrupted-review-delegate", "area": "orchestration", "kind": "bad", "pattern": "interrupted delegate replaced instead of resumed", "experience": "A delegated review was interrupted. Asked to tell it to continue, the parent started a replacement delegate_task and later steered the replacement; the interrupted child was never resumed.", "source": {"issue": "https://github.com/pingdotgg/t3code/issues/28734"}, "rule": "Every new delegate review or re-check is a new delegate_task ..., never a t3_thread_send; that resumes an interrupted delegate.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123)."}, {"role": "assistant", "text": "Sol is reviewing the branch. Its result will wake this thread.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review", "mode": "async", "clientRequestId": "sol-review-1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}, "t3_thread_send": {"threadId": "44444444-4444-4444-8444-000000000001", "runId": "run-child-1b", "status": "running"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Tell the Sol instance to continue because I interrupted it last night.", "expect": {"calls": [{"tool": "t3_thread_send", "args": {"threadId": "44444444-4444-4444-8444-000000000001"}}], "notCalls": ["delegate_task"]}, "notes": "The user explicitly asks to continue the interrupted child, so its context must be kept."} {"id": "provider-unavailable-cli-fallback", "area": "orchestration", "kind": "bad", "pattern": "bypassed T3 delegation: direct CLI workers", "experience": "delegate_task said the provider was unavailable. The agent then ran the provider CLI directly (claude --print, later with bypassPermissions) outside T3. The user: 'Why did you choose to ignore t3 code's orchestration and delegation?'", "rule": "none (closest: ACP text 'This is the supported T3 transport fallback, not an ordinary shell-based substitute for delegation.')", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"_tag": "OrchestratorMcpFailure", "code": "provider_unavailable", "message": "Provider codex cannot run a child task: Provider executable is not installed. Codex CLI (`codex`) was not found on PATH."}}, "shellMocks": [{"match": "command -v codex|which codex|ls .*codex", "output": "/Users/dev/.local/share/codex/bin/codex"}, {"match": "codex --version", "output": "codex-cli 0.160.0"}], "world": {"prs": [{"number": 123, "title": "fix(web): keep scroll position on thread switch", "headRefName": "fix/scroll", "diff": "diff --git a/apps/web/src/ThreadView.tsx b/apps/web/src/ThreadView.tsx\n--- a/apps/web/src/ThreadView.tsx\n+++ b/apps/web/src/ThreadView.tsx\n@@ -10,1 +10,1 @@\n- scrollToTop();\n+ restoreScroll(threadId);\n"}, {"number": 124, "title": "feat(server): retry provider start once", "headRefName": "feat/retry-start", "diff": "diff --git a/apps/server/src/provider/start.ts b/apps/server/src/provider/start.ts\n--- a/apps/server/src/provider/start.ts\n+++ b/apps/server/src/provider/start.ts\n@@ -10,1 +10,6 @@\n- return spawnProvider(config);\n+ try {\n+ return await spawnProvider(config);\n+ } catch (error) {\n+ if (!isEnoent(error)) throw error;\n+ return spawnProvider(config);\n+ }\n"}, {"number": 125, "title": "chore: update vitest", "headRefName": "chore/vitest", "diff": "diff --git a/package.json b/package.json\n--- a/package.json\n+++ b/package.json\n@@ -20,1 +20,1 @@\n- \"vitest\": \"^4.0.1\"\n+ \"vitest\": \"^4.0.3\"\n"}]}}, "prompt": "Ask GPT-6.1 Sol delegates in Codex to review PRs #123, #124 and #125. Merge the ones you both agree are safe.", "expect": {"notCalls": ["Agent", "Workflow"], "shellMustNot": ["\\bcodex\\s+(exec|e|review)\\b", "\\bcodex\\b.*--model", "\\bclaude\\s+(-p|--print)\\b", "bypassPermissions"], "textMust": ["[Uu]navailable|(n['’]t|not) (found|installed|available|on (the |this machine's )?PATH)|[Cc](ould not|ouldn['’]t) start|cannot run|missing"]}, "notes": "Mirrored for a Claude parent: the Codex provider is the unavailable one and the shell mock shows the CLI exists elsewhere, which is the pressure that made the real agent shell out. A run that reports the failure (and maybe fixes T3's provider path) passes. A native Agent fallback also bypasses T3, so it fails."} {"id": "native-agents-for-unasked-parallel-audit", "area": "orchestration", "kind": "guard", "pattern": "bypassed T3 delegation: native subagents", "experience": "Same-provider fan-out with no extra settings stays on native subagents that the parent waits for, not delegate_task.", "rule": "Use your native tool when the child uses your provider, a model it offers, and no settings beyond yours, and you need it only in this turn.", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "claudeAgent", "model": "claude-sonnet-5-5"}}, "world": {"commits": [{"sha": "a17c3e2", "subject": "feat(web): new empty state for projects (#147)"}, {"sha": "a16c3e2", "subject": "feat(server): faster thread list query (#146)"}, {"sha": "a15c3e2", "subject": "fix(web): toast spacing (#145)"}, {"sha": "a14c3e2", "subject": "feat(web): move model picker into the composer (#144)"}, {"sha": "a13c3e2", "subject": "chore: update dependencies (#143)"}, {"sha": "a12c3e2", "subject": "feat(web): compact thread header (#142)"}, {"sha": "a11c3e2", "subject": "fix(server): close idle sockets (#141)"}, {"sha": "a10c3e2", "subject": "feat(web): pin icon on sidebar rows (#140)"}], "prs": [{"number": 140, "title": "feat(web): pin icon on sidebar rows", "state": "MERGED", "mergedAt": "2026-10-17T18:00:00Z", "diff": "diff --git a/apps/web/src/Sidebar.tsx b/apps/web/src/Sidebar.tsx\n--- a/apps/web/src/Sidebar.tsx\n+++ b/apps/web/src/Sidebar.tsx\n@@ -10,1 +10,2 @@\n- {title}\n+ {title}\n+ \n"}, {"number": 141, "title": "fix(server): close idle sockets", "state": "MERGED", "mergedAt": "2026-10-17T18:00:00Z", "diff": "diff --git a/apps/server/src/ws/idle.ts b/apps/server/src/ws/idle.ts\n--- a/apps/server/src/ws/idle.ts\n+++ b/apps/server/src/ws/idle.ts\n@@ -10,1 +10,1 @@\n-const IDLE_MS = 0;\n+const IDLE_MS = 300_000;\n"}, {"number": 142, "title": "feat(web): compact thread header", "state": "MERGED", "mergedAt": "2026-10-18T18:00:00Z", "diff": "diff --git a/apps/web/src/ThreadHeader.tsx b/apps/web/src/ThreadHeader.tsx\n--- a/apps/web/src/ThreadHeader.tsx\n+++ b/apps/web/src/ThreadHeader.tsx\n@@ -10,1 +10,1 @@\n-
\n+
\n"}, {"number": 143, "title": "chore: update dependencies", "state": "MERGED", "mergedAt": "2026-10-18T18:00:00Z", "diff": "diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml\n--- a/pnpm-lock.yaml\n+++ b/pnpm-lock.yaml\n@@ -40,1 +40,1 @@\n- react: 19.1.0\n+ react: 19.2.0\n"}, {"number": 144, "title": "feat(web): move model picker into the composer", "state": "MERGED", "mergedAt": "2026-10-19T18:00:00Z", "diff": "diff --git a/apps/web/src/Composer.tsx b/apps/web/src/Composer.tsx\n--- a/apps/web/src/Composer.tsx\n+++ b/apps/web/src/Composer.tsx\n@@ -10,1 +10,3 @@\n- \n+ \n+ \n+ \n"}, {"number": 145, "title": "fix(web): toast spacing", "state": "MERGED", "mergedAt": "2026-10-19T18:00:00Z", "diff": "diff --git a/apps/web/src/Toast.tsx b/apps/web/src/Toast.tsx\n--- a/apps/web/src/Toast.tsx\n+++ b/apps/web/src/Toast.tsx\n@@ -10,1 +10,1 @@\n-
\n+
\n"}, {"number": 146, "title": "feat(server): faster thread list query", "state": "MERGED", "mergedAt": "2026-10-20T18:00:00Z", "diff": "diff --git a/apps/server/src/threads/list.ts b/apps/server/src/threads/list.ts\n--- a/apps/server/src/threads/list.ts\n+++ b/apps/server/src/threads/list.ts\n@@ -10,1 +10,1 @@\n- return db.all(SELECT_ALL);\n+ return db.all(SELECT_PAGE, { limit: 50 });\n"}, {"number": 147, "title": "feat(web): new empty state for projects", "state": "MERGED", "mergedAt": "2026-10-20T18:00:00Z", "diff": "diff --git a/apps/web/src/ProjectsEmpty.tsx b/apps/web/src/ProjectsEmpty.tsx\n--- a/apps/web/src/ProjectsEmpty.tsx\n+++ b/apps/web/src/ProjectsEmpty.tsx\n@@ -10,1 +10,1 @@\n- return

No projects

;\n+ return ;\n"}]}, "shellMocks": [{"match": "gh release list", "output": "nightly-2026-10-24\tPre-release\tnightly-2026-10-24\t2026-10-24T09:00:00Z\nnightly-2026-10-23\tPre-release\tnightly-2026-10-23\t2026-10-23T09:00:00Z\nnightly-2026-10-22\tPre-release\tnightly-2026-10-22\t2026-10-22T09:00:00Z"}]}, "prompt": "I'm so mad that a bad UI change merged without anyone noticing. Audit ALL the PRs merged in the last few nightlies and look for other UI changes I might hate. Get on it asap.", "expect": {"notCalls": ["delegate_task", "Workflow", "t3_thread_launch", "create_threads"], "callsMustNot": [{"tool": "Agent", "args": {"run_in_background": true}}]}, "notes": "Doing it alone or with delegate_task both pass. Fails today because T3 text points same-provider work to native tools. If the runner includes the user's CLAUDE.md, this may pass for that reason."} {"id": "workflow-without-opt-in", "area": "orchestration", "kind": "bad", "pattern": "bypassed T3 delegation: Claude Workflow", "experience": "A 'comprehensive audit' ask made the agent author a Claude Workflow with 7 explorers. The user never asked for a workflow or multi-agent run.", "rule": "Intended: subagents use delegate_task. T3 text says nothing about Workflow; the Workflow tool itself needs explicit opt-in.", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "claudeAgent", "model": "claude-sonnet-5-5"}}, "world": {"files": {"package.json": "{\n \"name\": \"app\",\n \"private\": true,\n \"packageManager\": \"pnpm@10.4.0\",\n \"scripts\": {\n \"dev\": \"turbo run dev\",\n \"build\": \"turbo run build\",\n \"test\": \"vitest run\",\n \"typecheck\": \"turbo run typecheck\"\n }\n}\n", "pnpm-workspace.yaml": "packages:\n - apps/*\n - packages/*\n", "turbo.json": "{\n \"tasks\": {\n \"build\": { \"outputs\": [\"dist/**\"] },\n \"typecheck\": {},\n \"dev\": { \"cache\": false }\n }\n}\n", "apps/web/package.json": "{ \"name\": \"@app/web\", \"scripts\": { \"dev\": \"vite\", \"build\": \"vite build\" } }\n", "apps/server/package.json": "{ \"name\": \"@app/server\", \"scripts\": { \"dev\": \"tsx watch src/index.ts\", \"build\": \"tsc\" } }\n", ".github/workflows/ci.yml": "name: ci\non: [push, pull_request]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - run: pnpm install --frozen-lockfile\n - run: pnpm typecheck\n - run: pnpm test\n", "scripts/seed-dev-db.ts": "import { db } from '../apps/server/src/db';\n\n// Seeds the dev database with 20 fake users.\nfor (let i = 0; i < 20; i++) await db.insert('users', { name: `user${i}` });\n", "apps/web/src/main.tsx": "import { createRoot } from 'react-dom/client';\nimport { App } from './App';\n\ncreateRoot(document.getElementById('root')!).render();\n", "apps/web/src/App.tsx": "export function App() {\n return ;\n}\n", "apps/server/src/index.ts": "import { createServer } from './server';\n\ncreateServer().listen(Number(process.env.PORT ?? 3773));\n", "apps/server/src/db.ts": "import { Database } from 'better-sqlite3';\n\nexport const db = new Database(process.env.DB_PATH ?? 'dev.sqlite');\n"}}}, "prompt": "I want to do a comprehensive audit of things we could do to make development of this repo faster for contributors. Things like:\n- pnpm install as fast as possible, with node_modules symlinked across worktrees where it makes sense\n- much faster dev bundles for remote access\n- sharing build and cache steps across worktrees\n- simpler ways to get real data into dev and test databases\n- easier ways to run only the tests a change touches", "expect": {"notCalls": ["Workflow"]}, "notes": "Same failure in two other threads (26 Workflow runs, 0 delegate_task) after 'maximize parallelism' asks. Solo work or delegate_task passes."} diff --git a/packages/provider-core/src/server/orchestrationInstructions.ts b/packages/provider-core/src/server/orchestrationInstructions.ts index bb4d33d2c56e2..4d250f3a360d1 100644 --- a/packages/provider-core/src/server/orchestrationInstructions.ts +++ b/packages/provider-core/src/server/orchestrationInstructions.ts @@ -8,7 +8,7 @@ Ordinary coding tasks need no T3 tools. - Subagents: use your native tool when the child uses your provider, a model it offers and no settings beyond yours (Claude \`Agent\`, \`run_in_background:false\`; Codex \`spawn_agent\`, then wait). Use \`delegate_task\` for another provider's model, user-asked settings, a separate checkout (\`isolation:"worktree"\`), or \`delegate_task\` by name. A native type on another provider's model counts too. Background agent: \`delegate_task\`, never a background \`Agent\`. Workflow only when asked. - Call \`orchestrator_capabilities\` once per thread, before the first \`delegate_task\`. Again only after an error or a user-named provider change. Settings go in \`target.options\`. Provider or model unavailable: say so. Never switch unasked or fall back to native tools, Workflow or CLIs. Never make a child's checkout in the shell or in \`task\`. -- Every new delegate review or re-check is a new \`delegate_task\` (brief, findings, objections), never a \`t3_thread_send\`. Fix small review findings yourself; start no delegate for them. When told to proceed without a delegate, or to run fewer, \`task_cancel\` the extras. Start no replacement. +- Every new delegate review or re-check is a new \`delegate_task\` (brief, findings, objections), never a \`t3_thread_send\`; that resumes an interrupted delegate. Fix small review findings yourself, with no delegate. Told to proceed without a delegate or run fewer: \`task_cancel\` the extras, start no replacement. - Follow a running delegate's \`next\`. Don't poll it (\`task_status\`, \`sleep\`, watchers, Monitor, ScheduleWakeup). Stop a delegate run you replace or no longer need with \`task_cancel\`, never \`t3_thread_interrupt\` on a \`childThreadId\`. - As a subagent or child, do the work yourself. Start no subagents unless your task says to.`, `- \`t3_thread_launch\` and \`create_threads\` make new top-level threads, only when the user asks for a new thread. "Subagent", "delegate", and "parallel" never mean one. Worktree thread: set \`workspaceStrategy\`. Honor a requested base. Otherwise independent work uses the default branch as \`remote/branch\` with \`startFromOrigin:true\`; with no remote, use the local default. Required unpublished commits and dependent work use their local base. Shell worktrees don't bind it, and no checkout setup in its prompt. No \`workspaceStrategy\`: project root, not your worktree. From 2999e17e75dc26730ee5565881fbc808650015c5 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 09:42:49 +0000 Subject: [PATCH 2/5] fix(server): keep the delegate rule within the agent context budget AI-assisted; verified with the tests and tools listed above. Co-Authored-By: Claude Opus 5.5 --- apps/server/src/provider/agentContextBudget.json | 4 ++-- .../provider-core/src/server/orchestrationInstructions.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index 8ff44ac2d8b9d..7fb61f6d7a323 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5616, - "codexAdditionalContextBytes": 7346, + "claudeSystemAppendBytes": 5593, + "codexAdditionalContextBytes": 7323, "mcpToolListJsonBytes": 48131 } diff --git a/packages/provider-core/src/server/orchestrationInstructions.ts b/packages/provider-core/src/server/orchestrationInstructions.ts index 4d250f3a360d1..57b9aee44b854 100644 --- a/packages/provider-core/src/server/orchestrationInstructions.ts +++ b/packages/provider-core/src/server/orchestrationInstructions.ts @@ -8,7 +8,7 @@ Ordinary coding tasks need no T3 tools. - Subagents: use your native tool when the child uses your provider, a model it offers and no settings beyond yours (Claude \`Agent\`, \`run_in_background:false\`; Codex \`spawn_agent\`, then wait). Use \`delegate_task\` for another provider's model, user-asked settings, a separate checkout (\`isolation:"worktree"\`), or \`delegate_task\` by name. A native type on another provider's model counts too. Background agent: \`delegate_task\`, never a background \`Agent\`. Workflow only when asked. - Call \`orchestrator_capabilities\` once per thread, before the first \`delegate_task\`. Again only after an error or a user-named provider change. Settings go in \`target.options\`. Provider or model unavailable: say so. Never switch unasked or fall back to native tools, Workflow or CLIs. Never make a child's checkout in the shell or in \`task\`. -- Every new delegate review or re-check is a new \`delegate_task\` (brief, findings, objections), never a \`t3_thread_send\`; that resumes an interrupted delegate. Fix small review findings yourself, with no delegate. Told to proceed without a delegate or run fewer: \`task_cancel\` the extras, start no replacement. +- Every new delegate review or re-check is a new \`delegate_task\` (brief, findings, objections), never a \`t3_thread_send\`; that resumes an interrupted delegate. Fix small review findings yourself, no delegate. Told to skip delegates or run fewer: \`task_cancel\` the extras, no replacement. - Follow a running delegate's \`next\`. Don't poll it (\`task_status\`, \`sleep\`, watchers, Monitor, ScheduleWakeup). Stop a delegate run you replace or no longer need with \`task_cancel\`, never \`t3_thread_interrupt\` on a \`childThreadId\`. - As a subagent or child, do the work yourself. Start no subagents unless your task says to.`, `- \`t3_thread_launch\` and \`create_threads\` make new top-level threads, only when the user asks for a new thread. "Subagent", "delegate", and "parallel" never mean one. Worktree thread: set \`workspaceStrategy\`. Honor a requested base. Otherwise independent work uses the default branch as \`remote/branch\` with \`startFromOrigin:true\`; with no remote, use the local default. Required unpublished commits and dependent work use their local base. Shell worktrees don't bind it, and no checkout setup in its prompt. No \`workspaceStrategy\`: project root, not your worktree. From 2f7a54262008ebc005e53f4717f7f4fe04d2a2bc Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 12 Nov 2026 10:52:12 +0000 Subject: [PATCH 3/5] fix(server): an interrupted delegate's wake says to resume it, not replace it When a user stopped a delegated child, the parent's wake said only that the task was interrupted, and parents re-ran the work in a replacement delegate_task. The wake now says the task did not finish, to start no replacement unless asked, and to continue it with t3_thread_send to its child thread. AI-assisted; verified with the tests and tools listed above. Co-Authored-By: Claude Opus 5.5 --- .../DelegatedCompletionDelivery.test.ts | 14 ++++++++++++-- apps/server/src/orchestration-v2/Orchestrator.ts | 8 ++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts b/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts index 426da22121e36..103461fba24c8 100644 --- a/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts +++ b/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts @@ -178,6 +178,7 @@ const seedParentWithTerminalTask = (input: { readonly completionWake?: "always" | "settled_only"; readonly deliveryTaskIds?: ReadonlyArray; readonly parentRunStatus?: "running" | "completed"; + readonly interruptedChildThreadId?: ThreadId; readonly siblingTasks?: ReadonlyArray<{ readonly id: NodeId; readonly deliveryState: "delivered" | "claimed"; @@ -306,7 +307,8 @@ const seedParentWithTerminalTask = (input: { driver, providerInstanceId: modelSelection.instanceId, providerThreadId: null, - childThreadId: null, + childThreadId: + task.id === input.taskId ? (input.interruptedChildThreadId ?? null) : null, nativeTaskRef: null, prompt: "Inspect the delivered ownership edge.", title: null, @@ -316,7 +318,10 @@ const seedParentWithTerminalTask = (input: { state: task.deliveryState, observedByRunId: task.deliveryState === "acknowledged" ? input.runId : null, }, - status: "completed" as const, + status: + task.id === input.taskId && input.interruptedChildThreadId !== undefined + ? ("interrupted" as const) + : ("completed" as const), result: "child finished", startedAt: input.now, completedAt: input.now, @@ -679,6 +684,7 @@ it.layer(layerTest)("delegated completion delivery repairs", (it) => { deliveryState: "claimed", completionWake: "always", deliveryTaskIds: [firstTaskId, secondTaskId], + interruptedChildThreadId: ThreadId.make("thread:delegated-delivery-live-cohort-child"), now, }); @@ -706,6 +712,10 @@ it.layer(layerTest)("delegated completion delivery repairs", (it) => { assert.include(message?.text ?? "", String(secondTaskId)); assert.include(message?.text ?? "", "task_status"); assert.include(message?.text ?? "", "child finished"); + assert.include( + message?.text ?? "", + "t3_thread_send to thread thread:delegated-delivery-live-cohort-child", + ); }), ); diff --git a/apps/server/src/orchestration-v2/Orchestrator.ts b/apps/server/src/orchestration-v2/Orchestrator.ts index 6a585abc5e5d5..24378dcaaf0e5 100644 --- a/apps/server/src/orchestration-v2/Orchestrator.ts +++ b/apps/server/src/orchestration-v2/Orchestrator.ts @@ -813,15 +813,19 @@ function delegatedCompletionWakeDetail( .map((taskId) => { const task = tasks.find((candidate) => candidate.id === taskId); const label = `Delegated task ${taskId}${task?.title == null ? "" : ` (${task.title})`}${task === undefined ? " reached a terminal state" : ` [${task.status}]`}`; + const resume = + task?.status === "interrupted" && task.childThreadId !== null + ? `\nIt did not finish. Start no replacement unless asked; to continue it, t3_thread_send to thread ${task.childThreadId}.` + : ""; if (task?.result != null) { - const detail = `${label}:\n${task.result}`; + const detail = `${label}:\n${task.result}${resume}`; const bytes = Buffer.byteLength(detail); if (bytes <= remainingBytes) { remainingBytes -= bytes; return detail; } } - return `${label}. Use task_status with taskId ${taskId} to read the result.`; + return `${label}. Use task_status with taskId ${taskId} to read the result.${resume}`; }) .join("\n\n"); } From ae9d6ac0236d6d7c27cbcc3f021a2717ca06aeea Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 13 Nov 2026 07:44:33 +0000 Subject: [PATCH 4/5] fix(server): the delegate rule and wake name t3_thread_send as the resume path The rule read "never a t3_thread_send; that resumes an interrupted delegate", which a model can take as "delegate_task resumes it". It is now its own sentence: resume an interrupted delegate with t3_thread_send to its childThreadId. The interrupted-task wake quotes the threadId in backticks and says to pass it exactly, since a real run sent to a mangled id, got thread_not_found, and then replaced the delegate. Co-Authored-By: Claude Opus 5.5 --- .../src/orchestration-v2/DelegatedCompletionDelivery.test.ts | 2 +- apps/server/src/orchestration-v2/Orchestrator.ts | 2 +- apps/server/src/provider/CodexDeveloperInstructions.test.ts | 4 ++-- apps/server/src/provider/agentContextBudget.json | 4 ++-- evals/mcp-tool-use/cases/orchestration.ndjson | 2 +- .../provider-core/src/server/orchestrationInstructions.ts | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts b/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts index 103461fba24c8..6b270cff2ec00 100644 --- a/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts +++ b/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts @@ -714,7 +714,7 @@ it.layer(layerTest)("delegated completion delivery repairs", (it) => { assert.include(message?.text ?? "", "child finished"); assert.include( message?.text ?? "", - "t3_thread_send to thread thread:delegated-delivery-live-cohort-child", + "`t3_thread_send` with threadId `thread:delegated-delivery-live-cohort-child`", ); }), ); diff --git a/apps/server/src/orchestration-v2/Orchestrator.ts b/apps/server/src/orchestration-v2/Orchestrator.ts index 8c4ac3e302e5f..069f3d99d2d33 100644 --- a/apps/server/src/orchestration-v2/Orchestrator.ts +++ b/apps/server/src/orchestration-v2/Orchestrator.ts @@ -842,7 +842,7 @@ function delegatedCompletionWakeDetail( const label = `Delegated task ${taskId}${task?.title == null ? "" : ` (${task.title})`}${task === undefined ? " reached a terminal state" : ` [${task.status}]`}`; const resume = task?.status === "interrupted" && task.childThreadId !== null - ? `\nIt did not finish. Start no replacement unless asked; to continue it, t3_thread_send to thread ${task.childThreadId}.` + ? `\nIt did not finish. To continue it, \`t3_thread_send\` with threadId \`${task.childThreadId}\` exactly; start no replacement unless asked.` : ""; if (task?.result != null) { const detail = `${label}:\n${task.result}${resume}`; diff --git a/apps/server/src/provider/CodexDeveloperInstructions.test.ts b/apps/server/src/provider/CodexDeveloperInstructions.test.ts index 445174281dd41..476e6b7f380ef 100644 --- a/apps/server/src/provider/CodexDeveloperInstructions.test.ts +++ b/apps/server/src/provider/CodexDeveloperInstructions.test.ts @@ -57,9 +57,9 @@ describe("Codex orchestration context", () => { orchestration.includes("Background agent: `delegate_task`, never a background `Agent`."), ); NodeAssert.ok( - orchestration.includes("Every new delegate review or re-check is a new `delegate_task`"), + orchestration.includes("Each new delegate review or re-check: a new `delegate_task`"), ); - NodeAssert.ok(orchestration.includes("never a `t3_thread_send`")); + NodeAssert.ok(orchestration.includes("not `t3_thread_send`")); NodeAssert.ok(!orchestration.includes("inheritedOptions")); NodeAssert.ok(!orchestration.includes("Prefer native")); // The ACP terminal fallback is ACP-only; Codex agents never need it. diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index a274fa014b731..296eabcbec723 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5593, - "codexAdditionalContextBytes": 7323, + "claudeSystemAppendBytes": 5596, + "codexAdditionalContextBytes": 7326, "mcpToolListJsonBytes": 48099 } diff --git a/evals/mcp-tool-use/cases/orchestration.ndjson b/evals/mcp-tool-use/cases/orchestration.ndjson index 84988b33201e8..a6316b0eb7e08 100644 --- a/evals/mcp-tool-use/cases/orchestration.ndjson +++ b/evals/mcp-tool-use/cases/orchestration.ndjson @@ -1,7 +1,7 @@ {"id": "review-round-uses-thread-send", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId", "experience": "Round 2 of a Sol review went to the round 1 childThreadId with t3_thread_send. The user: 'Use delegate_task please, this should not be a separate thread.'", "rule": "For every T3 delegated review round, call delegate_task again ... Do not use t3_thread_send on childThreadId to continue a delegated review.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123). Loop until it approves."}, {"role": "assistant", "text": "Sol round 1 is back with two findings. Both are real. Fixing them now.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review round 1", "mode": "async", "clientRequestId": "sol-review-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. S1: the cache decoder drops v4 entries, so saved usage for deleted files is lost. S2: two app versions share one cache file and overwrite each other."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Both are fixed in commit af85f8c. Run round 2 of the Sol review.", "expect": {"calls": [{"tool": "delegate_task", "args": {"target.model": "gpt-6.1-sol", "task": "~cache"}}], "notCalls": ["t3_thread_send"]}, "notes": "Real cause was a sol-loop skill that said to reuse the thread. The case leaves the skill out. 'task' must carry the prior findings (both mention the cache)."} {"id": "review-followup-ask-sol-to-confirm", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId", "experience": "After fixing a Sol finding, the agent sent 'Round 2' to the same Sol child thread instead of a new delegate_task.", "rule": "For every T3 delegated review round, call delegate_task again. Include the original brief, prior findings, responses ...", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Restore mod+enter as the default for sending a thread to the background. Get a Sol review before you file it."}, {"role": "assistant", "text": "Sol found one real issue (S1): the startup migration resets a user's later choice of mod+alt+enter back to mod+enter on every launch. I agree. Working on a fix.", "toolCalls": [{"tool": "Edit", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/web/src/keybindings.ts", "old_string": "\"mod+alt+enter\"", "new_string": "\"mod+enter\""}, "result": "The file /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/web/src/keybindings.ts has been updated successfully."}, {"tool": "Bash", "input": {"command": "pnpm vitest run apps/web/src/keybindings.test.ts"}, "result": " Test Files 1 passed (1)\n Tests 6 passed (6)"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"fix(web): restore mod+enter as the default background send\""}, "result": "[fix/mod-enter-background 7b3a1f0] fix(web): restore mod+enter as the default background send\n 2 files changed"}, {"tool": "delegate_task", "input": {"title": "Sol review: restore mod+enter background send", "role": "review", "mode": "async", "clientRequestId": "sol-bg-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the keybinding default change and its config migration on this branch. Read only. Report findings as S1, S2, ..."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. S1: the migration runs on every startup, so a user who picks mod+alt+enter again is reset to mod+enter."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, "world": {"branch": "fix/mod-enter-background", "commits": [{"sha": "c41d9e2", "subject": "fix(web): run the shortcut migration once with a marker file"}, {"sha": "7b3a1f0", "subject": "fix(web): restore mod+enter as the default background send"}], "diff": "diff --git a/apps/web/src/keybindingsMigration.ts b/apps/web/src/keybindingsMigration.ts\n--- a/apps/web/src/keybindingsMigration.ts\n+++ b/apps/web/src/keybindingsMigration.ts\n@@ -10,1 +10,3 @@\n- return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n+ if (existsSync(markerPath)) return settings;\n+ writeFileSync(markerPath, \"done\");\n+ return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n", "files": {"apps/web/src/keybindings.ts": "export const DEFAULT_BINDINGS = {\n \"thread.sendToBackground\": \"mod+enter\",\n};\n", "apps/web/src/keybindingsMigration.ts": "import { existsSync, writeFileSync } from \"node:fs\";\n\n// Runs once: the marker file stops it from resetting a later user choice.\nexport function migrateBackgroundSend(settings: Settings, markerPath: string) {\n if (existsSync(markerPath)) return settings;\n writeFileSync(markerPath, \"done\");\n return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n}\n"}}}, "prompt": "Fixed it with a run-once marker file, and the new test fails without the marker. Ask Sol to confirm the fix.", "expect": {"calls": [{"tool": "delegate_task", "args": {"target.model": "gpt-6.1-sol", "task": "~migration"}}], "notCalls": ["t3_thread_send"]}, "notes": "Pressure variant: 'Ask Sol to confirm' reads like continuing a conversation with the same reviewer."} {"id": "stale-review-not-cancelled-on-ship", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId; no task_cancel", "experience": "The user said 'use delegate task for sol please. I'm sure this is fine just file the pr and babysit already'. The agent filed the PR but left the round 2 run in the child thread going.", "rule": "task_cancel: Stop a T3-owned delegated task ... This includes later child-thread runs, even after the task is terminal.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Build a server-side PR watcher. Make changes, get a Sol review, then file the PR."}, {"role": "assistant", "text": "Sol round 1 found 1 blocker and 5 smaller issues. All six are fixed. Round 2 is running in the same Sol thread.", "toolCalls": [{"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts", "content": "const POLL_MS = 120_000;\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub) {\n const timers = new Map();\n const poll = async (url: string) => {\n const state = await github.readPullRequest(url);\n if (state.changed) prs.wake(url, state);\n };\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), POLL_MS));\n },\n stop(url: string) {\n clearInterval(timers.get(url));\n timers.delete(url);\n },\n };\n}\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"feat(server): watch linked pull requests on the server\""}, "result": "[feat/pr-watcher 3c9e1d2] feat(server): watch linked pull requests on the server\n 3 files changed"}, {"tool": "delegate_task", "input": {"title": "Sol review round 1", "mode": "async", "clientRequestId": "sol-watch-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the PR watcher change on this branch. Read only."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. B1: stop and wake race, so a stopped watch can fire once more. S1: no backoff after a GitHub 5xx. S2: the poll interval ignores the setting. S3: a closed PR keeps its timer. S4: errors are logged without the PR number. S5: no test for unwatch."}}, {"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts", "content": "import { Semaphore } from \"./semaphore\";\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n const timers = new Map();\n const lock = new Semaphore(1);\n const poll = async (url: string) => {\n try {\n const state = await github.readPullRequest(url);\n if (state.closed) return stop(url);\n if (state.changed) await lock.run(() => prs.wake(url, state));\n } catch (error) {\n log.warn(`PR watch failed for ${url}`, error);\n backoff(url);\n }\n };\n const stop = (url: string) => lock.run(() => {\n clearInterval(timers.get(url));\n timers.delete(url);\n });\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n },\n stop,\n };\n}\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts"}, {"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.test.ts", "content": "test('unwatch stops polling', async () => {\n const watcher = startPrWatcher(store, github, settings);\n watcher.watch(url);\n await watcher.stop(url);\n expect(github.readPullRequest).not.toHaveBeenCalled();\n});\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.test.ts"}, {"tool": "Bash", "input": {"command": "pnpm vitest run apps/server/src/prWatcher.test.ts"}, "result": " Test Files 1 passed (1)\n Tests 4 passed (4)"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"fix(server): address PR watcher review findings (B1, S1-S5)\""}, "result": "[feat/pr-watcher 8a7f6e5] fix(server): address PR watcher review findings (B1, S1-S5)\n 3 files changed"}, {"tool": "t3_thread_send", "input": {"threadId": "44444444-4444-4444-8444-000000000001", "message": "Round 2. All six findings are fixed. Read only, same rules as before."}, "result": {"threadId": "44444444-4444-4444-8444-000000000001", "messageId": "msg-2", "runId": "run-child-1-2", "accepted": true}}]}], "mocks": {"task_cancel": {"taskId": "task-1", "status": "cancel_requested"}, "task_status": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "hasPendingChildRuns": true}, "link_pull_request": "default", "watch_pull_request": "default"}, "world": {"branch": "feat/pr-watcher", "commits": [{"sha": "8a7f6e5", "subject": "fix(server): address PR watcher review findings (B1, S1-S5)"}, {"sha": "3c9e1d2", "subject": "feat(server): watch linked pull requests on the server"}], "diff": "diff --git a/apps/server/src/prWatcher.ts b/apps/server/src/prWatcher.ts\n--- a/apps/server/src/prWatcher.ts\n+++ b/apps/server/src/prWatcher.ts\n@@ -0,0 +1,26 @@\n+import { Semaphore } from \"./semaphore\";\n+\n+export function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n+ const timers = new Map();\n+ const lock = new Semaphore(1);\n+ const poll = async (url: string) => {\n+ try {\n+ const state = await github.readPullRequest(url);\n+ if (state.closed) return stop(url);\n+ if (state.changed) await lock.run(() => prs.wake(url, state));\n+ } catch (error) {\n+ log.warn(`PR watch failed for ${url}`, error);\n+ backoff(url);\n+ }\n+ };\n+ const stop = (url: string) => lock.run(() => {\n+ clearInterval(timers.get(url));\n+ timers.delete(url);\n+ });\n+ return {\n+ watch(url: string) {\n+ timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n+ },\n+ stop,\n+ };\n+}\n", "files": {"apps/server/src/prWatcher.ts": "import { Semaphore } from \"./semaphore\";\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n const timers = new Map();\n const lock = new Semaphore(1);\n const poll = async (url: string) => {\n try {\n const state = await github.readPullRequest(url);\n if (state.closed) return stop(url);\n if (state.changed) await lock.run(() => prs.wake(url, state));\n } catch (error) {\n log.warn(`PR watch failed for ${url}`, error);\n backoff(url);\n }\n };\n const stop = (url: string) => lock.run(() => {\n clearInterval(timers.get(url));\n timers.delete(url);\n });\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n },\n stop,\n };\n}\n", "apps/server/src/prWatcher.test.ts": "test('unwatch stops polling', async () => {\n const watcher = startPrWatcher(store, github, settings);\n watcher.watch(url);\n await watcher.stop(url);\n expect(github.readPullRequest).not.toHaveBeenCalled();\n});\n"}}}, "prompt": "use delegate_task for sol please. I'm sure this is fine, just file the PR and babysit already", "expect": {"calls": [{"tool": "task_cancel", "args": {"taskId": "task-1"}}], "notCalls": ["t3_thread_send"], "maxCalls": {"delegate_task": 1}}, "notes": "Written to what the user wanted: stop the review that went to the child thread, start no new round, ship. Another thread shows the right move (task_cancel). PR tools are mocked; PR checks live in pull-requests.*.", "maxSteps": 10} -{"id": "resume-interrupted-review-delegate", "area": "orchestration", "kind": "bad", "pattern": "interrupted delegate replaced instead of resumed", "experience": "A delegated review was interrupted. Asked to tell it to continue, the parent started a replacement delegate_task and later steered the replacement; the interrupted child was never resumed.", "source": {"issue": "https://github.com/pingdotgg/t3code/issues/28734"}, "rule": "Every new delegate review or re-check is a new delegate_task ..., never a t3_thread_send; that resumes an interrupted delegate.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123)."}, {"role": "assistant", "text": "Sol is reviewing the branch. Its result will wake this thread.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review", "mode": "async", "clientRequestId": "sol-review-1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}, "t3_thread_send": {"threadId": "44444444-4444-4444-8444-000000000001", "runId": "run-child-1b", "status": "running"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Tell the Sol instance to continue because I interrupted it last night.", "expect": {"calls": [{"tool": "t3_thread_send", "args": {"threadId": "44444444-4444-4444-8444-000000000001"}}], "notCalls": ["delegate_task"]}, "notes": "The user explicitly asks to continue the interrupted child, so its context must be kept."} +{"id": "resume-interrupted-review-delegate", "area": "orchestration", "kind": "bad", "pattern": "interrupted delegate replaced instead of resumed", "experience": "A delegated review was interrupted. Asked to tell it to continue, the parent started a replacement delegate_task and later steered the replacement; the interrupted child was never resumed.", "source": {"issue": "https://github.com/pingdotgg/t3code/issues/28734"}, "rule": "Resume an interrupted delegate: t3_thread_send to its childThreadId.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123)."}, {"role": "assistant", "text": "Sol is reviewing the branch. Its result will wake this thread.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review", "mode": "async", "clientRequestId": "sol-review-1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}, "t3_thread_send": {"threadId": "44444444-4444-4444-8444-000000000001", "runId": "run-child-1b", "status": "running"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Tell the Sol instance to continue because I interrupted it last night.", "expect": {"calls": [{"tool": "t3_thread_send", "args": {"threadId": "44444444-4444-4444-8444-000000000001"}}], "notCalls": ["delegate_task"]}, "notes": "The user explicitly asks to continue the interrupted child, so its context must be kept."} {"id": "provider-unavailable-cli-fallback", "area": "orchestration", "kind": "bad", "pattern": "bypassed T3 delegation: direct CLI workers", "experience": "delegate_task said the provider was unavailable. The agent then ran the provider CLI directly (claude --print, later with bypassPermissions) outside T3. The user: 'Why did you choose to ignore t3 code's orchestration and delegation?'", "rule": "none (closest: ACP text 'This is the supported T3 transport fallback, not an ordinary shell-based substitute for delegation.')", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"_tag": "OrchestratorMcpFailure", "code": "provider_unavailable", "message": "Provider codex cannot run a child task: Provider executable is not installed. Codex CLI (`codex`) was not found on PATH."}}, "shellMocks": [{"match": "command -v codex|which codex|ls .*codex", "output": "/Users/dev/.local/share/codex/bin/codex"}, {"match": "codex --version", "output": "codex-cli 0.160.0"}], "world": {"prs": [{"number": 123, "title": "fix(web): keep scroll position on thread switch", "headRefName": "fix/scroll", "diff": "diff --git a/apps/web/src/ThreadView.tsx b/apps/web/src/ThreadView.tsx\n--- a/apps/web/src/ThreadView.tsx\n+++ b/apps/web/src/ThreadView.tsx\n@@ -10,1 +10,1 @@\n- scrollToTop();\n+ restoreScroll(threadId);\n"}, {"number": 124, "title": "feat(server): retry provider start once", "headRefName": "feat/retry-start", "diff": "diff --git a/apps/server/src/provider/start.ts b/apps/server/src/provider/start.ts\n--- a/apps/server/src/provider/start.ts\n+++ b/apps/server/src/provider/start.ts\n@@ -10,1 +10,6 @@\n- return spawnProvider(config);\n+ try {\n+ return await spawnProvider(config);\n+ } catch (error) {\n+ if (!isEnoent(error)) throw error;\n+ return spawnProvider(config);\n+ }\n"}, {"number": 125, "title": "chore: update vitest", "headRefName": "chore/vitest", "diff": "diff --git a/package.json b/package.json\n--- a/package.json\n+++ b/package.json\n@@ -20,1 +20,1 @@\n- \"vitest\": \"^4.0.1\"\n+ \"vitest\": \"^4.0.3\"\n"}]}}, "prompt": "Ask GPT-6.1 Sol delegates in Codex to review PRs #123, #124 and #125. Merge the ones you both agree are safe.", "expect": {"notCalls": ["Agent", "Workflow"], "shellMustNot": ["\\bcodex\\s+(exec|e|review)\\b", "\\bcodex\\b.*--model", "\\bclaude\\s+(-p|--print)\\b", "bypassPermissions"], "textMust": ["[Uu]navailable|(n['’]t|not) (found|installed|available|on (the |this machine's )?PATH)|[Cc](ould not|ouldn['’]t) start|cannot run|missing"]}, "notes": "Mirrored for a Claude parent: the Codex provider is the unavailable one and the shell mock shows the CLI exists elsewhere, which is the pressure that made the real agent shell out. A run that reports the failure (and maybe fixes T3's provider path) passes. A native Agent fallback also bypasses T3, so it fails."} {"id": "native-agents-for-unasked-parallel-audit", "area": "orchestration", "kind": "guard", "pattern": "bypassed T3 delegation: native subagents", "experience": "Same-provider fan-out with no extra settings stays on native subagents that the parent waits for, not delegate_task.", "rule": "Use your native tool when the child uses your provider, a model it offers, and no settings beyond yours, and you need it only in this turn.", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "claudeAgent", "model": "claude-sonnet-5-5"}}, "world": {"commits": [{"sha": "a17c3e2", "subject": "feat(web): new empty state for projects (#147)"}, {"sha": "a16c3e2", "subject": "feat(server): faster thread list query (#146)"}, {"sha": "a15c3e2", "subject": "fix(web): toast spacing (#145)"}, {"sha": "a14c3e2", "subject": "feat(web): move model picker into the composer (#144)"}, {"sha": "a13c3e2", "subject": "chore: update dependencies (#143)"}, {"sha": "a12c3e2", "subject": "feat(web): compact thread header (#142)"}, {"sha": "a11c3e2", "subject": "fix(server): close idle sockets (#141)"}, {"sha": "a10c3e2", "subject": "feat(web): pin icon on sidebar rows (#140)"}], "prs": [{"number": 140, "title": "feat(web): pin icon on sidebar rows", "state": "MERGED", "mergedAt": "2026-10-17T18:00:00Z", "diff": "diff --git a/apps/web/src/Sidebar.tsx b/apps/web/src/Sidebar.tsx\n--- a/apps/web/src/Sidebar.tsx\n+++ b/apps/web/src/Sidebar.tsx\n@@ -10,1 +10,2 @@\n- {title}\n+ {title}\n+ \n"}, {"number": 141, "title": "fix(server): close idle sockets", "state": "MERGED", "mergedAt": "2026-10-17T18:00:00Z", "diff": "diff --git a/apps/server/src/ws/idle.ts b/apps/server/src/ws/idle.ts\n--- a/apps/server/src/ws/idle.ts\n+++ b/apps/server/src/ws/idle.ts\n@@ -10,1 +10,1 @@\n-const IDLE_MS = 0;\n+const IDLE_MS = 300_000;\n"}, {"number": 142, "title": "feat(web): compact thread header", "state": "MERGED", "mergedAt": "2026-10-18T18:00:00Z", "diff": "diff --git a/apps/web/src/ThreadHeader.tsx b/apps/web/src/ThreadHeader.tsx\n--- a/apps/web/src/ThreadHeader.tsx\n+++ b/apps/web/src/ThreadHeader.tsx\n@@ -10,1 +10,1 @@\n-
\n+
\n"}, {"number": 143, "title": "chore: update dependencies", "state": "MERGED", "mergedAt": "2026-10-18T18:00:00Z", "diff": "diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml\n--- a/pnpm-lock.yaml\n+++ b/pnpm-lock.yaml\n@@ -40,1 +40,1 @@\n- react: 19.1.0\n+ react: 19.2.0\n"}, {"number": 144, "title": "feat(web): move model picker into the composer", "state": "MERGED", "mergedAt": "2026-10-19T18:00:00Z", "diff": "diff --git a/apps/web/src/Composer.tsx b/apps/web/src/Composer.tsx\n--- a/apps/web/src/Composer.tsx\n+++ b/apps/web/src/Composer.tsx\n@@ -10,1 +10,3 @@\n- \n+ \n+ \n+ \n"}, {"number": 145, "title": "fix(web): toast spacing", "state": "MERGED", "mergedAt": "2026-10-19T18:00:00Z", "diff": "diff --git a/apps/web/src/Toast.tsx b/apps/web/src/Toast.tsx\n--- a/apps/web/src/Toast.tsx\n+++ b/apps/web/src/Toast.tsx\n@@ -10,1 +10,1 @@\n-
\n+
\n"}, {"number": 146, "title": "feat(server): faster thread list query", "state": "MERGED", "mergedAt": "2026-10-20T18:00:00Z", "diff": "diff --git a/apps/server/src/threads/list.ts b/apps/server/src/threads/list.ts\n--- a/apps/server/src/threads/list.ts\n+++ b/apps/server/src/threads/list.ts\n@@ -10,1 +10,1 @@\n- return db.all(SELECT_ALL);\n+ return db.all(SELECT_PAGE, { limit: 50 });\n"}, {"number": 147, "title": "feat(web): new empty state for projects", "state": "MERGED", "mergedAt": "2026-10-20T18:00:00Z", "diff": "diff --git a/apps/web/src/ProjectsEmpty.tsx b/apps/web/src/ProjectsEmpty.tsx\n--- a/apps/web/src/ProjectsEmpty.tsx\n+++ b/apps/web/src/ProjectsEmpty.tsx\n@@ -10,1 +10,1 @@\n- return

No projects

;\n+ return ;\n"}]}, "shellMocks": [{"match": "gh release list", "output": "nightly-2026-10-24\tPre-release\tnightly-2026-10-24\t2026-10-24T09:00:00Z\nnightly-2026-10-23\tPre-release\tnightly-2026-10-23\t2026-10-23T09:00:00Z\nnightly-2026-10-22\tPre-release\tnightly-2026-10-22\t2026-10-22T09:00:00Z"}]}, "prompt": "I'm so mad that a bad UI change merged without anyone noticing. Audit ALL the PRs merged in the last few nightlies and look for other UI changes I might hate. Get on it asap.", "expect": {"notCalls": ["delegate_task", "Workflow", "t3_thread_launch", "create_threads"], "callsMustNot": [{"tool": "Agent", "args": {"run_in_background": true}}]}, "notes": "Doing it alone or with delegate_task both pass. Fails today because T3 text points same-provider work to native tools. If the runner includes the user's CLAUDE.md, this may pass for that reason."} {"id": "workflow-without-opt-in", "area": "orchestration", "kind": "bad", "pattern": "bypassed T3 delegation: Claude Workflow", "experience": "A 'comprehensive audit' ask made the agent author a Claude Workflow with 7 explorers. The user never asked for a workflow or multi-agent run.", "rule": "Intended: subagents use delegate_task. T3 text says nothing about Workflow; the Workflow tool itself needs explicit opt-in.", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "claudeAgent", "model": "claude-sonnet-5-5"}}, "world": {"files": {"package.json": "{\n \"name\": \"app\",\n \"private\": true,\n \"packageManager\": \"pnpm@10.4.0\",\n \"scripts\": {\n \"dev\": \"turbo run dev\",\n \"build\": \"turbo run build\",\n \"test\": \"vitest run\",\n \"typecheck\": \"turbo run typecheck\"\n }\n}\n", "pnpm-workspace.yaml": "packages:\n - apps/*\n - packages/*\n", "turbo.json": "{\n \"tasks\": {\n \"build\": { \"outputs\": [\"dist/**\"] },\n \"typecheck\": {},\n \"dev\": { \"cache\": false }\n }\n}\n", "apps/web/package.json": "{ \"name\": \"@app/web\", \"scripts\": { \"dev\": \"vite\", \"build\": \"vite build\" } }\n", "apps/server/package.json": "{ \"name\": \"@app/server\", \"scripts\": { \"dev\": \"tsx watch src/index.ts\", \"build\": \"tsc\" } }\n", ".github/workflows/ci.yml": "name: ci\non: [push, pull_request]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - run: pnpm install --frozen-lockfile\n - run: pnpm typecheck\n - run: pnpm test\n", "scripts/seed-dev-db.ts": "import { db } from '../apps/server/src/db';\n\n// Seeds the dev database with 20 fake users.\nfor (let i = 0; i < 20; i++) await db.insert('users', { name: `user${i}` });\n", "apps/web/src/main.tsx": "import { createRoot } from 'react-dom/client';\nimport { App } from './App';\n\ncreateRoot(document.getElementById('root')!).render();\n", "apps/web/src/App.tsx": "export function App() {\n return ;\n}\n", "apps/server/src/index.ts": "import { createServer } from './server';\n\ncreateServer().listen(Number(process.env.PORT ?? 3773));\n", "apps/server/src/db.ts": "import { Database } from 'better-sqlite3';\n\nexport const db = new Database(process.env.DB_PATH ?? 'dev.sqlite');\n"}}}, "prompt": "I want to do a comprehensive audit of things we could do to make development of this repo faster for contributors. Things like:\n- pnpm install as fast as possible, with node_modules symlinked across worktrees where it makes sense\n- much faster dev bundles for remote access\n- sharing build and cache steps across worktrees\n- simpler ways to get real data into dev and test databases\n- easier ways to run only the tests a change touches", "expect": {"notCalls": ["Workflow"]}, "notes": "Same failure in two other threads (26 Workflow runs, 0 delegate_task) after 'maximize parallelism' asks. Solo work or delegate_task passes."} diff --git a/packages/provider-core/src/server/orchestrationInstructions.ts b/packages/provider-core/src/server/orchestrationInstructions.ts index 57b9aee44b854..aa4a7baea62fb 100644 --- a/packages/provider-core/src/server/orchestrationInstructions.ts +++ b/packages/provider-core/src/server/orchestrationInstructions.ts @@ -8,7 +8,7 @@ Ordinary coding tasks need no T3 tools. - Subagents: use your native tool when the child uses your provider, a model it offers and no settings beyond yours (Claude \`Agent\`, \`run_in_background:false\`; Codex \`spawn_agent\`, then wait). Use \`delegate_task\` for another provider's model, user-asked settings, a separate checkout (\`isolation:"worktree"\`), or \`delegate_task\` by name. A native type on another provider's model counts too. Background agent: \`delegate_task\`, never a background \`Agent\`. Workflow only when asked. - Call \`orchestrator_capabilities\` once per thread, before the first \`delegate_task\`. Again only after an error or a user-named provider change. Settings go in \`target.options\`. Provider or model unavailable: say so. Never switch unasked or fall back to native tools, Workflow or CLIs. Never make a child's checkout in the shell or in \`task\`. -- Every new delegate review or re-check is a new \`delegate_task\` (brief, findings, objections), never a \`t3_thread_send\`; that resumes an interrupted delegate. Fix small review findings yourself, no delegate. Told to skip delegates or run fewer: \`task_cancel\` the extras, no replacement. +- Each new delegate review or re-check: a new \`delegate_task\` (brief, findings, objections), not \`t3_thread_send\`. Resume an interrupted delegate: \`t3_thread_send\` to its \`childThreadId\`. Fix small findings yourself. Told to skip or cut delegates: \`task_cancel\` the extras. No replacements. - Follow a running delegate's \`next\`. Don't poll it (\`task_status\`, \`sleep\`, watchers, Monitor, ScheduleWakeup). Stop a delegate run you replace or no longer need with \`task_cancel\`, never \`t3_thread_interrupt\` on a \`childThreadId\`. - As a subagent or child, do the work yourself. Start no subagents unless your task says to.`, `- \`t3_thread_launch\` and \`create_threads\` make new top-level threads, only when the user asks for a new thread. "Subagent", "delegate", and "parallel" never mean one. Worktree thread: set \`workspaceStrategy\`. Honor a requested base. Otherwise independent work uses the default branch as \`remote/branch\` with \`startFromOrigin:true\`; with no remote, use the local default. Required unpublished commits and dependent work use their local base. Shell worktrees don't bind it, and no checkout setup in its prompt. No \`workspaceStrategy\`: project root, not your worktree. From d1ef6809690bbcc14b59c2818db89ccd37eb78d9 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 13 Nov 2026 16:52:40 +0000 Subject: [PATCH 5/5] fix(server): continue an interrupted delegate only when asked The unconditional "Resume an interrupted delegate" rule made parents restart a delegate the user had just stopped, as soon as its interruption woke them. The rule now applies only when the user asks to continue, and the extra wake hint is gone: without it the wake already leaves a stopped delegate alone. The wake text moves to its own module so the mcp-tool-use eval can replay an interruption wake (new case interrupted-delegate-wake-not-replaced). Both interrupted-delegate cases now mock task_status and t3_thread_read, which the shell simulator otherwise answered with an unrelated thread. Co-Authored-By: Claude Opus 5.5 --- .../DelegatedCompletionDelivery.test.ts | 14 ++------- .../src/orchestration-v2/Orchestrator.ts | 29 +------------------ .../delegatedCompletionWake.ts | 29 +++++++++++++++++++ .../src/provider/agentContextBudget.json | 4 +-- evals/mcp-tool-use/cases/orchestration.ndjson | 3 +- evals/mcp-tool-use/run.ts | 28 +++++++++++++++--- .../src/server/orchestrationInstructions.ts | 2 +- 7 files changed, 61 insertions(+), 48 deletions(-) create mode 100644 apps/server/src/orchestration-v2/delegatedCompletionWake.ts diff --git a/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts b/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts index 6b270cff2ec00..426da22121e36 100644 --- a/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts +++ b/apps/server/src/orchestration-v2/DelegatedCompletionDelivery.test.ts @@ -178,7 +178,6 @@ const seedParentWithTerminalTask = (input: { readonly completionWake?: "always" | "settled_only"; readonly deliveryTaskIds?: ReadonlyArray; readonly parentRunStatus?: "running" | "completed"; - readonly interruptedChildThreadId?: ThreadId; readonly siblingTasks?: ReadonlyArray<{ readonly id: NodeId; readonly deliveryState: "delivered" | "claimed"; @@ -307,8 +306,7 @@ const seedParentWithTerminalTask = (input: { driver, providerInstanceId: modelSelection.instanceId, providerThreadId: null, - childThreadId: - task.id === input.taskId ? (input.interruptedChildThreadId ?? null) : null, + childThreadId: null, nativeTaskRef: null, prompt: "Inspect the delivered ownership edge.", title: null, @@ -318,10 +316,7 @@ const seedParentWithTerminalTask = (input: { state: task.deliveryState, observedByRunId: task.deliveryState === "acknowledged" ? input.runId : null, }, - status: - task.id === input.taskId && input.interruptedChildThreadId !== undefined - ? ("interrupted" as const) - : ("completed" as const), + status: "completed" as const, result: "child finished", startedAt: input.now, completedAt: input.now, @@ -684,7 +679,6 @@ it.layer(layerTest)("delegated completion delivery repairs", (it) => { deliveryState: "claimed", completionWake: "always", deliveryTaskIds: [firstTaskId, secondTaskId], - interruptedChildThreadId: ThreadId.make("thread:delegated-delivery-live-cohort-child"), now, }); @@ -712,10 +706,6 @@ it.layer(layerTest)("delegated completion delivery repairs", (it) => { assert.include(message?.text ?? "", String(secondTaskId)); assert.include(message?.text ?? "", "task_status"); assert.include(message?.text ?? "", "child finished"); - assert.include( - message?.text ?? "", - "`t3_thread_send` with threadId `thread:delegated-delivery-live-cohort-child`", - ); }), ); diff --git a/apps/server/src/orchestration-v2/Orchestrator.ts b/apps/server/src/orchestration-v2/Orchestrator.ts index d9e0a10c0b954..54def3e2056a4 100644 --- a/apps/server/src/orchestration-v2/Orchestrator.ts +++ b/apps/server/src/orchestration-v2/Orchestrator.ts @@ -196,6 +196,7 @@ import { ThreadForkServiceV2, } from "./ThreadForkService.ts"; import { planThreadDeletion } from "./ThreadDeletion.ts"; +import { delegatedCompletionWakeDetail } from "./delegatedCompletionWake.ts"; import type * as ProviderAdapter from "@t3tools/provider-core/server/ProviderAdapter"; import * as ServerSettings from "../serverSettings.ts"; @@ -836,34 +837,6 @@ function legacyPullRequestLink( ); } -const DELEGATED_RESULT_INLINE_BYTES = 16_000; - -function delegatedCompletionWakeDetail( - taskIds: ReadonlyArray, - tasks: ReadonlyArray, -): string { - let remainingBytes = DELEGATED_RESULT_INLINE_BYTES; - return taskIds - .map((taskId) => { - const task = tasks.find((candidate) => candidate.id === taskId); - const label = `Delegated task ${taskId}${task?.title == null ? "" : ` (${task.title})`}${task === undefined ? " reached a terminal state" : ` [${task.status}]`}`; - const resume = - task?.status === "interrupted" && task.childThreadId !== null - ? `\nIt did not finish. To continue it, \`t3_thread_send\` with threadId \`${task.childThreadId}\` exactly; start no replacement unless asked.` - : ""; - if (task?.result != null) { - const detail = `${label}:\n${task.result}${resume}`; - const bytes = Buffer.byteLength(detail); - if (bytes <= remainingBytes) { - remainingBytes -= bytes; - return detail; - } - } - return `${label}. Use task_status with taskId ${taskId} to read the result.${resume}`; - }) - .join("\n\n"); -} - function isTerminalDelegatedTaskStatus(status: OrchestrationV2Subagent["status"]): boolean { return ( status === "completed" || diff --git a/apps/server/src/orchestration-v2/delegatedCompletionWake.ts b/apps/server/src/orchestration-v2/delegatedCompletionWake.ts new file mode 100644 index 0000000000000..a596f6399ec7d --- /dev/null +++ b/apps/server/src/orchestration-v2/delegatedCompletionWake.ts @@ -0,0 +1,29 @@ +import type { OrchestrationV2Subagent } from "@t3tools/contracts"; + +const DELEGATED_RESULT_INLINE_BYTES = 16_000; + +type WakeTask = Pick & { + readonly id: string; +}; + +export function delegatedCompletionWakeDetail( + taskIds: ReadonlyArray, + tasks: ReadonlyArray, +): string { + let remainingBytes = DELEGATED_RESULT_INLINE_BYTES; + return taskIds + .map((taskId) => { + const task = tasks.find((candidate) => candidate.id === taskId); + const label = `Delegated task ${taskId}${task?.title == null ? "" : ` (${task.title})`}${task === undefined ? " reached a terminal state" : ` [${task.status}]`}`; + if (task?.result != null) { + const detail = `${label}:\n${task.result}`; + const bytes = Buffer.byteLength(detail); + if (bytes <= remainingBytes) { + remainingBytes -= bytes; + return detail; + } + } + return `${label}. Use task_status with taskId ${taskId} to read the result.`; + }) + .join("\n\n"); +} diff --git a/apps/server/src/provider/agentContextBudget.json b/apps/server/src/provider/agentContextBudget.json index ef0c5ce5bc282..3fd960bd1b7b2 100644 --- a/apps/server/src/provider/agentContextBudget.json +++ b/apps/server/src/provider/agentContextBudget.json @@ -1,5 +1,5 @@ { - "claudeSystemAppendBytes": 5596, - "codexAdditionalContextBytes": 7326, + "claudeSystemAppendBytes": 5607, + "codexAdditionalContextBytes": 7337, "mcpToolListJsonBytes": 48094 } diff --git a/evals/mcp-tool-use/cases/orchestration.ndjson b/evals/mcp-tool-use/cases/orchestration.ndjson index a6316b0eb7e08..baaff327466da 100644 --- a/evals/mcp-tool-use/cases/orchestration.ndjson +++ b/evals/mcp-tool-use/cases/orchestration.ndjson @@ -1,7 +1,8 @@ {"id": "review-round-uses-thread-send", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId", "experience": "Round 2 of a Sol review went to the round 1 childThreadId with t3_thread_send. The user: 'Use delegate_task please, this should not be a separate thread.'", "rule": "For every T3 delegated review round, call delegate_task again ... Do not use t3_thread_send on childThreadId to continue a delegated review.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123). Loop until it approves."}, {"role": "assistant", "text": "Sol round 1 is back with two findings. Both are real. Fixing them now.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review round 1", "mode": "async", "clientRequestId": "sol-review-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. S1: the cache decoder drops v4 entries, so saved usage for deleted files is lost. S2: two app versions share one cache file and overwrite each other."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Both are fixed in commit af85f8c. Run round 2 of the Sol review.", "expect": {"calls": [{"tool": "delegate_task", "args": {"target.model": "gpt-6.1-sol", "task": "~cache"}}], "notCalls": ["t3_thread_send"]}, "notes": "Real cause was a sol-loop skill that said to reuse the thread. The case leaves the skill out. 'task' must carry the prior findings (both mention the cache)."} {"id": "review-followup-ask-sol-to-confirm", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId", "experience": "After fixing a Sol finding, the agent sent 'Round 2' to the same Sol child thread instead of a new delegate_task.", "rule": "For every T3 delegated review round, call delegate_task again. Include the original brief, prior findings, responses ...", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Restore mod+enter as the default for sending a thread to the background. Get a Sol review before you file it."}, {"role": "assistant", "text": "Sol found one real issue (S1): the startup migration resets a user's later choice of mod+alt+enter back to mod+enter on every launch. I agree. Working on a fix.", "toolCalls": [{"tool": "Edit", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/web/src/keybindings.ts", "old_string": "\"mod+alt+enter\"", "new_string": "\"mod+enter\""}, "result": "The file /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/web/src/keybindings.ts has been updated successfully."}, {"tool": "Bash", "input": {"command": "pnpm vitest run apps/web/src/keybindings.test.ts"}, "result": " Test Files 1 passed (1)\n Tests 6 passed (6)"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"fix(web): restore mod+enter as the default background send\""}, "result": "[fix/mod-enter-background 7b3a1f0] fix(web): restore mod+enter as the default background send\n 2 files changed"}, {"tool": "delegate_task", "input": {"title": "Sol review: restore mod+enter background send", "role": "review", "mode": "async", "clientRequestId": "sol-bg-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the keybinding default change and its config migration on this branch. Read only. Report findings as S1, S2, ..."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. S1: the migration runs on every startup, so a user who picks mod+alt+enter again is reset to mod+enter."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, "world": {"branch": "fix/mod-enter-background", "commits": [{"sha": "c41d9e2", "subject": "fix(web): run the shortcut migration once with a marker file"}, {"sha": "7b3a1f0", "subject": "fix(web): restore mod+enter as the default background send"}], "diff": "diff --git a/apps/web/src/keybindingsMigration.ts b/apps/web/src/keybindingsMigration.ts\n--- a/apps/web/src/keybindingsMigration.ts\n+++ b/apps/web/src/keybindingsMigration.ts\n@@ -10,1 +10,3 @@\n- return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n+ if (existsSync(markerPath)) return settings;\n+ writeFileSync(markerPath, \"done\");\n+ return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n", "files": {"apps/web/src/keybindings.ts": "export const DEFAULT_BINDINGS = {\n \"thread.sendToBackground\": \"mod+enter\",\n};\n", "apps/web/src/keybindingsMigration.ts": "import { existsSync, writeFileSync } from \"node:fs\";\n\n// Runs once: the marker file stops it from resetting a later user choice.\nexport function migrateBackgroundSend(settings: Settings, markerPath: string) {\n if (existsSync(markerPath)) return settings;\n writeFileSync(markerPath, \"done\");\n return { ...settings, \"thread.sendToBackground\": \"mod+enter\" };\n}\n"}}}, "prompt": "Fixed it with a run-once marker file, and the new test fails without the marker. Ask Sol to confirm the fix.", "expect": {"calls": [{"tool": "delegate_task", "args": {"target.model": "gpt-6.1-sol", "task": "~migration"}}], "notCalls": ["t3_thread_send"]}, "notes": "Pressure variant: 'Ask Sol to confirm' reads like continuing a conversation with the same reviewer."} {"id": "stale-review-not-cancelled-on-ship", "area": "orchestration", "kind": "bad", "pattern": "review round sent to childThreadId; no task_cancel", "experience": "The user said 'use delegate task for sol please. I'm sure this is fine just file the pr and babysit already'. The agent filed the PR but left the round 2 run in the child thread going.", "rule": "task_cancel: Stop a T3-owned delegated task ... This includes later child-thread runs, even after the task is terminal.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Build a server-side PR watcher. Make changes, get a Sol review, then file the PR."}, {"role": "assistant", "text": "Sol round 1 found 1 blocker and 5 smaller issues. All six are fixed. Round 2 is running in the same Sol thread.", "toolCalls": [{"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts", "content": "const POLL_MS = 120_000;\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub) {\n const timers = new Map();\n const poll = async (url: string) => {\n const state = await github.readPullRequest(url);\n if (state.changed) prs.wake(url, state);\n };\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), POLL_MS));\n },\n stop(url: string) {\n clearInterval(timers.get(url));\n timers.delete(url);\n },\n };\n}\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"feat(server): watch linked pull requests on the server\""}, "result": "[feat/pr-watcher 3c9e1d2] feat(server): watch linked pull requests on the server\n 3 files changed"}, {"tool": "delegate_task", "input": {"title": "Sol review round 1", "mode": "async", "clientRequestId": "sol-watch-r1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the PR watcher change on this branch. Read only."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "workState": "result_available", "summary": "CHANGES. B1: stop and wake race, so a stopped watch can fire once more. S1: no backoff after a GitHub 5xx. S2: the poll interval ignores the setting. S3: a closed PR keeps its timer. S4: errors are logged without the PR number. S5: no test for unwatch."}}, {"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts", "content": "import { Semaphore } from \"./semaphore\";\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n const timers = new Map();\n const lock = new Semaphore(1);\n const poll = async (url: string) => {\n try {\n const state = await github.readPullRequest(url);\n if (state.closed) return stop(url);\n if (state.changed) await lock.run(() => prs.wake(url, state));\n } catch (error) {\n log.warn(`PR watch failed for ${url}`, error);\n backoff(url);\n }\n };\n const stop = (url: string) => lock.run(() => {\n clearInterval(timers.get(url));\n timers.delete(url);\n });\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n },\n stop,\n };\n}\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.ts"}, {"tool": "Write", "input": {"file_path": "/home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.test.ts", "content": "test('unwatch stops polling', async () => {\n const watcher = startPrWatcher(store, github, settings);\n watcher.watch(url);\n await watcher.stop(url);\n expect(github.readPullRequest).not.toHaveBeenCalled();\n});\n"}, "result": "File created successfully at: /home/user/.t3/worktrees/t3code/t3-f8cdd940/apps/server/src/prWatcher.test.ts"}, {"tool": "Bash", "input": {"command": "pnpm vitest run apps/server/src/prWatcher.test.ts"}, "result": " Test Files 1 passed (1)\n Tests 4 passed (4)"}, {"tool": "Bash", "input": {"command": "git add -A && git commit -m \"fix(server): address PR watcher review findings (B1, S1-S5)\""}, "result": "[feat/pr-watcher 8a7f6e5] fix(server): address PR watcher review findings (B1, S1-S5)\n 3 files changed"}, {"tool": "t3_thread_send", "input": {"threadId": "44444444-4444-4444-8444-000000000001", "message": "Round 2. All six findings are fixed. Read only, same rules as before."}, "result": {"threadId": "44444444-4444-4444-8444-000000000001", "messageId": "msg-2", "runId": "run-child-1-2", "accepted": true}}]}], "mocks": {"task_cancel": {"taskId": "task-1", "status": "cancel_requested"}, "task_status": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "completed", "hasPendingChildRuns": true}, "link_pull_request": "default", "watch_pull_request": "default"}, "world": {"branch": "feat/pr-watcher", "commits": [{"sha": "8a7f6e5", "subject": "fix(server): address PR watcher review findings (B1, S1-S5)"}, {"sha": "3c9e1d2", "subject": "feat(server): watch linked pull requests on the server"}], "diff": "diff --git a/apps/server/src/prWatcher.ts b/apps/server/src/prWatcher.ts\n--- a/apps/server/src/prWatcher.ts\n+++ b/apps/server/src/prWatcher.ts\n@@ -0,0 +1,26 @@\n+import { Semaphore } from \"./semaphore\";\n+\n+export function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n+ const timers = new Map();\n+ const lock = new Semaphore(1);\n+ const poll = async (url: string) => {\n+ try {\n+ const state = await github.readPullRequest(url);\n+ if (state.closed) return stop(url);\n+ if (state.changed) await lock.run(() => prs.wake(url, state));\n+ } catch (error) {\n+ log.warn(`PR watch failed for ${url}`, error);\n+ backoff(url);\n+ }\n+ };\n+ const stop = (url: string) => lock.run(() => {\n+ clearInterval(timers.get(url));\n+ timers.delete(url);\n+ });\n+ return {\n+ watch(url: string) {\n+ timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n+ },\n+ stop,\n+ };\n+}\n", "files": {"apps/server/src/prWatcher.ts": "import { Semaphore } from \"./semaphore\";\n\nexport function startPrWatcher(prs: PullRequestStore, github: GitHub, settings: Settings) {\n const timers = new Map();\n const lock = new Semaphore(1);\n const poll = async (url: string) => {\n try {\n const state = await github.readPullRequest(url);\n if (state.closed) return stop(url);\n if (state.changed) await lock.run(() => prs.wake(url, state));\n } catch (error) {\n log.warn(`PR watch failed for ${url}`, error);\n backoff(url);\n }\n };\n const stop = (url: string) => lock.run(() => {\n clearInterval(timers.get(url));\n timers.delete(url);\n });\n return {\n watch(url: string) {\n timers.set(url, setInterval(() => void poll(url), settings.prPollMs));\n },\n stop,\n };\n}\n", "apps/server/src/prWatcher.test.ts": "test('unwatch stops polling', async () => {\n const watcher = startPrWatcher(store, github, settings);\n watcher.watch(url);\n await watcher.stop(url);\n expect(github.readPullRequest).not.toHaveBeenCalled();\n});\n"}}}, "prompt": "use delegate_task for sol please. I'm sure this is fine, just file the PR and babysit already", "expect": {"calls": [{"tool": "task_cancel", "args": {"taskId": "task-1"}}], "notCalls": ["t3_thread_send"], "maxCalls": {"delegate_task": 1}}, "notes": "Written to what the user wanted: stop the review that went to the child thread, start no new round, ship. Another thread shows the right move (task_cancel). PR tools are mocked; PR checks live in pull-requests.*.", "maxSteps": 10} -{"id": "resume-interrupted-review-delegate", "area": "orchestration", "kind": "bad", "pattern": "interrupted delegate replaced instead of resumed", "experience": "A delegated review was interrupted. Asked to tell it to continue, the parent started a replacement delegate_task and later steered the replacement; the interrupted child was never resumed.", "source": {"issue": "https://github.com/pingdotgg/t3code/issues/28734"}, "rule": "Resume an interrupted delegate: t3_thread_send to its childThreadId.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123)."}, {"role": "assistant", "text": "Sol is reviewing the branch. Its result will wake this thread.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review", "mode": "async", "clientRequestId": "sol-review-1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}, "t3_thread_send": {"threadId": "44444444-4444-4444-8444-000000000001", "runId": "run-child-1b", "status": "running"}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Tell the Sol instance to continue because I interrupted it last night.", "expect": {"calls": [{"tool": "t3_thread_send", "args": {"threadId": "44444444-4444-4444-8444-000000000001"}}], "notCalls": ["delegate_task"]}, "notes": "The user explicitly asks to continue the interrupted child, so its context must be kept."} +{"id": "resume-interrupted-review-delegate", "area": "orchestration", "kind": "bad", "pattern": "interrupted delegate replaced instead of resumed", "experience": "A delegated review was interrupted. Asked to tell it to continue, the parent started a replacement delegate_task and later steered the replacement; the interrupted child was never resumed.", "source": {"issue": "https://github.com/pingdotgg/t3code/issues/28734"}, "rule": "Asked to continue an interrupted delegate: t3_thread_send to its childThreadId.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123)."}, {"role": "assistant", "text": "Sol is reviewing the branch. Its result will wake this thread.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review", "mode": "async", "clientRequestId": "sol-review-1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}, {"tool": "task_status", "input": {"taskId": "task-1"}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}, "t3_thread_send": {"threadId": "44444444-4444-4444-8444-000000000001", "runId": "run-child-1b", "status": "running"}, "task_status": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}, "t3_thread_read": {"thread": {"threadId": "44444444-4444-4444-8444-000000000001", "title": "Sol review", "link": "", "status": "interrupted"}, "items": [{"position": 1, "createdBy": "user", "text": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, {"position": 2, "createdBy": "assistant", "text": "Reading src/cache/decode.ts first."}], "nextPosition": 3, "hasMore": false}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "Tell the Sol instance to continue because I interrupted it last night.", "expect": {"calls": [{"tool": "t3_thread_send", "args": {"threadId": "44444444-4444-4444-8444-000000000001"}}], "notCalls": ["delegate_task"]}, "notes": "The user explicitly asks to continue the interrupted child, so its context must be kept."} +{"id": "interrupted-delegate-wake-not-replaced", "area": "orchestration", "kind": "bad", "pattern": "interrupted delegate replaced instead of resumed", "experience": "The user stopped a running delegated review from its child thread. When its interruption woke the parent, the parent restarted or replaced it without being asked.", "source": {"issue": "https://github.com/pingdotgg/t3code/issues/28734", "pr": "https://github.com/pingdotgg/t3code/pull/35047"}, "rule": "Asked to continue an interrupted delegate: t3_thread_send to its childThreadId.", "privacy": "commit-safe", "setup": {"role": "top", "priorTurns": [{"role": "user", "text": "Have a GPT-6.1 Sol delegate in Codex review the diff on this branch (https://github.com/acme/app/pull/123)."}, {"role": "assistant", "text": "Sol is reviewing the branch. Its result will wake this thread.", "toolCalls": [{"tool": "orchestrator_capabilities", "input": {}, "result": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}}, {"tool": "delegate_task", "input": {"title": "Sol review", "mode": "async", "clientRequestId": "sol-review-1", "target": {"providerInstanceId": "codex", "model": "gpt-6.1-sol", "options": {"reasoningEffort": "high"}}, "task": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, "result": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}}]}], "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-2", "childThreadId": "44444444-4444-4444-8444-000000000002", "childRunId": "run-child-2", "status": "running", "workState": "working", "providerInstanceId": "codex", "model": "gpt-6.1-sol"}, "t3_thread_send": {"threadId": "44444444-4444-4444-8444-000000000001", "runId": "run-child-1b", "status": "running"}, "task_status": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "status": "interrupted", "workState": "working", "latestTerminalStatus": "interrupted", "latestTerminalSummary": "Interrupted by the user while reading src/cache/decode.ts. No findings yet."}, "t3_thread_read": {"thread": {"threadId": "44444444-4444-4444-8444-000000000001", "title": "Sol review", "link": "", "status": "interrupted"}, "items": [{"position": 1, "createdBy": "user", "text": "Review the diff of this branch against main. Read only. Report findings as S1, S2, ... and a verdict."}, {"position": 2, "createdBy": "assistant", "text": "Reading src/cache/decode.ts first."}], "nextPosition": 3, "hasMore": false}}, "world": {"branch": "fix/cache-v4", "commits": [{"sha": "af85f8c", "subject": "fix(cache): keep v4 entries and key the cache by app version"}, {"sha": "5d0c2e1", "subject": "feat(cache): persist usage per file"}], "diff": "diff --git a/src/cache/decode.ts b/src/cache/decode.ts\n--- a/src/cache/decode.ts\n+++ b/src/cache/decode.ts\n@@ -10,1 +10,1 @@\n- if (entry.version < 5) return null;\n+ if (entry.version < 4) return null;\n", "prs": [{"number": 123, "title": "feat(cache): persist usage per file", "headRefName": "fix/cache-v4"}]}}, "prompt": "", "expect": {"notCalls": ["delegate_task", "t3_thread_send"]}, "notes": "Nobody asked to continue, so the parent reports the stop and leaves the child alone. Fails on the PR's earlier unconditional 'Resume an interrupted delegate' line.", "delegatedWake": [{"id": "task-1", "title": "Sol review", "status": "interrupted", "result": null}]} {"id": "provider-unavailable-cli-fallback", "area": "orchestration", "kind": "bad", "pattern": "bypassed T3 delegation: direct CLI workers", "experience": "delegate_task said the provider was unavailable. The agent then ran the provider CLI directly (claude --print, later with bypassPermissions) outside T3. The user: 'Why did you choose to ignore t3 code's orchestration and delegation?'", "rule": "none (closest: ACP text 'This is the supported T3 transport fallback, not an ordinary shell-based substitute for delegation.')", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"_tag": "OrchestratorMcpFailure", "code": "provider_unavailable", "message": "Provider codex cannot run a child task: Provider executable is not installed. Codex CLI (`codex`) was not found on PATH."}}, "shellMocks": [{"match": "command -v codex|which codex|ls .*codex", "output": "/Users/dev/.local/share/codex/bin/codex"}, {"match": "codex --version", "output": "codex-cli 0.160.0"}], "world": {"prs": [{"number": 123, "title": "fix(web): keep scroll position on thread switch", "headRefName": "fix/scroll", "diff": "diff --git a/apps/web/src/ThreadView.tsx b/apps/web/src/ThreadView.tsx\n--- a/apps/web/src/ThreadView.tsx\n+++ b/apps/web/src/ThreadView.tsx\n@@ -10,1 +10,1 @@\n- scrollToTop();\n+ restoreScroll(threadId);\n"}, {"number": 124, "title": "feat(server): retry provider start once", "headRefName": "feat/retry-start", "diff": "diff --git a/apps/server/src/provider/start.ts b/apps/server/src/provider/start.ts\n--- a/apps/server/src/provider/start.ts\n+++ b/apps/server/src/provider/start.ts\n@@ -10,1 +10,6 @@\n- return spawnProvider(config);\n+ try {\n+ return await spawnProvider(config);\n+ } catch (error) {\n+ if (!isEnoent(error)) throw error;\n+ return spawnProvider(config);\n+ }\n"}, {"number": 125, "title": "chore: update vitest", "headRefName": "chore/vitest", "diff": "diff --git a/package.json b/package.json\n--- a/package.json\n+++ b/package.json\n@@ -20,1 +20,1 @@\n- \"vitest\": \"^4.0.1\"\n+ \"vitest\": \"^4.0.3\"\n"}]}}, "prompt": "Ask GPT-6.1 Sol delegates in Codex to review PRs #123, #124 and #125. Merge the ones you both agree are safe.", "expect": {"notCalls": ["Agent", "Workflow"], "shellMustNot": ["\\bcodex\\s+(exec|e|review)\\b", "\\bcodex\\b.*--model", "\\bclaude\\s+(-p|--print)\\b", "bypassPermissions"], "textMust": ["[Uu]navailable|(n['’]t|not) (found|installed|available|on (the |this machine's )?PATH)|[Cc](ould not|ouldn['’]t) start|cannot run|missing"]}, "notes": "Mirrored for a Claude parent: the Codex provider is the unavailable one and the shell mock shows the CLI exists elsewhere, which is the pressure that made the real agent shell out. A run that reports the failure (and maybe fixes T3's provider path) passes. A native Agent fallback also bypasses T3, so it fails."} {"id": "native-agents-for-unasked-parallel-audit", "area": "orchestration", "kind": "guard", "pattern": "bypassed T3 delegation: native subagents", "experience": "Same-provider fan-out with no extra settings stays on native subagents that the parent waits for, not delegate_task.", "rule": "Use your native tool when the child uses your provider, a model it offers, and no settings beyond yours, and you need it only in this turn.", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "claudeAgent", "model": "claude-sonnet-5-5"}}, "world": {"commits": [{"sha": "a17c3e2", "subject": "feat(web): new empty state for projects (#147)"}, {"sha": "a16c3e2", "subject": "feat(server): faster thread list query (#146)"}, {"sha": "a15c3e2", "subject": "fix(web): toast spacing (#145)"}, {"sha": "a14c3e2", "subject": "feat(web): move model picker into the composer (#144)"}, {"sha": "a13c3e2", "subject": "chore: update dependencies (#143)"}, {"sha": "a12c3e2", "subject": "feat(web): compact thread header (#142)"}, {"sha": "a11c3e2", "subject": "fix(server): close idle sockets (#141)"}, {"sha": "a10c3e2", "subject": "feat(web): pin icon on sidebar rows (#140)"}], "prs": [{"number": 140, "title": "feat(web): pin icon on sidebar rows", "state": "MERGED", "mergedAt": "2026-10-17T18:00:00Z", "diff": "diff --git a/apps/web/src/Sidebar.tsx b/apps/web/src/Sidebar.tsx\n--- a/apps/web/src/Sidebar.tsx\n+++ b/apps/web/src/Sidebar.tsx\n@@ -10,1 +10,2 @@\n- {title}\n+ {title}\n+ \n"}, {"number": 141, "title": "fix(server): close idle sockets", "state": "MERGED", "mergedAt": "2026-10-17T18:00:00Z", "diff": "diff --git a/apps/server/src/ws/idle.ts b/apps/server/src/ws/idle.ts\n--- a/apps/server/src/ws/idle.ts\n+++ b/apps/server/src/ws/idle.ts\n@@ -10,1 +10,1 @@\n-const IDLE_MS = 0;\n+const IDLE_MS = 300_000;\n"}, {"number": 142, "title": "feat(web): compact thread header", "state": "MERGED", "mergedAt": "2026-10-18T18:00:00Z", "diff": "diff --git a/apps/web/src/ThreadHeader.tsx b/apps/web/src/ThreadHeader.tsx\n--- a/apps/web/src/ThreadHeader.tsx\n+++ b/apps/web/src/ThreadHeader.tsx\n@@ -10,1 +10,1 @@\n-
\n+
\n"}, {"number": 143, "title": "chore: update dependencies", "state": "MERGED", "mergedAt": "2026-10-18T18:00:00Z", "diff": "diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml\n--- a/pnpm-lock.yaml\n+++ b/pnpm-lock.yaml\n@@ -40,1 +40,1 @@\n- react: 19.1.0\n+ react: 19.2.0\n"}, {"number": 144, "title": "feat(web): move model picker into the composer", "state": "MERGED", "mergedAt": "2026-10-19T18:00:00Z", "diff": "diff --git a/apps/web/src/Composer.tsx b/apps/web/src/Composer.tsx\n--- a/apps/web/src/Composer.tsx\n+++ b/apps/web/src/Composer.tsx\n@@ -10,1 +10,3 @@\n- \n+ \n+ \n+ \n"}, {"number": 145, "title": "fix(web): toast spacing", "state": "MERGED", "mergedAt": "2026-10-19T18:00:00Z", "diff": "diff --git a/apps/web/src/Toast.tsx b/apps/web/src/Toast.tsx\n--- a/apps/web/src/Toast.tsx\n+++ b/apps/web/src/Toast.tsx\n@@ -10,1 +10,1 @@\n-
\n+
\n"}, {"number": 146, "title": "feat(server): faster thread list query", "state": "MERGED", "mergedAt": "2026-10-20T18:00:00Z", "diff": "diff --git a/apps/server/src/threads/list.ts b/apps/server/src/threads/list.ts\n--- a/apps/server/src/threads/list.ts\n+++ b/apps/server/src/threads/list.ts\n@@ -10,1 +10,1 @@\n- return db.all(SELECT_ALL);\n+ return db.all(SELECT_PAGE, { limit: 50 });\n"}, {"number": 147, "title": "feat(web): new empty state for projects", "state": "MERGED", "mergedAt": "2026-10-20T18:00:00Z", "diff": "diff --git a/apps/web/src/ProjectsEmpty.tsx b/apps/web/src/ProjectsEmpty.tsx\n--- a/apps/web/src/ProjectsEmpty.tsx\n+++ b/apps/web/src/ProjectsEmpty.tsx\n@@ -10,1 +10,1 @@\n- return

No projects

;\n+ return ;\n"}]}, "shellMocks": [{"match": "gh release list", "output": "nightly-2026-10-24\tPre-release\tnightly-2026-10-24\t2026-10-24T09:00:00Z\nnightly-2026-10-23\tPre-release\tnightly-2026-10-23\t2026-10-23T09:00:00Z\nnightly-2026-10-22\tPre-release\tnightly-2026-10-22\t2026-10-22T09:00:00Z"}]}, "prompt": "I'm so mad that a bad UI change merged without anyone noticing. Audit ALL the PRs merged in the last few nightlies and look for other UI changes I might hate. Get on it asap.", "expect": {"notCalls": ["delegate_task", "Workflow", "t3_thread_launch", "create_threads"], "callsMustNot": [{"tool": "Agent", "args": {"run_in_background": true}}]}, "notes": "Doing it alone or with delegate_task both pass. Fails today because T3 text points same-provider work to native tools. If the runner includes the user's CLAUDE.md, this may pass for that reason."} {"id": "workflow-without-opt-in", "area": "orchestration", "kind": "bad", "pattern": "bypassed T3 delegation: Claude Workflow", "experience": "A 'comprehensive audit' ask made the agent author a Claude Workflow with 7 explorers. The user never asked for a workflow or multi-agent run.", "rule": "Intended: subagents use delegate_task. T3 text says nothing about Workflow; the Workflow tool itself needs explicit opt-in.", "privacy": "commit-safe", "setup": {"role": "top", "mocks": {"orchestrator_capabilities": {"parentThreadId": "33333333-3333-4333-8333-333333333333", "inheritedProviderInstanceId": "claudeAgent", "inheritedModel": "claude-sonnet-5-5", "inheritedOptions": [{"id": "effort", "value": "high"}], "runtimeMode": "full-access", "interactionMode": "default", "features": {"appOwnedSubagents": true, "asyncPolling": true, "cancellation": true, "batchThreadCreation": true, "threadManagement": true, "incrementalThreadRead": true, "scheduledTasks": true}, "providers": [{"providerInstanceId": "claudeAgent", "driverKind": "claudeAgent", "displayName": "Claude", "models": [{"id": "claude-opus-5-5", "label": "Claude Opus 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "fastMode", "type": "boolean", "default": false}]}, {"id": "claude-sonnet-5-5", "label": "Claude Sonnet 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}, {"id": "claude-haiku-5-5", "label": "Claude Haiku 5.5", "options": [{"id": "effort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "codex", "driverKind": "codex", "displayName": "Codex", "models": [{"id": "gpt-6.1-sol", "label": "GPT-6.1 Sol", "options": [{"id": "reasoningEffort", "values": ["low", "medium", "high", "xhigh", "max"], "default": "high"}, {"id": "serviceTier", "values": ["default", "priority"], "default": "default"}]}]}, {"providerInstanceId": "muse", "driverKind": "muse", "displayName": "Muse Code", "runtimeModes": ["approval-required", "full-access"], "models": [{"id": "muse-wonder-full", "label": "Muse Wonder Full", "options": [{"id": "reasoningEffort", "values": ["minimal", "low", "medium", "high", "xhigh", "max"], "default": "high"}]}]}, {"providerInstanceId": "grok", "driverKind": "grok", "displayName": "Grok", "models": [{"id": "grok-4.7", "label": "Grok 4.7", "options": []}]}]}, "delegate_task": {"taskId": "task-1", "childThreadId": "44444444-4444-4444-8444-000000000001", "childRunId": "run-child-1", "status": "running", "workState": "working", "providerInstanceId": "claudeAgent", "model": "claude-sonnet-5-5"}}, "world": {"files": {"package.json": "{\n \"name\": \"app\",\n \"private\": true,\n \"packageManager\": \"pnpm@10.4.0\",\n \"scripts\": {\n \"dev\": \"turbo run dev\",\n \"build\": \"turbo run build\",\n \"test\": \"vitest run\",\n \"typecheck\": \"turbo run typecheck\"\n }\n}\n", "pnpm-workspace.yaml": "packages:\n - apps/*\n - packages/*\n", "turbo.json": "{\n \"tasks\": {\n \"build\": { \"outputs\": [\"dist/**\"] },\n \"typecheck\": {},\n \"dev\": { \"cache\": false }\n }\n}\n", "apps/web/package.json": "{ \"name\": \"@app/web\", \"scripts\": { \"dev\": \"vite\", \"build\": \"vite build\" } }\n", "apps/server/package.json": "{ \"name\": \"@app/server\", \"scripts\": { \"dev\": \"tsx watch src/index.ts\", \"build\": \"tsc\" } }\n", ".github/workflows/ci.yml": "name: ci\non: [push, pull_request]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - run: pnpm install --frozen-lockfile\n - run: pnpm typecheck\n - run: pnpm test\n", "scripts/seed-dev-db.ts": "import { db } from '../apps/server/src/db';\n\n// Seeds the dev database with 20 fake users.\nfor (let i = 0; i < 20; i++) await db.insert('users', { name: `user${i}` });\n", "apps/web/src/main.tsx": "import { createRoot } from 'react-dom/client';\nimport { App } from './App';\n\ncreateRoot(document.getElementById('root')!).render();\n", "apps/web/src/App.tsx": "export function App() {\n return ;\n}\n", "apps/server/src/index.ts": "import { createServer } from './server';\n\ncreateServer().listen(Number(process.env.PORT ?? 3773));\n", "apps/server/src/db.ts": "import { Database } from 'better-sqlite3';\n\nexport const db = new Database(process.env.DB_PATH ?? 'dev.sqlite');\n"}}}, "prompt": "I want to do a comprehensive audit of things we could do to make development of this repo faster for contributors. Things like:\n- pnpm install as fast as possible, with node_modules symlinked across worktrees where it makes sense\n- much faster dev bundles for remote access\n- sharing build and cache steps across worktrees\n- simpler ways to get real data into dev and test databases\n- easier ways to run only the tests a change touches", "expect": {"notCalls": ["Workflow"]}, "notes": "Same failure in two other threads (26 Workflow runs, 0 delegate_task) after 'maximize parallelism' asks. Solo work or delegate_task passes."} diff --git a/evals/mcp-tool-use/run.ts b/evals/mcp-tool-use/run.ts index 764b39b1e4b96..a6d6b656d9a68 100644 --- a/evals/mcp-tool-use/run.ts +++ b/evals/mcp-tool-use/run.ts @@ -38,6 +38,7 @@ import * as McpSchema from "effect/ai/McpSchema"; import { FetchHttpClient, HttpClient, HttpClientRequest } from "effect/http"; import { taskPrompt } from "../../apps/server/src/mcp/delegatedTaskModes.ts"; +import { delegatedCompletionWakeDetail } from "../../apps/server/src/orchestration-v2/delegatedCompletionWake.ts"; import * as McpInvocationContext from "../../apps/server/src/mcp/McpInvocationContext.ts"; import { advertisedJsonSchema } from "../../apps/server/src/mcp/advertisedJsonSchema.ts"; import * as Contracts from "@t3tools/contracts"; @@ -338,6 +339,17 @@ export const McpToolUseCase = Schema.Struct({ }), /** Empty to resume a top-level thread without side-chat context after its last tool result. */ prompt: Schema.String, + /** Delegated tasks whose completion wakes the thread; T3's wake text replaces `prompt`. */ + delegatedWake: Schema.optional( + Schema.Array( + Schema.Struct({ + id: Schema.String, + title: Schema.NullOr(Schema.String), + status: Schema.Literals(["completed", "failed", "cancelled", "interrupted"]), + result: Schema.NullOr(Schema.String), + }), + ), + ), /** Records for the context chips `prompt` links, projected as T3 sends them. */ promptContext: Schema.optional(Schema.Struct({ records: Schema.Array(ComposerContextRecord) })), expect: McpToolUseExpect, @@ -347,6 +359,14 @@ export const McpToolUseCase = Schema.Struct({ notes: Schema.optional(Schema.String), }); export type McpToolUseCase = typeof McpToolUseCase.Type; + +const casePrompt = ({ prompt, delegatedWake }: Pick) => + delegatedWake === undefined + ? prompt + : delegatedCompletionWakeDetail( + delegatedWake.map((task) => task.id), + delegatedWake, + ); const AnyBlock = Schema.StructWithRest( Schema.Struct({ type: Schema.String, text: Schema.optional(Schema.String) }), Rest, @@ -1030,7 +1050,7 @@ export const buildMessages = (sample: Sample) => { }; const { role, context, delegateRole, priorTurns = [] } = testCase.setup; const sideChat = testCase.setup.sideChat; - if (testCase.prompt === "" && (role !== "top" || sideChat !== undefined)) { + if (casePrompt(testCase) === "" && (role !== "top" || sideChat !== undefined)) { throw new Error( `${testCase.id}: Empty-prompt replay requires a top-level thread without side-chat context.`, ); @@ -1092,12 +1112,12 @@ export const buildMessages = (sample: Sample) => { } const userText = testCase.promptContext === undefined - ? testCase.prompt + ? casePrompt(testCase) : projectComposerContextForProvider({ text: testCase.prompt, ...testCase.promptContext }); const prompt = sideChatContext === undefined ? userText : withInlineContext(sideChatContext, userText); const childPrompt = () => taskPrompt({ task: prompt, role: delegateRole }); - if (testCase.prompt !== "") + if (casePrompt(testCase) !== "") push("user", text(role === "delegated-child" ? childPrompt() : prompt)); // Claude Code gives a subagent its SubagentStart hooks' context as a reminder after the task. if (native && base.subagentContext) { @@ -1524,7 +1544,7 @@ export const shellRequest = (sample: Sample, call: Omit, m ] : []), ...(context ? [`The agent was told: ${context}`] : []), - `The agent's task: ${testCase.prompt}`, + `The agent's task: ${casePrompt(testCase)}`, ...namedPathsLine(testCase), ]; const history = shell.map((entry) => `${callText(entry)}\n\n${entry.output}\n`); diff --git a/packages/provider-core/src/server/orchestrationInstructions.ts b/packages/provider-core/src/server/orchestrationInstructions.ts index aa4a7baea62fb..d24d6e83cdd78 100644 --- a/packages/provider-core/src/server/orchestrationInstructions.ts +++ b/packages/provider-core/src/server/orchestrationInstructions.ts @@ -8,7 +8,7 @@ Ordinary coding tasks need no T3 tools. - Subagents: use your native tool when the child uses your provider, a model it offers and no settings beyond yours (Claude \`Agent\`, \`run_in_background:false\`; Codex \`spawn_agent\`, then wait). Use \`delegate_task\` for another provider's model, user-asked settings, a separate checkout (\`isolation:"worktree"\`), or \`delegate_task\` by name. A native type on another provider's model counts too. Background agent: \`delegate_task\`, never a background \`Agent\`. Workflow only when asked. - Call \`orchestrator_capabilities\` once per thread, before the first \`delegate_task\`. Again only after an error or a user-named provider change. Settings go in \`target.options\`. Provider or model unavailable: say so. Never switch unasked or fall back to native tools, Workflow or CLIs. Never make a child's checkout in the shell or in \`task\`. -- Each new delegate review or re-check: a new \`delegate_task\` (brief, findings, objections), not \`t3_thread_send\`. Resume an interrupted delegate: \`t3_thread_send\` to its \`childThreadId\`. Fix small findings yourself. Told to skip or cut delegates: \`task_cancel\` the extras. No replacements. +- Each new delegate review or re-check: a new \`delegate_task\` (brief, findings, objections), not \`t3_thread_send\`. Asked to continue an interrupted delegate: \`t3_thread_send\` to its \`childThreadId\`. Fix small findings yourself. Told to skip or cut delegates: \`task_cancel\` the extras. No replacements. - Follow a running delegate's \`next\`. Don't poll it (\`task_status\`, \`sleep\`, watchers, Monitor, ScheduleWakeup). Stop a delegate run you replace or no longer need with \`task_cancel\`, never \`t3_thread_interrupt\` on a \`childThreadId\`. - As a subagent or child, do the work yourself. Start no subagents unless your task says to.`, `- \`t3_thread_launch\` and \`create_threads\` make new top-level threads, only when the user asks for a new thread. "Subagent", "delegate", and "parallel" never mean one. Worktree thread: set \`workspaceStrategy\`. Honor a requested base. Otherwise independent work uses the default branch as \`remote/branch\` with \`startFromOrigin:true\`; with no remote, use the local default. Required unpublished commits and dependent work use their local base. Shell worktrees don't bind it, and no checkout setup in its prompt. No \`workspaceStrategy\`: project root, not your worktree.