Fix Code Generation Resilience
Summary
Improved strategy code generation resilience after OpenAI Responses API/network failures caused long waits, stuck tool states, blank code previews, and duplicate user turns during durable replay.
Root Cause
- The Codex/OpenAI Responses adapter had no bounded request timeout, no stream idle timeout, and no retry path for transient provider or transport failures.
write_strategy_codelet provider errors bubble through as a generic tool failure, after which the planner could continue and re-enter tool calls.- Code preview hydration only trusted
codeSoFar, so persisted progress inmeta.code_so_faror final/partialresult.codeTextcould render as an empty Code Generation block. - Durable replay inserted the run-start user turn by durable id only, so an optimistic local user turn with the same text could remain and make the message appear duplicated.
Changes
- Added bounded OpenAI Responses API handling in
services/backend/src/lib/ai/openai-responses-adapter.ts:- 120s request timeout
- 90s stream idle timeout
- one retry for transient HTTP statuses and transport failures
- request-id-aware error messages
- abort propagation when streams are cancelled
- Updated
write_strategy_codeinservices/backend/src/routes/bots/bots-chat-handlers.ts:- retries transient generation failures once
- emits initial and partial
code_so_farprogress - preserves partial code in tool error results when available
- stops further tool replanning after strategy/analysis code-generation tool failures
- fails with a clear no-save error when generation cannot complete
- Updated durable replay in
services/frontend/src/routes/bots/BotDetailPage.tsx:- restores code preview from
codeSoFar,meta.code_so_far, orresult.codeText - dedupes replayed user turns by matching message text and sender
- reuses optimistic assistant turns for the durable run assistant
- settles stale running tool calls when runs finish, error, cancel, or hydrate with no active run
- restores code preview from
- Updated
packages/chat-ui/src/StreamingChatPanel.tsx:- preserves code preview from final/partial tool results
- settles running tools on
done,error,cancelled, stream close, and non-abort catch paths - shows a nonblank running code panel with
Waiting for the first code chunk...before the first streamed code delta
Key Snippets
const RESPONSES_API_REQUEST_TIMEOUT_MS = 120_000;
const RESPONSES_API_STREAM_IDLE_TIMEOUT_MS = 90_000;
const RESPONSES_API_RETRY_STATUS_CODES = new Set([408, 409, 429, 500, 502, 503, 504, 520, 522, 524]);
const partialResult = latestCodeSoFar
? { ok: false, error: errorMsg, codeText: latestCodeSoFar, partial: true }
: null;
const extractToolCodePreview = (value) =>
value.codeSoFar ?? value.meta?.code_so_far ?? value.result?.codeText;
Validation
pnpm --filter @quantago/api typecheckpassed.pnpm --filter @quantago/frontend typecheckpassed.pnpm --filter @quantago/api lintpassed with existing warning-only baseline.pnpm --filter @quantago/frontend lintpassed with existing warning-only baseline.pnpm typecheckpassed for API, frontend, admin, docs, and landing.pnpm lintpassed with existing warning-only baseline.
Deployments
- Dev backend version:
a6e70e3d-c148-4632-9544-c6038bd906f7 - Production backend version:
0bdfee8c-36b2-4c5b-925b-08a1fd55ce4b - Dev frontend Pages:
https://a2ec6c65.quantago-app.pages.dev(https://develop.quantago-app.pages.dev) - Production frontend Pages:
https://787647d9.quantago-app.pages.dev
Health Checks
- Dev API: HTTP 200
- Production API: HTTP 200
- Dev frontend: HTTP 200
- Production frontend: HTTP 200