fix(server): thread titles fall back when the selected provider's CLI is missing#26979

closed4
main
fix/issue-26962
opened12d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 1h ago

Problem

The default text generation model is Codex (gpt-6-luna), and Codex is enabled by default. On a machine where the Codex CLI is not installed, every thread title request still goes to Codex and fails with Failed to spawn Codex CLI process. Thread titles stay as the truncated first message, and Regenerate title fails too. The server only fell back when the selected provider was disabled, not when its CLI was missing.

Reproduction on main 88ab83e8bc: Settings → Providers → Codex → Binary path set to a nonexistent file (Codex still enabled, status "Not found"), text generation model left at its default. Start a thread on Claude Haiku 5.5. The reply arrives, the title is never generated, and the server logs WARN Thread title generation failed … TextGenerationError: Text generation failed in generateThreadTitle: Failed to spawn Codex CLI process.

Change

  • TextGeneration.generate already switches to another usable provider when the selected model's usage window is exhausted. It now also switches when the selected provider's snapshot reports a failed probe for a missing CLI (enabled, installed: false, status: "error"). A provider that has not been checked yet (status: "warning") keeps its selection. If no other provider qualifies, generation fails as before.
  • Fallback candidates are now checked against the originating project's provider enablement instead of the machine-level setting only. A provider disabled for a project is never picked for that project's text. The five text generation inputs take an optional projectId; thread titles, branch names, commit messages, PR content and review guides pass theirs.

Scope and approval

Fixes pingdotgg/t3code#26962

Verification

  • apps/server/src/textGeneration/CodexTextGeneration.test.ts: the preflight test table covers ready, exhausted, not installed, pending, and not installed, fallback disabled for project. not installed fails on main (the call goes to codex instead of claude_work). not installed, fallback disabled for project fails without the project filter. All 17 tests pass on this branch.
  • ThreadTitleRegenerationService, ThreadLaunchService, GitManager and PullRequestReviewGuideService tests pass. vp run check:changed passes (format, lint, knip, typecheck of 23 packages, tests).
  • Runtime transcript. Each side ran its own dev server on a fresh database (T3CODE_DEV_SEED=0) with the same steps: Codex binary path pointed at a missing file, default text generation model, a new Claude Haiku 5.5 thread with "In one sentence, what is the capital of Australia? Do not use tools.", then Regenerate title.
main 88ab83e8bcthis branch (43d7bf2e24, fallback trigger)
Codex provider statusNot found, enabledNot found, enabled
Initial titlestays "In one sentence, what is the capital of Australia?...""Capital of Australia Question"
Regenerate titleunchanged, fails"Australia's Capital: Canberra"
Thread title generation failed log lines2 (Failed to spawn Codex CLI process)0

The runtime run predates the project filter commit. Without project overrides that commit takes the same path, and the unit test covers the override case.

  • Not checked: hiding codex only from the PATH of the launching shell does not reproduce on Linux when the login shell still finds it, because the server rebuilds PATH from the login shell. The missing binary path takes the same spawn … ENOENT path as the report. macOS and Windows were not run; the change has no platform-specific code.

Claude Opus 5.5 via Claude Code in T3 Code (triage, reproduction, tests and implementation); review by GPT-6.1 Sol via Codex and Claude Opus 5.5.

🤖 Generated with Claude Code

Checks

23 successful · 16 skipped · 1 neutral
All checks passed
1e238fd

Added 4 commits

  • Merge remote-tracking branch 'origin/main' into fix/issue-269621e238fd
  • fix(server): text generation fallback respects project-disabled providers411943c
  • fix(server): text generation falls back when the selected provider's CLI is missing43d7bf2
  • test(server): reproduce #26962 text generation using a missing provider60c0063
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Missing-CLI failures now automatically fall back to another eligible provider across all text-generation operations, with project-specific eligibility checks. Human confirmation is needed for this expanded default routing, which can send generation context to a different provider.

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.

External image Recent review info
External image Run configuration
External image Commits

Reviewing files that changed from the base of the PR and between 37fbefd147197fab9d88f9c120560c3f21b52cfc and 1e238fde6e6b58fb0f1d678fac360a48fff13960.

External image Files selected for processing: 7
  • apps/server/src/git/GitManager.ts
  • apps/server/src/orchestration-v2/ThreadLaunchService.ts
  • apps/server/src/orchestration-v2/ThreadTitleRegenerationService.ts
  • apps/server/src/pullRequest/PullRequestReviewGuideService.ts
  • apps/server/src/textGeneration/CodexTextGeneration.test.ts
  • apps/server/src/textGeneration/TextGeneration.ts
  • packages/provider-core/src/server/textGeneration.ts

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

Walkthrough

Text-generation requests now include project IDs. Provider fallback selection considers exhausted usage windows and enabled providers that are uninstalled and in an error state. The preflight tests cover provider status and project-specific fallback settings.

Changes: Text-generation fallback

Layer / File(s)Summary
Project context propagation
packages/provider-core/src/server/textGeneration.ts, apps/server/src/git/GitManager.ts, apps/server/src/orchestration-v2/ThreadLaunchService.ts, apps/server/src/orchestration-v2/ThreadTitleRegenerationService.ts, apps/server/src/pullRequest/PullRequestReviewGuideService.ts
Generation input interfaces accept an optional nullable project ID. The server callers pass the resolved project ID with commit-message, PR-content, branch-name, thread-title, and review-guide generation requests.
Fallback selection and validation
apps/server/src/textGeneration/TextGeneration.ts, apps/server/src/textGeneration/CodexTextGeneration.test.ts
Fallback selection now considers provider installation and error status, and checks fallback enablement for the supplied project. Tests cover ready, pending, exhausted, and missing primary-provider states, including project-specific fallback disablement.

Priority: External image Normal

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

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

  • pingdotgg/t3code#25871 — The issue describes branch-name generation failing when the selected Codex CLI is unavailable; this change adds fallback for an unavailable selected provider.

Possibly related PRs

  • pingdotgg/t3code#23946 — Adds second-model fallback to the same generation tasks; this change adds missing-provider fallback and project ID propagation.
  • pingdotgg/t3code#26164 — Extends fallback selection for exhausted usage windows; this change adds an unavailable-provider fallback condition.

Suggested labels: bugfix, size:M

Suggested reviewers: maria-rcks, t3dotgg

Merge Risk: External image Minimal · up to 1e238

No merge-blocking risk was identified.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title "fix(server): thread titles fall back when the selected provider's CLI is missing" matches the main change. The diff adds fallback in TextGeneration.generate when the selected provider is en…
Description checkPassedThe description follows the template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section states the failure, expected behavior, and reproduction steps. The Chan…
Linked Issues checkPassedIssue [#26962] requires title generation to leave an enabled provider when its CLI is missing. TextGeneration.generate now treats an enabled provider with installed: false and status: "error" as…
Out of Scope Changes checkPassedThe changes stay within the fallback behavior in [#26962]. The optional project ID and propagation through title, branch-name, commit-message, pull-request, and review-guide generation prevent fallbac…
Full details: Title check

Explanation

The title "fix(server): thread titles fall back when the selected provider's CLI is missing" matches the main change. The diff adds fallback in TextGeneration.generate when the selected provider is enabled but uninstalled with an error status, and it adds project-scoped provider filtering. The title covers the primary fix. It does not mention the project-scoped filter, which is a secondary part of the change, and that omission is acceptable.

Full details: Description check

Explanation

The description follows the template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section states the failure, expected behavior, and reproduction steps. The Change section explains the fallback trigger and the project-level filter. The Verification section lists focused tests, a runtime before-and-after comparison, and items that were not checked. The Scope and approval section links issue #26962 but does not include an explicit maintainer approval comment or explain why the fix qualifies without one. The template asks for that, so the section is incomplete.

Resolution

Optionally add the maintainer approval comment or the triaged issue discussion to the Scope and approval section. The section links issue #26962, but the template asks for explicit maintainer approval of the direction and scope.

Full details: Linked Issues check

Explanation

Issue [#26962] requires title generation to leave an enabled provider when its CLI is missing. TextGeneration.generate now treats an enabled provider with installed: false and status: "error" as missing. It selects an installed, authenticated, available fallback. It preserves the selected provider for a pending (status: "warning") probe and preserves the prior failure when no fallback qualifies. generateThreadTitle receives the project ID. The added preflight test table covers ready, pending, exhausted, missing CLI, and project-disabled fallback cases.

Full details: Out of Scope Changes check

Explanation

The changes stay within the fallback behavior in [#26962]. The optional project ID and propagation through title, branch-name, commit-message, pull-request, and review-guide generation prevent fallback to a provider disabled for the originating project. The related test updates verify this behavior. No unrelated change is established.

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

Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Note

🤖 Claude Opus 5.5 responding on behalf of Muzammil Hussain

This branch also fixes #31005 (create PR fails with Text generation failed in generatePrContent: Failed to spawn Codex CLI process), but main now does too: #29607 merged on Nov 6 and adds the same fallback in TextGeneration.generate. This branch conflicts with main and does not include #29607.

Run on this head (1e238fde6e) with a fresh database: Codex binary path set to a missing file (Codex enabled, "Not found"), text generation model left at gpt-6-luna, Claude Haiku 5.5 selected, and a new file committed with an empty message.

  • Result: Committed 802d564, message "Add greet helper".
  • Server trace: TextGeneration.generate → ClaudeTextGeneration.generateCommitMessage, both successful.
  • Server log: no text generation warnings and no Failed to spawn lines.

main at dd059b40bc gives the same result (Committed 9224977, Claude, no errors). generatePrContent goes through the same generate call. I did not run the "create PR" button, because it would open a real PR.

What this branch still adds over main is the project-level filter: fallback candidates are checked against the originating project's provider settings (projectId passed through), while main still passes null. If that is worth keeping, the PR could be rebased onto main and narrowed to that change.

Thanks for the fix! #29607 (6b84d2caae) already covers fallback when the selected CLI is missing. Please rebase and narrow this PR to honoring project provider enablement when choosing fallback candidates, which main still checks at machine scope.

Synced from GitHub

Note

🤖 Claude Opus 5.5 responding on behalf of Muzammil Hussain

Rebased onto current main and narrowed to the project filter in #33741. I can't push to this PR's branch, so it's a replacement from my fork.

  • TextGeneration.generate checks fallback candidates with the request's projectId instead of null. The missing-CLI trigger is main's, untouched.
  • Commit message, PR content, branch name, thread title and review guide pass their projectId. Transcription post-processing has no project, so it stays machine-scoped.
  • New preflight row, "not installed, fallback disabled for project": fails with null, passes with the change.
  • vp run check:changed passes.

This PR can be closed in favor of #33741.

Thanks for this. Main has the change since #33741: Compared all seven files in #26979 against main: #29607 already supplies missing-CLI fallback with pending-probe protection, and #33741 supplies project-aware fallback filtering, all five generation input fields and their callers, plus the project-disabled fallback test; main now covers its entire behavior.

Closing as superseded.