feat(provider): OpenAI Responses background mode (sa-73) - #2518
Merged
Merged
Conversation
topcheer
pushed a commit
that referenced
this pull request
Sep 18, 2026
…lution (sa-73) Follow-up to PR #2518: companion-file check flagged config_vendor_test.go. Adds TestResponsesBackgroundWiring verifying responses_background: true survives yaml unmarshal and ResolveEndpoint propagation (on/off cases), so registry background-mode wiring cannot silently regress. Co-Authored-By: ggcode <noreply@ggcode.dev>
topcheer
commented
Sep 18, 2026
topcheer
left a comment
Owner
Author
There was a problem hiding this comment.
复审通过 ✅(三重点核销)
① 轮询面:指数退避 1s 起倍增至 10s 帽(长任务不空转 API)+连续 5 错熔断(持续端点失败浮出而非永轮——瞬态断连容忍由 background 模式存在意义注释论证)+ctx 取消优先分支(先 best-effort cancelResponse 再返回——dropped turn 不烧 token)。
② 前后台消息序:onPoll 增量快照(每次 poll payload 与上次 diff 出新 text 流式发)——文本顺序=服务器产出顺序(快照单调追加);后台模式无 tool_call 前后台竞态(terminal 才返回完整 payload——工具调用经终态统一交付)。
③ 成本归属:终态 payload 的 usage 随正常 Chat 返回路径进本次 run 的 TokenUsage——后台 token 计入发起 run(无归属漂移);cancel 场景 usage 丢弃(服务器侧取消语义)。
opt-in 配置门(responses_background yaml)+非后台路径零变。CI 绿。可合并。
Owner
Author
Long reasoning turns (GPT-5.x Pro, codex-max) previously held one HTTP
connection open for the entire multi-minute execution, making them fragile
against idle timeouts and dropped connections (learned the hard way in
sa-66/sa-71 where 5-minute+ turns kept dying).
Implements OpenAI's background mode (2025-12-31 guide, currently in
openbeta) on the stateless-replay Responses adapter:
- Create with background=true; API returns a Response object with status
"queued" immediately (goes to work server-side).
- Poll GET /responses/{id} with exponential backoff (1s -> 10s cap) until
a terminal state (completed/failed/incomplete/cancelled). Tolerates up
to 5 consecutive transient poll errors.
- Context cancellation explicitly cancels the server-side run via
POST /responses/{id}/cancel (idempotent, best-effort) so a dropped
turn stops burning tokens.
- ChatStream in background mode diffs text across poll snapshots for
incremental deltas; reasoning items / function calls / hosted
web_search items are replayed from the terminal payload so the
stateless encrypted-reasoning loop (sa-54) and hosted-tool echo
(sa-62) keep working unchanged.
- Opt-in per endpoint: responses_background: true in config, wired
through EndpointConfig -> ResolvedEndpoint -> registry (both the
openai-responses case and the URL-sniff fallback).
Docs: new "Background mode" section in docs/guide/providers.md.
Tests: 9 httptest-based tests covering request flag, poll-to-completion,
transient-error retry, failed/cancelled/incomplete terminal states,
cancel-on-context-cancel, incremental stream deltas, and config wiring.
Race-clean; full provider+config suites pass with -tags goolm.
Co-Authored-By: ggcode <noreply@ggcode.dev>
Co-Authored-By: ggcode <noreply@ggcode.dev>
…lution (sa-73) Follow-up to PR #2518: companion-file check flagged config_vendor_test.go. Adds TestResponsesBackgroundWiring verifying responses_background: true survives yaml unmarshal and ResolveEndpoint propagation (on/off cases), so registry background-mode wiring cannot silently regress. Co-Authored-By: ggcode <noreply@ggcode.dev>
topcheer
force-pushed
the
sa-73-background
branch
from
September 18, 2026 05:56
92f2cce to
1a5bdcd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements OpenAI Responses background mode (official guide: platform.openai.com/docs/guides/background, openbeta) for the stateless-replay Responses adapter, so multi-minute reasoning turns (GPT-5.x Pro, codex-max) no longer depend on a single held-open HTTP connection.
Problem
ggcode's Responses client was purely synchronous:
POST /responsesblocked until the full response finished. GPT-5.x Pro / codex-max runs of 5+ minutes repeatedly died on idle timeouts and dropped connections (recurring pattern in sa-66/sa-71).Implementation
background: true-> API returns a Response object with statusqueuedimmediately and executes server-side.GET /responses/{id}with exponential backoff (1s -> 10s cap) until a terminal state (completed/failed/incomplete/cancelled); tolerates up to 5 consecutive transient poll errors.POST /responses/{id}/cancel(best-effort, fresh 5s context) so a dropped turn stops burning tokens.ChatStreamin background mode diffs text across poll snapshots for incremental deltas; reasoning items / function calls / hostedweb_searchitems are replayed from the terminal payload - the stateless encrypted-reasoning loop (sa-54) and hosted-tool echo (sa-62) work unchanged.responses_background: true, wiredEndpointConfig->ResolvedEndpoint-> registry (both theopenai-responsescase and the URL-sniff fallback).Chat()non-background behavior is untouched (decode path refactored into sharedchatResponseFromPayload).Test plan
go test -race -tags goolmclean on background testsinternal/provider+internal/configsuites pass (-p 1 -parallel 2,-tags goolm)go vet -tags goolm ./...clean; gofmt cleanCo-Authored-By: ggcode noreply@ggcode.dev