fix(client-runtime): Pi subagent rows show their thinking level#30489

closed3
main
fix/issue-30442
opened7d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1d ago

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):

  1. Start a Pi thread on anthropic/claude-haiku-5-5.
  2. Have it call delegate_task with options: [{ "id": "thinking", "value": "high" }].
  3. 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

  • thinking is now the last entry of REASONING_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.ts and handoff.ts each added thinking to 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 toggle fails on main (expected null to be 'Low') and passes here.
  • The same test checks that Claude's on/off thinking still gets no label.
  • vp-check-changed passes 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-5 delegates one async child at thinking: high that runs sleep 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.

1440×900 darkBefore (7c22e24)After (7715109)
Recording
Viewport / themeBefore (7c22e24)After (7715109)Diff0, timer digits maskedDiff16, timer digits masked
1440×900 dark
1440×900 light
390×900 dark
390×900 light

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 darkBefore (7c22e24)After (7715109)Diff0, timer digits maskedDiff16, 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.

1440×900 darkBefore (7c22e24)After (7715109)Diff0Diff16
Still
Recording

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 thinking level. 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

24 successful · 16 skipped
All checks passed
6b5c739

Added 3 commits

  • test(client-runtime): reproduce #30442 Pi thinking level missing from effort label5211e30
  • Merge remote-tracking branch 'origin/main' into fix/issue-304426b5c739
  • fix(client-runtime): Pi subagent rows show their thinking level7715109
Synced from GitHub

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.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

The changes add thinking as a reasoning-effort option candidate, adjust fallback handling for models absent from the catalog, and add tests for formatting select and boolean thinking values.

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.ts
thinking becomes the final reasoning-effort option candidate. REASONING_DESCRIPTOR_IDS uses the effort option IDs, and the catalog-absent handoff fallback no longer checks thinking separately. Tests verify that a select value of "low" formats as "Low" and a boolean value formats as null.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested labels: bugfix, size:XS

Suggested 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 nameStatusExplanation
Title checkPassedThe 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 checkPassedThe PR satisfies active issue #30442. REASONING_EFFORT_OPTION_IDS now includes thinking after dedicated effort IDs, so Pi select values can produce the subagent effort label while dedicated IDs re…
Out of Scope Changes checkPassedThe 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 checkPassedThe 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 #30442 for 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_IDS now includes thinking after dedicated effort IDs, so Pi select values can produce the subagent effort label while dedicated IDs retain precedence. formatModelSelectionEffort already ignores boolean values, and the added test verifies Pi thinking: low renders Low while Claude thinking: true renders no label. The related modelTraits.ts and handoff.ts updates 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 #30442 for 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
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.ts
  • packages/client-runtime/src/modelTraits.ts
  • packages/client-runtime/src/state/threadExecution.test.ts
  • packages/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.