Repository navigation
fix(server): Pi thread titles use linked PR context - #16210
Conversation
Every provider in apps/server/src/textGeneration carried its own copy of the four operations (commit message, PR content, branch name, thread title): building the prompt, calling the provider, sanitizing the reply. The copies drifted. Pi never passed linkedContext into the thread title prompt, so Pi titles ignored a linked PR or issue that the other providers used. Pi also dropped the needsRefinement signal for an unresolved subject. TextGenerationOperations.fromRunner now owns the four operations once. A provider supplies only a runner that sends one prompt and decodes the reply; decodeJsonReply covers the providers that reply in text. Codex reads image attachments from the request instead of from per-operation code. OpenCode 1.x and 2.x already shared operations through makeOpenCodeOperations, which this replaces. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review. 📝 WalkthroughWalkthroughThe PR adds shared text-generation operation contracts, prompt construction, result processing, and JSON reply decoding. Provider runners adopt the shared interfaces. Codex updates image attachment handling, and a Pi test checks thread-title generation with linked source-control context. ChangesShared text-generation operations
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to No actionable defect is supported by the supplied review context; the suspected attachment-file leak is not introduced by this change. The PR appears ready for normal checks. 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
Full details: Description checkExplanation The description explains the problem, implementation, side effects, and verification. It does not include the required scope and approval information: a triaged issue or discussion with explicit maintainer approval. The reported cross-provider refactor is not described as a very small, focused fix that qualifies for the exemption. Resolution Add a link to the triaged issue or discussion and the explicit maintainer approval comment for the scope and direction. If no prior approval exists, obtain it and include the link. Do not use the small-fix exemption unless maintainers agree this broad cross-provider refactor qualifies as a very small, focused fix of an obvious bug.
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR fixes Pi thread-title context handling but also replaces duplicated operation implementations across all text-generation providers with a new shared runtime abstraction. Because the cross-provider refactor can affect multiple production integrations, it merits human review. No code changes detected at You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
…n-shared # Conflicts: # apps/server/src/textGeneration/CodexTextGeneration.ts
## What's Changed * refactor(server,relay): webhook capabilities live in services, not handlers by @juliusmarminge in pingdotgg/t3code#16232 * fix(server): a T3 Connect preferences save finishes even if the client disconnects by @juliusmarminge in pingdotgg/t3code#16266 * refactor(server): import service modules as namespaces, not aliased layers by @juliusmarminge in pingdotgg/t3code#16267 * feat(server): log how long PR watches stay quiet before they end by @t3dotgg in pingdotgg/t3code#16262 * feat(server,web): choose where new worktrees are created by @juliusmarminge in pingdotgg/t3code#16231 * perf(server): idle status polls and PR sweeps start fewer git processes by @t3dotgg in pingdotgg/t3code#16272 * perf(server): PR watches spend ~90% fewer GitHub points by checking a 1-point fingerprint first by @t3dotgg in pingdotgg/t3code#16270 * fix(pull-requests): PR detail reads no longer drain the GitHub quota by @t3dotgg in pingdotgg/t3code#16280 * refactor: layer variables are named layer or layerXyz by @juliusmarminge in pingdotgg/t3code#16282 * refactor(server): T3 Connect link capabilities live in a CloudLink service by @juliusmarminge in pingdotgg/t3code#16265 * fix(web): sidebar drag and drop no longer snaps back by @t3dotgg in pingdotgg/t3code#16291 * fix(web): inline HTML renders no longer trap the thread's scroll by @t3dotgg in pingdotgg/t3code#16283 * refactor(server): one module per service instead of Services/ and Layers/ folders by @juliusmarminge in pingdotgg/t3code#16295 * chore(review): configure CodeRabbit in TypeScript by @esthor in pingdotgg/t3code#16281 * docs: put the Effect and web UI review rules in the docs by @esthor in pingdotgg/t3code#16286 * chore(lint): require a reason on every lint and type-checker suppression by @esthor in pingdotgg/t3code#16294 * refactor(relay): import HookInboxObject once, as a namespace by @juliusmarminge in pingdotgg/t3code#16307 * fix(web): a rejected desktop-local credential is not retried every poll by @juliusmarminge in pingdotgg/t3code#16273 * feat(desktop): the renderer's bootstrap token rotates every 12 hours by @juliusmarminge in pingdotgg/t3code#16275 * fix(web): recover from a closed IndexedDB connection by @juliusmarminge in pingdotgg/t3code#16311 * fix(relay): stop forcing manual relay deploys by default by @juliusmarminge in pingdotgg/t3code#13563 * feat(relay): measure the managed tunnel backlog by @juliusmarminge in pingdotgg/t3code#13564 * feat(relay): clean up tunnels of hosts that never registered recovery by @juliusmarminge in pingdotgg/t3code#13565 * perf(relay): delete expired tunnels four at a time within a time budget by @juliusmarminge in pingdotgg/t3code#13566 * feat(connect): tell users when an idle tunnel was removed by @juliusmarminge in pingdotgg/t3code#13567 * docs(relay): add the legacy tunnel cleanup rollout runbook by @juliusmarminge in pingdotgg/t3code#13568 * chore(review): point CodeRabbit at the web UI conventions by @esthor in pingdotgg/t3code#16324 * chore(review): turn off CodeRabbit's docstring coverage check by @esthor in pingdotgg/t3code#16328 * refactor(server): CloudLink keeps only the link lifecycle; pure checks live beside it by @juliusmarminge in pingdotgg/t3code#16340 * refactor(server): CloudLink fails with its own errors; the connect routes map them to HTTP by @juliusmarminge in pingdotgg/t3code#16341 * refactor(server): replay guards stay in CloudLink by @juliusmarminge in pingdotgg/t3code#16349 * fix(server): forks no longer merge into their upstream repo's project group by @t3dotgg in pingdotgg/t3code#16353 * fix(server): stop the startup project sync from delaying the app window by @Mnigos in pingdotgg/t3code#14912 * fix(web): avoid blocking image preparation conversions by @Bil0000 in pingdotgg/t3code#13342 * fix(server): return partial workspace index on timeout by @Michel-Liao in pingdotgg/t3code#11500 * fix(server): probe project favicon candidates concurrently by @ishaanko in pingdotgg/t3code#12543 * fix(observability): a failing trace disk no longer stalls the server by @t3dotgg in pingdotgg/t3code#13758 * fix(server): status polling no longer locks the git index by @ahalekelly in pingdotgg/t3code#14718 * perf(shared): scan PATH once per command before spawning, not on every spawn by @SkiTee3000 in pingdotgg/t3code#12600 * fix(server): main's startup auto-pull test compiles again by @t3dotgg in pingdotgg/t3code#16357 * fix(server): project favicons stop being rescanned every minute by @t3dotgg in pingdotgg/t3code#16206 * fix(server): Claude limits load again for users with large transcript histories by @t3dotgg in pingdotgg/t3code#16358 * fix(server): caches and ids are written atomically by @juliusmarminge in pingdotgg/t3code#16242 * fix(server): one-shot initializers no longer race by @juliusmarminge in pingdotgg/t3code#16260 * fix(server): the PR cache sweep only removes real entry files by @juliusmarminge in pingdotgg/t3code#16285 * chore: keep one copy each of undici 8 and ws 8 by @juliusmarminge in pingdotgg/t3code#16211 * fix(shared): DrainableWorker keeps running after a failed item by @juliusmarminge in pingdotgg/t3code#16223 * fix(server): metrics count interrupted work on the monotonic clock by @juliusmarminge in pingdotgg/t3code#16207 * refactor(web): import connection storage as a namespace in its test by @juliusmarminge in pingdotgg/t3code#16315 * fix(contracts): trimmed IDs round-trip by @juliusmarminge in pingdotgg/t3code#16300 * fix(server): main's settings, keybindings and session tests compile again by @juliusmarminge in pingdotgg/t3code#16363 * chore(lint): catch known tags with Effect.catchTags by @esthor in pingdotgg/t3code#16361 * fix(observability): T3 Connect tracing stops at the relay boundary by @juliusmarminge in pingdotgg/t3code#16314 * fix(relay): error and deadline responses carry CORS headers by @juliusmarminge in pingdotgg/t3code#16253 * fix(web): bring back the live shimmer on work log rows by @juliusmarminge in pingdotgg/t3code#16372 * refactor: Effect code gets UUIDs and SHA-256 from Effect's Crypto by @esthor in pingdotgg/t3code#16377 * fix(relay): export traces through one tracer, one request span each by @juliusmarminge in pingdotgg/t3code#16382 * fix(server): Pi thread titles use linked PR context by @juliusmarminge in pingdotgg/t3code#16210 * fix(desktop): retry transient bearer bootstrap and degrade on session fetch failure by @jamesvillarrubia in pingdotgg/t3code#12919 * fix(server): avoid scanning completed history for pending secrets by @Yash-Singh1 in pingdotgg/t3code#16409 * fix(orchestration-v2): let Stop recover stalled runs by @Yash-Singh1 in pingdotgg/t3code#15442 * fix(release): resolve version-qualified catalog overrides by @Yash-Singh1 in pingdotgg/t3code#16411 * fix(web): type in front of bold that starts a composer line by @saphid in pingdotgg/t3code#13217 * fix(desktop): prevent browser screenshot filename collisions by @saphid in pingdotgg/t3code#14784 * fix(server): end clone options before the repository URL by @saphid in pingdotgg/t3code#14781 * fix(web): queued messages no longer split the composer notice stack by @tristanmanchester in pingdotgg/t3code#16400 * fix(server): reject invalid explicit Bitbucket repositories by @aravhawk in pingdotgg/t3code#15876 * fix: restore desktop and server typechecks on main by @Yash-Singh1 in pingdotgg/t3code#16415 * fix(shared): find versioned JetBrains macOS app bundles by @Sypher760-gif in pingdotgg/t3code#16246 * fix(server): OpenCode 2 threads get T3 Code's MCP tools by @nkoynov in pingdotgg/t3code#16142 * feat(preview): run the browser on the environment server by @maria-rcks in pingdotgg/t3code#15328 * fix: restore service references breaking ci by @maria-rcks in pingdotgg/t3code#16495 * fix(mcp): mark declared tool failures as errors by @maria-rcks in pingdotgg/t3code#15617 * fix(release): unblock nightly browser tests and cli builds by @maria-rcks in pingdotgg/t3code#16515 ## New Contributors * @esthor made their first contribution in pingdotgg/t3code#16281 * @ahalekelly made their first contribution in pingdotgg/t3code#14718 * @SkiTee3000 made their first contribution in pingdotgg/t3code#12600 * @jamesvillarrubia made their first contribution in pingdotgg/t3code#12919 * @Sypher760-gif made their first contribution in pingdotgg/t3code#16246 * @nkoynov made their first contribution in pingdotgg/t3code#16142 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261005.2702...v0.0.46-nightly.20261006.2735 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261006.2735
## What's Changed * refactor(server,relay): webhook capabilities live in services, not handlers by @juliusmarminge in pingdotgg/t3code#16232 * fix(server): a T3 Connect preferences save finishes even if the client disconnects by @juliusmarminge in pingdotgg/t3code#16266 * refactor(server): import service modules as namespaces, not aliased layers by @juliusmarminge in pingdotgg/t3code#16267 * feat(server): log how long PR watches stay quiet before they end by @t3dotgg in pingdotgg/t3code#16262 * feat(server,web): choose where new worktrees are created by @juliusmarminge in pingdotgg/t3code#16231 * perf(server): idle status polls and PR sweeps start fewer git processes by @t3dotgg in pingdotgg/t3code#16272 * perf(server): PR watches spend ~90% fewer GitHub points by checking a 1-point fingerprint first by @t3dotgg in pingdotgg/t3code#16270 * fix(pull-requests): PR detail reads no longer drain the GitHub quota by @t3dotgg in pingdotgg/t3code#16280 * refactor: layer variables are named layer or layerXyz by @juliusmarminge in pingdotgg/t3code#16282 * refactor(server): T3 Connect link capabilities live in a CloudLink service by @juliusmarminge in pingdotgg/t3code#16265 * fix(web): sidebar drag and drop no longer snaps back by @t3dotgg in pingdotgg/t3code#16291 * fix(web): inline HTML renders no longer trap the thread's scroll by @t3dotgg in pingdotgg/t3code#16283 * refactor(server): one module per service instead of Services/ and Layers/ folders by @juliusmarminge in pingdotgg/t3code#16295 * chore(review): configure CodeRabbit in TypeScript by @esthor in pingdotgg/t3code#16281 * docs: put the Effect and web UI review rules in the docs by @esthor in pingdotgg/t3code#16286 * chore(lint): require a reason on every lint and type-checker suppression by @esthor in pingdotgg/t3code#16294 * refactor(relay): import HookInboxObject once, as a namespace by @juliusmarminge in pingdotgg/t3code#16307 * fix(web): a rejected desktop-local credential is not retried every poll by @juliusmarminge in pingdotgg/t3code#16273 * feat(desktop): the renderer's bootstrap token rotates every 12 hours by @juliusmarminge in pingdotgg/t3code#16275 * fix(web): recover from a closed IndexedDB connection by @juliusmarminge in pingdotgg/t3code#16311 * fix(relay): stop forcing manual relay deploys by default by @juliusmarminge in pingdotgg/t3code#13563 * feat(relay): measure the managed tunnel backlog by @juliusmarminge in pingdotgg/t3code#13564 * feat(relay): clean up tunnels of hosts that never registered recovery by @juliusmarminge in pingdotgg/t3code#13565 * perf(relay): delete expired tunnels four at a time within a time budget by @juliusmarminge in pingdotgg/t3code#13566 * feat(connect): tell users when an idle tunnel was removed by @juliusmarminge in pingdotgg/t3code#13567 * docs(relay): add the legacy tunnel cleanup rollout runbook by @juliusmarminge in pingdotgg/t3code#13568 * chore(review): point CodeRabbit at the web UI conventions by @esthor in pingdotgg/t3code#16324 * chore(review): turn off CodeRabbit's docstring coverage check by @esthor in pingdotgg/t3code#16328 * refactor(server): CloudLink keeps only the link lifecycle; pure checks live beside it by @juliusmarminge in pingdotgg/t3code#16340 * refactor(server): CloudLink fails with its own errors; the connect routes map them to HTTP by @juliusmarminge in pingdotgg/t3code#16341 * refactor(server): replay guards stay in CloudLink by @juliusmarminge in pingdotgg/t3code#16349 * fix(server): forks no longer merge into their upstream repo's project group by @t3dotgg in pingdotgg/t3code#16353 * fix(server): stop the startup project sync from delaying the app window by @Mnigos in pingdotgg/t3code#14912 * fix(web): avoid blocking image preparation conversions by @Bil0000 in pingdotgg/t3code#13342 * fix(server): return partial workspace index on timeout by @Michel-Liao in pingdotgg/t3code#11500 * fix(server): probe project favicon candidates concurrently by @ishaanko in pingdotgg/t3code#12543 * fix(observability): a failing trace disk no longer stalls the server by @t3dotgg in pingdotgg/t3code#13758 * fix(server): status polling no longer locks the git index by @ahalekelly in pingdotgg/t3code#14718 * perf(shared): scan PATH once per command before spawning, not on every spawn by @SkiTee3000 in pingdotgg/t3code#12600 * fix(server): main's startup auto-pull test compiles again by @t3dotgg in pingdotgg/t3code#16357 * fix(server): project favicons stop being rescanned every minute by @t3dotgg in pingdotgg/t3code#16206 * fix(server): Claude limits load again for users with large transcript histories by @t3dotgg in pingdotgg/t3code#16358 * fix(server): caches and ids are written atomically by @juliusmarminge in pingdotgg/t3code#16242 * fix(server): one-shot initializers no longer race by @juliusmarminge in pingdotgg/t3code#16260 * fix(server): the PR cache sweep only removes real entry files by @juliusmarminge in pingdotgg/t3code#16285 * chore: keep one copy each of undici 8 and ws 8 by @juliusmarminge in pingdotgg/t3code#16211 * fix(shared): DrainableWorker keeps running after a failed item by @juliusmarminge in pingdotgg/t3code#16223 * fix(server): metrics count interrupted work on the monotonic clock by @juliusmarminge in pingdotgg/t3code#16207 * refactor(web): import connection storage as a namespace in its test by @juliusmarminge in pingdotgg/t3code#16315 * fix(contracts): trimmed IDs round-trip by @juliusmarminge in pingdotgg/t3code#16300 * fix(server): main's settings, keybindings and session tests compile again by @juliusmarminge in pingdotgg/t3code#16363 * chore(lint): catch known tags with Effect.catchTags by @esthor in pingdotgg/t3code#16361 * fix(observability): T3 Connect tracing stops at the relay boundary by @juliusmarminge in pingdotgg/t3code#16314 * fix(relay): error and deadline responses carry CORS headers by @juliusmarminge in pingdotgg/t3code#16253 * fix(web): bring back the live shimmer on work log rows by @juliusmarminge in pingdotgg/t3code#16372 * refactor: Effect code gets UUIDs and SHA-256 from Effect's Crypto by @esthor in pingdotgg/t3code#16377 * fix(relay): export traces through one tracer, one request span each by @juliusmarminge in pingdotgg/t3code#16382 * fix(server): Pi thread titles use linked PR context by @juliusmarminge in pingdotgg/t3code#16210 * fix(desktop): retry transient bearer bootstrap and degrade on session fetch failure by @jamesvillarrubia in pingdotgg/t3code#12919 * fix(server): avoid scanning completed history for pending secrets by @Yash-Singh1 in pingdotgg/t3code#16409 * fix(orchestration-v2): let Stop recover stalled runs by @Yash-Singh1 in pingdotgg/t3code#15442 * fix(release): resolve version-qualified catalog overrides by @Yash-Singh1 in pingdotgg/t3code#16411 * fix(web): type in front of bold that starts a composer line by @saphid in pingdotgg/t3code#13217 * fix(desktop): prevent browser screenshot filename collisions by @saphid in pingdotgg/t3code#14784 * fix(server): end clone options before the repository URL by @saphid in pingdotgg/t3code#14781 * fix(web): queued messages no longer split the composer notice stack by @tristanmanchester in pingdotgg/t3code#16400 * fix(server): reject invalid explicit Bitbucket repositories by @aravhawk in pingdotgg/t3code#15876 * fix: restore desktop and server typechecks on main by @Yash-Singh1 in pingdotgg/t3code#16415 * fix(shared): find versioned JetBrains macOS app bundles by @Sypher760-gif in pingdotgg/t3code#16246 * fix(server): OpenCode 2 threads get T3 Code's MCP tools by @nkoynov in pingdotgg/t3code#16142 * feat(preview): run the browser on the environment server by @maria-rcks in pingdotgg/t3code#15328 * fix: restore service references breaking ci by @maria-rcks in pingdotgg/t3code#16495 * fix(mcp): mark declared tool failures as errors by @maria-rcks in pingdotgg/t3code#15617 * fix(release): unblock nightly browser tests and cli builds by @maria-rcks in pingdotgg/t3code#16515 ## New Contributors * @esthor made their first contribution in pingdotgg/t3code#16281 * @ahalekelly made their first contribution in pingdotgg/t3code#14718 * @SkiTee3000 made their first contribution in pingdotgg/t3code#12600 * @jamesvillarrubia made their first contribution in pingdotgg/t3code#12919 * @Sypher760-gif made their first contribution in pingdotgg/t3code#16246 * @nkoynov made their first contribution in pingdotgg/t3code#16142 **Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261005.2702...v0.0.46-nightly.20261006.2735 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261006.2735
Problem
Each provider in
apps/server/src/textGeneration/had its own copy of the four operations (commit message, PR content, branch name, thread title): it built the prompt, called the provider, and sanitized the reply. The copies drifted. Pi never passedlinkedContextinto the thread title prompt, so Pi titles ignored a linked PR or issue that the other providers used. Pi also dropped theneedsRefinementsignal for an unresolved subject.OpenCode 2 was already correct here. It and OpenCode 1.x share
makeOpenCodeOperations, which passeslinkedContext.Fix
TextGenerationOperations.fromRunner(name, run)now owns the four operations in one place: prompt building,linkedContextand attachments in the thread title prompt, reply sanitizing, and theneedsRefinementpassthrough. Each provider supplies only a runner, which sends one prompt and decodes the reply as the request's schema.decodeJsonReplycovers the six providers whose reply is text (Pi, Cursor, Grok, Antigravity, OpenCode 1.x and 2.x).makeOpenCodeOperations/OpenCodeJsonRunnerare replaced by the shared module.What each runner still owns, all unchanged:
--output-schemaand reads the output file. Image attachments are now resolved inside the runner from the request, rather than in the branch-name and title operations.structured_outputfrom the CLI's JSON envelope. Titles still run in a temp directory instead of the checkout.cwdand run in an empty temp directory. Antigravity still adds its "use only the input below" preamble to the prompt.Two side effects, both kept on purpose:
<Provider>TextGeneration.generate*shape. OpenCode 2 spans are nowOpenCode2TextGeneration.*instead of reusingOpenCodeTextGeneration.*.No contract or
TextGenerationservice interface changes.Verification
From
apps/server:vp test run src/textGeneration: 12 files, 151 tests passed (was 11 / 150 on main; the new file isPiTextGeneration.test.ts).makePiTextGenerationover an in-process fakepi --mode rpcand asserts that the prompt Pi receives carries the linked context. Against main'sPiTextGeneration.tsit fails withexpected 'Generate a title that will help the u…' to include 'Linked source control context (refere…'.vp test run src/provider/Drivers src/orchestration-v2/ThreadTitleRegenerationService.test.ts src/orchestration-v2/ThreadLaunchService.test.ts src/git/GitManager.test.ts: 17 files, 295 tests passed.vp exec tsc --noEmit -p .: exit 0, no errors.From the repo root:
vp lint --report-unused-disable-directives <changed files>: clean.vp exec knip --workspace apps/server --exports --preprocessor ./scripts/knip-schemas.ts --no-config-hints: exit 0.Net change:
git diff --stat origin/mainreports 10 files changed, 317 insertions(+), 1049 deletions(-).Model/harness: Claude Opus 5.5 (1M context) via Claude Code in T3 Code.
🤖 Generated with Claude Code