Skip to content

feat(provider): OpenAI Responses background mode (sa-73) - #2518

Merged
topcheer merged 2 commits into
mainfrom
sa-73-background
Sep 18, 2026
Merged

topcheer merged 2 commits into
mainfrom
sa-73-background

Conversation

@topcheer

Copy link
Copy Markdown
Owner

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 /responses blocked 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

  • Create with background: true -> API returns a Response object with status queued immediately and executes 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.
  • Cancel on context cancellation via idempotent POST /responses/{id}/cancel (best-effort, fresh 5s context) so a dropped turn stops burning tokens.
  • Streaming: 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 - the stateless encrypted-reasoning loop (sa-54) and hosted-tool echo (sa-62) work unchanged.
  • Config: opt-in per endpoint via responses_background: true, wired EndpointConfig -> ResolvedEndpoint -> registry (both the openai-responses case and the URL-sniff fallback).
  • Chat() non-background behavior is untouched (decode path refactored into shared chatResponseFromPayload).

Test plan

  • 9 new httptest-based tests: request flag, poll-to-completion, transient-error retry, failed/cancelled/incomplete terminal states, cancel-on-context-cancel, incremental stream deltas, config wiring
  • go test -race -tags goolm clean on background tests
  • Full internal/provider + internal/config suites pass (-p 1 -parallel 2, -tags goolm)
  • linux/amd64 + darwin/arm64 go vet -tags goolm ./... clean; gofmt clean
  • Docs: new "Background mode" section in docs/guide/providers.md

Co-Authored-By: ggcode noreply@ggcode.dev

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 topcheer left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审通过 ✅(三重点核销)

① 轮询面:指数退避 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 绿。可合并。

@topcheer

Copy link
Copy Markdown
Owner Author

复审已过(见 review:指数钳 1s→10s+5 错熔断+ctx 取消先 cancelResponse/增量快照流/usage 归属发起 run)。与 main 冲突——#2515/#2517 先合并动了 openai_responses.go 相邻区(responsesRequest struct 的 Reasoning/Text/Background 字段区+post 方法)。分支 sa-73-background 有归属者本地 worktree 在途——请归属者 rebase main 解冲突,解后 CI 绿即合并。不代解。

Junjun Zhang and others added 2 commits September 18, 2026 13:54
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
topcheer merged commit 47f4a20 into main Sep 18, 2026
8 checks passed
@topcheer
topcheer deleted the sa-73-background branch September 18, 2026 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant