Skip to content

fix(clients): say "Starting Claude" until the provider actually starts - #30307

Open
ishaanko wants to merge 3 commits into
pingdotgg:mainfrom
ishaanko:fix/claude-starting-state
Open

ishaanko wants to merge 3 commits into
pingdotgg:mainfrom
ishaanko:fix/claude-starting-state

Conversation

@ishaanko

@ishaanko ishaanko commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Problem

When a provider is slow to start, the chat says "Thinking" for as long as it takes, even though nothing is running yet. The server marks a run running before ClaudeAdapterV2.startTurn opens the Claude query, so on a loaded host or behind a long SessionStart hook the label stays wrong for minutes. A Claude registration timeout makes it worse: setMcpServers waits 90s and a resumed session retries once, so "Thinking" can last about 3 minutes before the turn fails. I hit this on a fork whose Claude process never answered: the chat said "Thinking" for almost 2 minutes until I stopped it, and the server log showed orchestration-v2.claude-mcp-registration-timeout with no provider turn.

Change

summarizeThreadRun in client-runtime already marks turnEnded from the run attempt's provider turn. Next to it, a starting or running run with no provider turn yet now carries providerStartingLabel ("Starting Claude", using the session driver's display name). Web and mobile show that label, with a terminal icon, in the live row that says "Thinking". Every adapter reports a provider turn once its turn starts, and Claude reports it after open returns. So the label switches back to "Thinking" as soon as the provider is actually running.

Mobile carries the label on the cached thinking feed entry, and on the latestRunsEqual comparison, so the virtualized feed updates when the provider starts.

Scope and approval

Part of #14244, which Julius triaged as a real chat-surface bug. Its expected behavior is "the UI shows what it is doing (for example 'Starting Claude…')", and the triage notes there is no such string. This PR adds only that label. #23590 is separate: it makes the working row appear during startup at all. This PR changes what the row says once it does appear.

Verification

  • vp test run packages/client-runtime/src/state/threadExecution.test.ts apps/mobile/src/lib/threadActivity.test.ts: 72 passed. The new case covers a running run with no provider turn ("Starting Claude", or "Starting" with no session) and a running provider turn (no label). With threadExecution.ts reverted, it fails (1 failed, 24 passed).
  • Typecheck for client-runtime, web, and mobile, plus lint and format on the changed files: clean.
  • Real web client against an isolated dev server with real Claude (Haiku 5.5). The Claude binary path pointed at a wrapper that sleeps 60s before exec claude for SDK sessions, so T3 waited on setMcpServers exactly as in the report. In the same thread on main, the row said "Thinking". On this branch it said "Starting Claude", then the turn ran normally once Claude started, and the reply "hi" replaced the row.
Before (main) After
Before: Thinking while Claude has not started After: Starting Claude while Claude has not started

Not checked: the mobile client in a simulator (the change there is the shared run summary plus the label prop), and providers other than Claude in a live run. Every adapter emits provider_turn.updated on turn start, and the label only appears while that turn is missing.

Implementation: Claude Opus 5.5 in Claude Code, running in T3 Code.

The server marks a run running before the provider opens its session. When
the provider is slow to start (a loaded host, a long SessionStart hook, or
Claude's MCP registration wait plus retry), the chat said "Thinking" for
minutes while nothing was running. The run summary now carries a starting
label until the provider reports a turn, and web and mobile show it in
place of "Thinking".
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-03T18:53:41.513878Z c2948a9 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 3, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at c2948a9

Macroscope's review found this PR approvable — Web and mobile show “Starting” with the provider name until a provider turn appears, then retain the existing activity presentation. This is a display-only change with no change to provider execution or stored data.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

Thread run summaries can include a provider-starting label when a run is starting or running without a provider turn. Mobile and web thread activity rows receive and display this label when available.

Changes: Provider startup label

Layer / File(s) Summary
Derive the provider-starting label
packages/client-runtime/src/state/models.ts, packages/client-runtime/src/state/threadExecution.ts, packages/client-runtime/src/state/threadExecution.test.ts
Thread run summaries can include a provider-starting label for starting or running runs without a provider turn. The label uses a matching provider session’s display name when available. Tests cover named and generic labels, and the absence of a label when a provider turn is running.
Carry the label into thread activity
apps/mobile/src/lib/threadActivity.ts
Thinking entries and latest-run data can carry the label. Run comparisons and thinking-row caching account for label changes.
Pass and display the label
apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/MessagesTimeline.tsx, apps/web/src/components/chat/timelineRowContext.ts, apps/web/src/components/chat/TimelineWorkGroupRows.tsx, apps/mobile/src/features/threads/ThreadFeed.tsx, apps/mobile/src/features/threads/thread-work-log.tsx
The web timeline and mobile thinking row receive the label. When present, a row displays it with a terminal icon; otherwise, the row displays “Thinking” with a brain icon.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant ChatView
  participant ConversationTimeline
  participant TimelineRowActivityState
  participant ThinkingTimelineRow
  ChatView->>ConversationTimeline: providerStartingLabel or null
  ConversationTimeline->>TimelineRowActivityState: providerStartingLabel
  TimelineRowActivityState->>ThinkingTimelineRow: activity state
  ThinkingTimelineRow->>ThinkingTimelineRow: Display label and select icon
Loading

Possibly related issues

Suggested reviewers: juliusmarminge, maria-rcks

Merge Risk: Minimal · up to 46177

The startup label follows provider-turn state on the verified paths. No merge-blocking issue is established.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title clearly summarizes the main change: show “Starting Claude” until the provider starts its turn.
Description check Passed The description covers the problem, change, scope and approval, and verification. It reports test and live-run results, includes before-and-after screenshots, and states what was not checked.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 6769598 and 461774d.

Files selected for processing: 4

  • apps/mobile/src/features/threads/ThreadFeed.tsx
  • apps/mobile/src/features/threads/thread-work-log.tsx
  • apps/web/src/components/ChatView.tsx
  • apps/web/src/components/chat/MessagesTimeline.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

@maria-rcks

maria-rcks commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol and claude-opus-5-5 on behalf of Maria

Verified in a real dev environment

verified the web path on Linux with repo Playwright and /usr/bin/google-chrome, using real Codex gpt-6.1-sol through the local proxy. created the project and threads through the app against a real git checkout. no mocks, fixtures, demo provider, or artificial startup delay.

  • reproduced on github/main (9def583f8e315f644708501ebcf1f3d4bb320444): the row said "Thinking" before any provider turn existed.
  • checked the exact PR head c2948a9f8f5bae047f8f7a38c11ca693e0dff066: the same prompt showed "Starting Codex" with the terminal icon, then "Thinking" after provider-turn registration, then real terminal activity and the completed reply. the live row cleared.
  • a second turn ran in the same thread. "Stop generation" interrupted the real provider turn, cleared the live row, and showed "Stopped by user". a subsequent message completed successfully.
  • Blacksmith ran vp test run packages/client-runtime/src/state/threadExecution.test.ts apps/mobile/src/lib/threadActivity.test.ts: 72 passed. the head's 31 CI checks were successful. no code changes needed.

selected persisted server events (UTC), read from the isolated dev databases:

main
20:11:12.900 run.updated           running
20:11:13.235 screenshot           Thinking
20:11:13.595 provider-turn.updated running

PR
20:18:34.242 run.updated           running
20:18:35.001 client observation    Starting Codex
20:18:35.118 provider-turn.updated running
20:18:35.661 client observation    Thinking
20:18:56.604 run.updated           completed
20:21:07.765 provider-turn.updated interrupted
20:21:07.954 run.updated           interrupted
20:22:09.940 provider-turn.updated completed (follow-up)
20:22:09.961 run.updated           completed (follow-up)

matching prompt and chat crop, before on main:

main: Thinking before the provider turn starts

after on the PR:

PR: Starting Codex before the provider turn starts

24-second recording (GIF for GitHub compatibility) of submission, startup label, thinking, real command execution, and reply. inspected the recording and verified uploaded playback and seeking in T3's browser:

real Codex startup transition and completed reply

Not verified

Claude's actual startup/MCP-registration delay: claude auth status reports loggedIn: false, so this verifies the shared label behavior through Codex, not a real Claude session. native iOS/Android and Electron desktop were not exercised on this Linux VM. other provider adapters, remote/relay connections, and upstream model queues were not exercised; the label tracks provider-turn registration, not every upstream queue or network delay.

Merged main (6769598ae0)

merged main with a merge commit. main added the zen live answer preview, which reuses the same Thinking-row label. resolved it so the starting label wins before the provider turn, the zen preview keeps the brain icon, and mobile carries the starting label as its own providerStartingLabel field on the thinking entry. vp run check:changed passed on Blacksmith (format, lint, knip, typecheck, 261 tests, react compiler). the live UI was not rechecked after the merge.

# Conflicts:
#	apps/mobile/src/features/threads/thread-work-log.tsx
#	apps/mobile/src/lib/threadActivity.ts
#	apps/web/src/components/chat/TimelineWorkGroupRows.tsx
@ishaanko

ishaanko commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Note

Written by Claude Opus 5.5 (Claude Code in T3 Code) on behalf of Ishaan

Closing the mobile gap from the verification above.

Ran the PR head (6769598ae0) in T3 Code Dev on an iOS 27.2 simulator (iPhone 18 Pro), paired to an isolated dev server with real Claude (Haiku 5.5). As in the web check, the Claude binary path pointed at a wrapper that waits 60s before starting Claude, so the startup window stays open long enough to capture.

  • While Claude was starting, the live row said "Starting Claude" with the terminal icon.
  • When the provider turn started (provider-turn.updated running, 61s after run.updated running), it switched to "Thinking" with the brain icon. The reply replaced the row 2s later.
Starting Provider running
iOS: Starting Claude iOS: Thinking

Not checked: Android (no SDK on this host).

…tate

# Conflicts:
#	apps/mobile/src/features/threads/thread-work-log.tsx

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants