Skip to content

fix(OpenAI Responses/provider): skip Responses item id replay when store support is stripped#89729

Closed
snowzlm wants to merge 4 commits into
openclaw:mainfrom
snowzlm:fix/responses-storeless-replay-v2
Closed

fix(OpenAI Responses/provider): skip Responses item id replay when store support is stripped#89729
snowzlm wants to merge 4 commits into
openclaw:mainfrom
snowzlm:fix/responses-storeless-replay-v2

Conversation

@snowzlm

@snowzlm snowzlm commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

What problem does this PR solve?

  • Prevents OpenClaw from replaying prior OpenAI Responses item ids when the effective request is non-persistent (store=false) or store support is stripped because a custom OpenAI Responses-compatible provider declares compat.supportsStore=false.
  • Fixes follow-up/tool-turn failures where custom OpenAI Responses-compatible backends may reject reused store-backed item ids after the request is made stateless.
  • Keeps existing replay behavior for store-enabled OpenAI Responses requests so the change stays scoped to non-persistent routes.

Follow-up issue:

Why the previous main fix was not enough

03dec8bb3a00209780d3140ec3f10ad0eb069030 is included in current main, but current main still allows replay for this custom-provider path:

api: "openai-responses",
provider: "custom-openai-responses",
baseUrl: "https://custom.example.com/v1",
compat: { supportsStore: false }

In that path, the payload policy has:

  • explicitStore === undefined
  • shouldStripStore === true

Current main still uses:

const policyAllowsReplayIds = payloadPolicy.explicitStore !== false;

Because undefined !== false is true, stale Responses item ids can still be replayed even though store support has been stripped.

This PR adds the missing shouldStripStore gate and ensures wrapper-created options disable replayResponsesItemIds when the effective payload is storeless.

Real behavior proof

Behavior or issue addressed: Custom OpenAI Responses-compatible providers that strip Responses store support must not replay prior store-backed Responses item ids. Before this fix, current main still replays stale reasoning, message, and function_call item ids in that storeless path. After this fix, those ids are omitted while the tool call_id remains available for stateless tool-result linking.

Real environment tested: Real local OpenClaw checkout on Linux, updated to latest upstream main and this PR branch. Latest upstream main was ed4c4afc0f6e6ce455bafcd3a2d4857fd1ebc778; updated PR branch was ce91ed58658c11c875055ee252c7e6f755cc7cba. The provider in the repro is a generic custom OpenAI Responses-compatible provider only: provider: "custom-openai-responses", baseUrl: "https://custom.example.com/v1", compat: { supportsStore: false, supportsPromptCacheKey: false }.

Exact steps or command run after this patch: Ran a Node/tsx source-level payload capture in the real checkout. The repro creates prior assistant reasoning, message, and function_call entries with old Responses ids rs_prior, msg_prior, and fc_prior, then calls buildOpenAIResponsesParams for the generic custom OpenAI Responses-compatible provider with compat.supportsStore=false. The same command was run against latest upstream main and against this updated PR branch.

Observed result after fix: Latest upstream main includes prior item ids in the outgoing storeless payload (hasAnyPriorReplayId=true, safeForStorelessReplay=false). This PR branch omits those prior item ids (hasAnyPriorReplayId=false, safeForStorelessReplay=true) while preserving call_id: "call_abc".

Evidence after fix: Terminal output from the real checkout source-level reproduction:

## compare summaries
{
  "sourceLabel": "latest upstream main",
  "sourceSha": "ed4c4afc0f6e6ce455bafcd3a2d4857fd1ebc778",
  "provider": "custom-openai-responses",
  "baseUrl": "https://custom.example.com/v1",
  "hasAnyPriorReplayId": true,
  "safeForStorelessReplay": false,
  "replayedIds": [
    { "type": "message", "id": null, "call_id": null },
    { "type": "reasoning", "id": "rs_prior", "call_id": null },
    { "type": "message", "id": "msg_prior", "call_id": null },
    { "type": "function_call", "id": "fc_prior", "call_id": "call_abc" },
    { "type": "message", "id": null, "call_id": null }
  ]
}
{
  "sourceLabel": "updated fix branch",
  "sourceSha": "ce91ed58658c11c875055ee252c7e6f755cc7cba",
  "provider": "custom-openai-responses",
  "baseUrl": "https://custom.example.com/v1",
  "hasAnyPriorReplayId": false,
  "safeForStorelessReplay": true,
  "replayedIds": [
    { "type": "message", "id": null, "call_id": null },
    { "type": "reasoning", "id": null, "call_id": null },
    { "type": "message", "id": null, "call_id": null },
    { "type": "function_call", "id": null, "call_id": "call_abc" },
    { "type": "message", "id": null, "call_id": null }
  ]
}

Focused tests and CI evidence after fix: GitHub Actions was run first on this PR head (ce91ed58658c11c875055ee252c7e6f755cc7cba) via workflow dispatch: https://github.com/snowzlm/openclaw/actions/runs/26872539403. The relevant shards completed successfully: checks-node-agentic-agents-core-runtime and checks-node-agentic-agents-embedded. The overall CI run is red only because build-artifacts / Check Control UI i18n failed, which is unrelated to this OpenAI Responses replay/store policy change.

Focused local confirmation also passes in a constrained environment using the repo scoped Vitest configs plus OPENCLAW_VITEST_INCLUDE_FILE, so each run only loads the target file:

src/agents/openai-transport-stream.test.ts
openai transport stream > omits Responses replay item ids when custom Responses routes strip store support
✓ passed
Summary: Test Files 1 passed (1), Tests 1 passed | 240 skipped (241)

src/agents/embedded-agent-runner-extraparams.test.ts
applyExtraParamsToAgent > disables Responses replay item ids when custom Responses routes strip store
✓ passed
Summary: Test Files 1 passed (1), Tests 1 passed | 131 skipped (132)

Commands used:

OPENCLAW_VITEST_INCLUDE_FILE='["src/agents/openai-transport-stream.test.ts"]' \
OPENCLAW_VITEST_MAX_WORKERS=1 VITEST_MAX_WORKERS=1 CI=1 \
pnpm exec vitest run --config test/vitest/vitest.agents-core.config.ts \
  -t 'custom Responses routes strip store support' --reporter=verbose --pool=forks

OPENCLAW_VITEST_INCLUDE_FILE='["src/agents/embedded-agent-runner-extraparams.test.ts"]' \
OPENCLAW_VITEST_MAX_WORKERS=1 VITEST_MAX_WORKERS=1 CI=1 \
pnpm exec vitest run --config test/vitest/vitest.agents-embedded-agent.config.ts \
  -t 'custom Responses routes strip store' --reporter=verbose --pool=forks

Local Responses-compatible proxy backend smoke after fix: Added a redacted local backend-acceptance smoke in the real PR checkout. The smoke starts a local POST /v1/responses HTTP server that behaves like a storeless Responses-compatible backend: it rejects follow-up payloads that replay prior Responses item ids (rs_prior, msg_prior, fc_prior) and accepts payloads that omit those ids while preserving the stateless tool call_id.

The smoke uses the same generic custom provider shape as the PR proof (provider: "custom-openai-responses", baseUrl: "https://custom.example.com/v1", compat.supportsStore=false) and does not use or disclose any real custom provider endpoint.

Observed redacted backend result:

{
  "smoke": "local Responses-compatible proxy backend acceptance",
  "prHead": "ce91ed58658c11c875055ee252c7e6f755cc7cba",
  "provider": "custom-openai-responses",
  "configuredBaseUrl": "https://custom.example.com/v1",
  "localEndpoint": "http://127.0.0.1:<redacted>/v1/responses",
  "negativeControl": {
    "status": 400,
    "accepted": false,
    "inspection": {
      "itemCount": 5,
      "replayedPriorIds": ["rs_prior", "msg_prior", "fc_prior"],
      "hasAnyPriorReplayId": true,
      "callIds": ["call_abc", "call_abc"],
      "hasStatelessToolCallId": true,
      "storeField": null
    }
  },
  "fixedBranch": {
    "status": 200,
    "accepted": true,
    "responseStatus": "completed",
    "inspection": {
      "itemCount": 5,
      "replayedPriorIds": [],
      "hasAnyPriorReplayId": false,
      "callIds": ["call_abc", "call_abc"],
      "hasStatelessToolCallId": true,
      "storeField": null
    }
  },
  "pass": true
}

This directly exercises the remaining backend-acceptance gap: the local Responses-compatible backend rejects stale replay ids, then accepts the fixed follow-up turn from the PR branch because prior Responses item ids are absent and the stateless call_id is preserved.

What was not tested: No real custom provider endpoint is used or disclosed in this PR body or evidence. The repro and focused tests stay on the generic custom OpenAI Responses-compatible provider path (provider: "custom-openai-responses", baseUrl: "https://custom.example.com/v1").

Tests

  • Added/kept coverage for direct buildOpenAIResponsesParams behavior when custom Responses routes strip store support.
  • Added/kept coverage for wrapper-created options disabling replayResponsesItemIds when custom Responses routes strip store support.
  • GitHub Actions workflow-dispatch CI was run on this PR head; relevant shards checks-node-agentic-agents-core-runtime and checks-node-agentic-agents-embedded passed. The only overall CI failure was unrelated build-artifacts / Check Control UI i18n.
  • Focused local Vitest confirmation passed for both target tests using scoped configs and OPENCLAW_VITEST_INCLUDE_FILE.
  • Redacted local Responses-compatible proxy smoke passed: negative control with stale prior item ids was rejected (400), while the PR branch follow-up payload was accepted (200 completed) with no prior Responses item ids and preserved stateless call_id.
  • Source-level deterministic reproduction confirms current main is unsafe and this branch is safe for the generic custom OpenAI Responses-compatible provider case.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 3, 2026
@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 3, 2026, 11:28 AM ET / 15:28 UTC.

Summary
The PR changes OpenAI Responses payload construction and the OpenAI Responses context-management wrapper so store-stripped custom Responses-compatible providers do not replay prior Responses item ids.

PR surface: Source +3, Tests +137. Total +140 across 4 files.

Reproducibility: yes. Source inspection shows current main can resolve shouldStripStore: true while still defaulting replay ids on because the replay gate only checks explicitStore !== false; the PR body also supplies before/after terminal output and a local backend smoke, though I did not run tests in this read-only review.

Review metrics: none identified.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • No ClawSweeper repair lane is needed because the branch already contains the focused fix and proof; remaining action is maintainer review and merge gating.

Security
Cleared: The diff changes payload policy and regression tests only; it introduces no dependency, workflow, credential, package-resolution, or code-download surface.

Review details

Best possible solution:

Land this focused fix after normal maintainer review and required checks; keep the linked follow-up issue open until the merge closes it.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main can resolve shouldStripStore: true while still defaulting replay ids on because the replay gate only checks explicitStore !== false; the PR body also supplies before/after terminal output and a local backend smoke, though I did not run tests in this read-only review.

Is this the best way to solve the issue?

Yes. The best fix is to use the existing payload policy at the two replay handoff points; provider-specific branching or stripping ids inside conversion would be a less direct owner boundary.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against d358294f897c.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal/source-level output and a redacted local Responses-compatible backend smoke that rejects stale prior ids and accepts the fixed payload.

Label justifications:

  • P2: The PR fixes a scoped provider follow-up/tool-turn failure for custom OpenAI Responses-compatible routes, with limited blast radius.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes after-fix terminal/source-level output and a redacted local Responses-compatible backend smoke that rejects stale prior ids and accepts the fixed payload.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal/source-level output and a redacted local Responses-compatible backend smoke that rejects stale prior ids and accepts the fixed payload.
Evidence reviewed

PR surface:

Source +3, Tests +137. Total +140 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 7 4 +3
Tests 2 137 0 +137
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 144 4 +140

What I checked:

  • Root policy read: Root AGENTS.md was read fully and required whole-surface review, scoped AGENTS checks, provider compatibility caution, and direct dependency/Codex contract inspection for this provider-runtime verdict. (AGENTS.md:1, d358294f897c)
  • Scoped policy read: src/agents/AGENTS.md was read; it adds test-performance guidance for the touched agent tests but does not change the provider-runtime decision. (src/agents/AGENTS.md:1, d358294f897c)
  • Current main direct-builder gap: On current main, buildOpenAIResponsesParams resolves payload policy with storeMode disable but allows replay unless explicitStore is exactly false, so shouldStripStore true does not disable item-id replay. (src/agents/openai-transport-stream.ts:2199, d358294f897c)
  • Current main wrapper gap: On current main, the wrapper derives replayResponsesItemIds from explicitStore only, leaving store-stripped custom routes to inherit caller/default replay behavior when explicitStore is undefined. (src/llm/providers/stream-wrappers/openai.ts:399, d358294f897c)
  • Payload policy owner: resolveOpenAIResponsesPayloadPolicy sets shouldStripStore when compat.supportsStore is false for a Responses API, independently from explicitStore, so the missing gate belongs at the replay-policy handoff. (src/agents/openai-responses-payload-policy.ts:353, d358294f897c)
  • PR patch read: The PR adds !payloadPolicy.shouldStripStore to the direct-builder replay gate and makes the wrapper pass replayResponsesItemIds: false when the policy strips store. (src/agents/openai-transport-stream.ts:2202, ce91ed58658c)

Likely related people:

  • Vincent Koc: Recent history shows repeated provider/OpenAI transport and compatibility commits in the central files, including compat endpoint detection and store/proxy policy work. (role: recent area contributor; confidence: medium; commits: 66825c09699a, 7836c9a6c24d, cc1881a83846; files: src/agents/openai-transport-stream.ts, src/llm/providers/stream-wrappers/openai.ts, src/agents/openai-responses-payload-policy.ts)
  • Peter Steinberger: Recent history shows multiple OpenAI transport/default/tool-schema refactors in the same provider area. (role: adjacent owner; confidence: medium; commits: 628c71103eb7, 3207c5326a94, a9125ec0b07b; files: src/agents/openai-transport-stream.ts, src/llm/providers/stream-wrappers/openai.ts)
  • waterblue: Authored the prior mainline explicit store=false replay-id fix that this PR follows up. (role: introduced adjacent fix; confidence: medium; commits: 03dec8bb3a00; files: src/agents/openai-transport-stream.ts, src/llm/providers/stream-wrappers/openai.ts, src/agents/openai-transport-stream.test.ts)
  • Ayaan Zaidi: Touched the Responses payload capability detection file that defines store support and shouldStripStore behavior. (role: adjacent capability contributor; confidence: medium; commits: 685f9903ec38; files: src/agents/openai-responses-payload-policy.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 3, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jun 3, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@snowzlm

snowzlm commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper Re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 3, 2026
@snowzlm snowzlm changed the title fix: skip Responses item id replay when store support is stripped fix(OpenAI Responses/provider): skip Responses item id replay when store support is stripped Jun 3, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. labels Jun 3, 2026
@snowzlm

snowzlm commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper Re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

Re-review progress:

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 3, 2026
@snowzlm

snowzlm commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

Closing as duplicate/superseded by #90706. The refreshed #90706 branch is based on latest main and now includes both the direct builder fix from this PR set and the wrapper fix originally covered here.

@snowzlm snowzlm closed this Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Custom OpenAI Responses-compatible providers still replay item ids when store support is stripped

1 participant