fix(client-runtime): Pi subagent rows show their thinking level#30489
Problem
The hover card on a Pi subagent row shows only the model, so you can't tell what reasoning level a delegated child runs at. Claude (effort), Codex (reasoningEffort), Cursor (reasoning) and OpenCode (variant) rows already show it. Pi names its reasoning option thinking, and that id was missing from the shared list the label reads (REASONING_EFFORT_OPTION_IDS).
To reproduce on main (7c22e24):
- Start a Pi thread on
anthropic/claude-haiku-5-5. - Have it call
delegate_taskwithoptions: [{ "id": "thinking", "value": "high" }]. - While the child runs, hover its row. The card reads "Haiku 5.5".
An OpenCode child delegated with variant: max reads "Beam Free · max" in the same card.
Change
thinkingis now the last entry ofREASONING_EFFORT_OPTION_IDS, so a model that has a dedicated effort select still shows that.- Claude and Cursor also have an option called
thinking, but it's an on/off switch. Every consumer skips on/off values, so those never become a label. modelTraits.tsandhandoff.tseach addedthinkingto that list themselves. They now use the shared list as it is, with the same ids in the same order, so their behaviour doesn't change.
Scope and approval
Fixes pingdotgg/t3code#30442
Verification
Tests:
threadExecution.test.ts › formatModelSelectionEffort › labels a Pi thinking level but not Claude's boolean thinking togglefails on main (expected null to be 'Low') and passes here.- The same test checks that Claude's on/off
thinkingstill gets no label. vp-check-changedpasses on the head: format, lint, knip, typecheck of 7 packages, and 41 tests across 2 files.
Evidence. Before is 7c22e24. After is 7715109; the head adds only a merge of main.
- Both sides ran the real web dev server with a fresh database and
T3CODE_DEV_SEED=0. - Setup: Pi enabled; the parent on
anthropic/claude-haiku-5-5delegates one async child atthinking: highthat runssleep 3600. - Browser: Chromium 156 through agent-browser, DPR 1, no device emulation, 100% zoom, reduced motion, browser clock frozen.
The diffs below mask four regions that come from real runs and can't match across two servers: the changed digits of the parent's "Worked for" duration and of three elapsed timers. Each mask is a cyan box drawn around exactly the changed digit pixels, plus 1 px; no static text is masked. With them masked, the only change at zero threshold in every pair is one 31×12 px box: the · high suffix. The unmasked diffs are kept with the run's scratch files.
R1: running Pi child, timeline row hover card
Steps (before / after): 1.0 s hover the "Pi high proof" row; card readable at about 1.5 s; dwell to 4.5 s; pointer leaves.
| Viewport / theme | Before (7c22e24) | After (7715109) | Diff0, timer digits masked | Diff16, timer digits masked |
|---|---|---|---|---|
| 1440×900 dark | ||||
| 1440×900 light | ||||
| 390×900 dark | ||||
| 390×900 light |
R2: same child, Related threads hover card in thread details
Steps: 1.0 s open thread details; 1.7 s hover "Pi high proof" under Related threads; dwell to 5.2 s; pointer leaves.
| 1440×900 dark | Before (7c22e24) | After (7715109) | Diff0, timer digits masked | Diff16, timer digits masked |
|---|---|---|---|---|
| Still | ||||
| Recording |
C1: control harness, an on/off thinking: true stays model-only
This is a labelled component harness, not a real Claude turn. It mounts the real SubagentTooltipContent inside the real hover card, with a Claude-style on/off thinking option and a saved thinking: true. Both sides read model only, and the two frames are pixel-identical at zero threshold.
What else changed (all inside the masks):
- The parent's "Worked for" went from 5.4 s to 6.2 s.
- The child's elapsed timers moved by one second.
- Nothing else.
Seeding: in each side's fresh home, userdata/settings.json gets "pi": {"driver":"pi","enabled":true,"config":{"enabled":true}} under providerInstances. Then:
node src/bin.ts project add <empty fixture repo>node src/bin.ts thread start --provider pi --model anthropic/claude-haiku-5-5 --json <project> '<prompt>'
The prompt was: "Call orchestrator_capabilities, then delegate_task exactly once with target provider pi, model anthropic/claude-haiku-5-5, options [{"id":"thinking","value":"high"}], mode async, title "Pi high proof", and task "Run sleep 3600 in the shell, wait for it to return, then reply done. Make no file changes." Keep the delegation available. Do not replace it with the provider-native subagent tool."
Not checked:
- Mobile: no current producer gives a mobile row a Pi
thinkinglevel. Pi's own subagents have no T3 child thread, and plain mobile agent rows carry no effort. - Desktop: it renders the same web components.
Model and harness: Claude Opus 5.5 (Claude Code) as lead, test writer, implementer and reviewer B; GPT-6.1 Sol (Codex) as reviewer A, proof auditor and evidence capturer, all orchestrated through T3 Code.
🤖 Generated with Claude Code
Checks
Added 3 commits
Approvability
Verdict: Approved at 6b5c739
Macroscope's review found this PR approvable — Pi subagent displays now recognize and show their existing thinking level. The change preserves effort-option precedence and does not change model settings or product defaults.
You can add or adjust custom eligibility rules. Learn more.
No actionable comments were generated in the recent review.
Walkthrough
The changes add
thinkingas a reasoning-effort option candidate, adjust fallback handling for models absent from the catalog, and add tests for formatting select and booleanthinkingvalues.Changes: Pi reasoning-effort recognition
Layer / File(s) Summary Effort option recognition and formatting
packages/client-runtime/src/state/threadExecution.ts,packages/client-runtime/src/modelTraits.ts,packages/client-runtime/src/handoff.ts,packages/client-runtime/src/state/threadExecution.test.tsthinkingbecomes the final reasoning-effort option candidate.REASONING_DESCRIPTOR_IDSuses the effort option IDs, and the catalog-absent handoff fallback no longer checksthinkingseparately. Tests verify that a select value of"low"formats as"Low"and a boolean value formats asnull.Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested labels:
bugfix,size:XSSuggested reviewers:
t3dotgg
Merge Risk: External image Minimal · up to 6b5c7
Pi reasoning levels can appear in subagent details without labeling boolean toggles. No merge-blocking risk was identified.
Pre-merge checks: Passed 4
Check name Status Explanation Title check Passed The title names the change: Pi subagent rows now show the thinking level. It follows the conventional commit form and matches the change to REASONING_EFFORT_OPTION_IDS, the test, and the subagent hove… Linked Issues check Passed The PR satisfies active issue #30442.REASONING_EFFORT_OPTION_IDSnow includesthinkingafter dedicated effort IDs, so Pi select values can produce the subagent effort label while dedicated IDs re…Out of Scope Changes check Passed The changes stay within #30442. The implementation updates the shared effort-ID list, synchronizes two existing consumers, and adds focused regression coverage. No unrelated product behavior or unrela…Description check Passed The description is complete and follows the required template. It explains the problem and reproduction steps, describes the shared-list change and compatibility behavior, links issue #30442for scope…Full details: Title check
Explanation
The title names the change: Pi subagent rows now show the thinking level. It follows the conventional commit form and matches the change to REASONING_EFFORT_OPTION_IDS, the test, and the subagent hover card label. It is specific and does not cover unrelated work.
Full details: Linked Issues check
Explanation
The PR satisfies active issue
#30442.REASONING_EFFORT_OPTION_IDSnow includesthinkingafter dedicated effort IDs, so Pi select values can produce the subagent effort label while dedicated IDs retain precedence.formatModelSelectionEffortalready ignores boolean values, and the added test verifies Pithinking: lowrendersLowwhile Claudethinking: truerenders no label. The relatedmodelTraits.tsandhandoff.tsupdates keep their ID handling aligned with the shared list.
Full details: Out of Scope Changes check
Explanation
The changes stay within
#30442. The implementation updates the shared effort-ID list, synchronizes two existing consumers, and adds focused regression coverage. No unrelated product behavior or unrelated files are changed.
Full details: Description check
Explanation
The description is complete and follows the required template. It explains the problem and reproduction steps, describes the shared-list change and compatibility behavior, links issue
#30442for scope approval, documents focused tests and observed results, includes detailed visual verification and limitations, and identifies the agent models and harness used.
Finishing Touches
Generate docstrings
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
- Commit to this branch
- Create a new PR
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-30442
- File: .coderabbit.config.ts
- Commit: 6b5c739
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
1763bde4-1055-403a-a69a-0ecb3c25dc1f
External image Commits
Reviewing files that changed from the base of the PR and between 43bf0babd4b41d22466640e5d9c8d08e190fff9c and 6b5c7394dd70626c23d24dca4b1dfb737af2b852.
External image Files selected for processing: 4
packages/client-runtime/src/handoff.tspackages/client-runtime/src/modelTraits.tspackages/client-runtime/src/state/threadExecution.test.tspackages/client-runtime/src/state/threadExecution.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.
External image Recent review info
-
External image Run configuration
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-30442
- File: .coderabbit.config.ts
- Commit: 6b5c739
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
1763bde4-1055-403a-a69a-0ecb3c25dc1f
External image Commits
Reviewing files that changed from the base of the PR and between 43bf0babd4b41d22466640e5d9c8d08e190fff9c and 6b5c7394dd70626c23d24dca4b1dfb737af2b852.
External image Files selected for processing: 4
packages/client-runtime/src/handoff.tspackages/client-runtime/src/modelTraits.tspackages/client-runtime/src/state/threadExecution.test.tspackages/client-runtime/src/state/threadExecution.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.
Thanks, @juliusmarminge, for the earlier fix and thorough evidence. This branch now conflicts with main; #33346 by @StiensWout merges cleanly and covers the same Pi thinking-level issue, so we are keeping that PR instead.