Skip to content

fix(openai): avoid stale Responses message id replay#85277

Merged
steipete merged 5 commits into
openclaw:mainfrom
latensified:fix/openai-responses-pruned-reasoning
May 31, 2026
Merged

fix(openai): avoid stale Responses message id replay#85277
steipete merged 5 commits into
openclaw:mainfrom
latensified:fix/openai-responses-pruned-reasoning

Conversation

@latensified

@latensified latensified commented May 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: OpenAI Responses request replay can reuse a signed assistant message item id after the corresponding reasoning item has been pruned from local history.
  • Solution: replay signed assistant message ids only when the immediately preceding replayed item is the paired reasoning item.
  • What changed: added a small replay-id policy helper, wired it into the OpenAI Responses transport, and covered the pruned-reasoning case in the existing reasoning replay tests.
  • What did NOT change (scope boundary): this does not change reasoning-item replay, tool-call replay, payload metadata, model selection, or Telegram formatting.

Motivation

This prevents a latent OpenAI Responses failure exposed by long-running sessions whose assistant text still has a persisted Responses item id but whose paired reasoning item is no longer replayable. In that state, the next request can be rejected before the model responds.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: OpenAI Responses rejected replayed conversation history when an assistant message item id was included without the required paired reasoning item, while phase metadata still needs to survive without replaying orphan provider-owned assistant ids.
  • Real environment tested: local OpenClaw source checkout on macOS arm64 using the OpenAI Responses transport path, plus a live OpenAI Responses API request against gpt-5.5 on May 31, 2026 after maintainer fixup d6902ed1a0f13c7b73e69fcfdc6566086b3c532f.
  • Exact steps or command run after this patch:
node --import tsx --input-type=module <<'INNER'
import OpenAI from 'openai';
import { buildOpenAIResponsesParams } from './src/agents/openai-transport-stream.ts';

const model = {
  id: 'gpt-5.4',
  name: 'gpt-5.4',
  api: 'openai-responses',
  provider: 'openai',
  baseUrl: 'https://api.openai.com/v1',
  reasoning: true,
  input: ['text'],
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
  contextWindow: 128000,
  maxTokens: 4096,
};
const ZERO_USAGE = {
  input: 0,
  output: 0,
  cacheRead: 0,
  cacheWrite: 0,
  totalTokens: 0,
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
};
const context = {
  systemPrompt: 'system',
  messages: [
    { role: 'user', content: 'Earlier prompt', timestamp: 1 },
    {
      role: 'assistant',
      api: 'openai-responses',
      provider: 'openai',
      model: 'gpt-5.4',
      usage: ZERO_USAGE,
      stopReason: 'stop',
      timestamp: 2,
      content: [
        {
          type: 'text',
          text: 'Earlier answer',
          textSignature: 'msg_real_response_item_requiring_reasoning',
        },
      ],
    },
    {
      role: 'assistant',
      api: 'openai-responses',
      provider: 'openai',
      model: 'gpt-5.4',
      usage: ZERO_USAGE,
      stopReason: 'stop',
      timestamp: 2,
      content: [
        {
          type: 'thinking',
          thinking: 'chain',
          thinkingSignature: JSON.stringify({
            id: 'rs_reasoning_item',
            type: 'reasoning',
            summary: [],
          }),
        },
        {
          type: 'text',
          text: 'Pinned commentary answer',
          textSignature: JSON.stringify({ v: 1, id: 'msg_commentary', phase: 'commentary' }),
        },
      ],
    },
    { role: 'user', content: 'Latest prompt', timestamp: 3 },
  ],
};
const params = buildOpenAIResponsesParams(model, context, {});
const captured = {};
const client = new OpenAI({
  apiKey: 'test',
  baseURL: 'https://api.openai.com/v1',
  fetch: async (url, init) => {
    captured.url = String(url);
    captured.body = init?.body ? String(init.body) : '';
    return new Response(JSON.stringify({
      id: 'resp_test',
      object: 'response',
      created_at: 0,
      status: 'completed',
      model: 'gpt-5.4',
      output: [],
      parallel_tool_calls: false,
      tools: [],
    }), {
      status: 200,
      headers: { 'content-type': 'application/json' },
    });
  },
});
await client.responses.create({ ...params, stream: false });
const payload = JSON.stringify(params.input);
console.log(JSON.stringify({
  proof: 'openai-responses-sdk-loopback',
  pr_head: 'b60fd8baa5901ec405764edfa476b867f65c1f60',
  request_path: new URL(captured.url).pathname,
  stale_signed_message_id: 'msg_real_response_item_requiring_reasoning',
  stale_id_present_in_openclaw_payload: payload.includes('msg_real_response_item_requiring_reasoning'),
  stale_id_present_in_sdk_request: captured.body.includes('msg_real_response_item_requiring_reasoning'),
  commentary_phase_id_present_in_openclaw_payload: payload.includes('msg_commentary'),
  commentary_phase_id_present_in_sdk_request: captured.body.includes('msg_commentary'),
}, null, 2));
INNER
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):

Before this patch, the live OpenClaw Telegram agent diagnosed a real OpenAI Responses failure after conversation pruning:

OpenAI rejected the next request with:
message was provided without its required reasoning item

Failure shape:
- prior assistant message ids were replayed from textSignature
- paired reasoning items had been pruned/unavailable

After this patch, I reran the current-head OpenAI SDK loopback on b60fd8baa5901ec405764edfa476b867f65c1f60. It imported buildOpenAIResponsesParams from src/agents/openai-transport-stream.ts, sent that exact payload through OpenAI Node SDK 6.39.0 with an in-process fetch loopback, and confirmed that both the OpenClaw payload and the serialized SDK /v1/responses request omitted the stale raw signed assistant message id while preserving phase metadata and omitting the phase-tagged provider-owned replay id:

{
  "proof": "openai-responses-sdk-loopback",
  "pr_head": "b60fd8baa5901ec405764edfa476b867f65c1f60",
  "request_path": "/v1/responses",
  "stale_signed_message_id": "msg_real_response_item_requiring_reasoning",
  "stale_id_present_in_openclaw_payload": false,
  "stale_id_present_in_sdk_request": false,
  "commentary_phase_id_present_in_openclaw_payload": true,
  "commentary_phase_id_present_in_sdk_request": true
}

Maintainer live proof on d6902ed1a0f13c7b73e69fcfdc6566086b3c532f sent the PR-built payload to the real OpenAI Responses API. The setup produced both reasoning and message output items; the replayed message preserved phase: final_answer, omitted the provider-owned message id, and the live request completed.

{
  "proof": "live-openai-responses-phase-id-omitted",
  "model": "gpt-5.5",
  "setup_output_types": ["reasoning", "message"],
  "replayed_message_has_id": false,
  "replayed_message_phase": "final_answer",
  "live_result_status": "completed"
}
  • Observed result after fix: stale raw signed assistant message ids are omitted when their required reasoning item is absent; phase-tagged provider ids are omitted without losing phase metadata, and unsigned assistant messages still get the existing synthetic fallback id.
  • What was not tested: a live deployed gateway restart has not been run; focused replay tests now pass via node scripts/run-vitest.mjs src/agents/openai-transport-stream.test.ts src/agents/openai-responses.reasoning-replay.test.ts src/llm/providers/openai-responses-shared.test.ts (3 shards, 228 tests), alongside a live OpenAI Responses API proof.
  • Before evidence (optional but encouraged): live OpenClaw agent output above captured the OpenAI rejection text and identified the pruned-reasoning replay shape.

Root Cause (if applicable)

  • Root cause: the Responses replay path treated persisted assistant text signatures as independently replayable message ids, but OpenAI can require the corresponding reasoning item to be replayed with that message item.
  • Missing detection / guardrail: existing coverage checked reasoning replay when reasoning was present; it did not check the pruned-reasoning case where only the signed assistant message survived.
  • Contributing context (if known): long-lived sessions can prune or omit reasoning items while retaining assistant text signatures.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/agents/openai-responses.reasoning-replay.test.ts
  • Scenario the test should lock in: a signed assistant message id is omitted when no paired reasoning item was replayed; the same signed id is preserved when paired reasoning was replayed; unsigned text still uses the fallback id.
  • Why this is the smallest reliable guardrail: the bug is in request payload construction, before network IO, so the replay-id policy can be tested deterministically.
  • Existing test that already covers this (if any): none for the pruned-reasoning signed-message case.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

None, except affected OpenAI Responses sessions avoid a provider-side 400 when replay history has a stale signed message id without its paired reasoning item.

Diagram (if applicable)

Before:
[assistant textSignature id survives] -> [reasoning item pruned] -> [request replays message id] -> [OpenAI rejects]

After:
[assistant textSignature id survives] -> [reasoning item pruned] -> [request omits stale message id] -> [request remains valid]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS arm64
  • Runtime/container: local Node/Vitest via OpenClaw source checkout
  • Model/provider: openai/gpt-5.4, OpenAI Responses
  • Integration/channel (if any): Telegram agent session exposed the failure; source regression covers the transport replay policy.
  • Relevant config (redacted): OpenAI Responses API model with reasoning enabled.

Steps

  1. Create a replay candidate with a signed assistant text message id.
  2. Omit the paired reasoning item, matching a pruned history state.
  3. Build the next OpenAI Responses request.

Expected

  • The stale signed assistant message id is omitted when paired reasoning is unavailable.

Actual

  • Before this change, the stale signed assistant message id was replayed even when the paired reasoning item was unavailable.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: live OpenAI Responses gpt-5.5 API proof via an inline node --import tsx --input-type=module script that imported buildOpenAIResponsesParams from src/agents/openai-transport-stream.ts; focused replay regression coverage via node scripts/run-vitest.mjs src/agents/openai-transport-stream.test.ts src/agents/openai-responses.reasoning-replay.test.ts src/llm/providers/openai-responses-shared.test.ts (3 shards, 228 tests); node scripts/run-tsgo.mjs -p tsconfig.core.json; node scripts/run-oxlint.mjs on touched files; git diff --check; autoreview clean.
  • Edge cases checked: raw and phase-tagged signed ids without reasoning are omitted; phase metadata is preserved; signed id with reasoning is preserved; unsigned assistant text keeps the synthetic fallback id.
  • What you did not verify: live gateway deployment on this branch.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: omitting a stale Responses message id may reduce provider-side continuity for that one historical assistant message.
    • Mitigation: the text content and phase metadata are still replayed; the id is omitted only when the paired reasoning item is missing, which is the provider-rejected shape.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S proof: supplied External PR includes structured after-fix real behavior proof. labels May 22, 2026
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 31, 2026, 2:59 PM ET / 18:59 UTC.

Summary
The PR adds a Responses replay-id policy to the embedded and shared OpenAI Responses converters, plus regression tests, so persisted assistant message ids are replayed only when the paired reasoning item was replayed.

PR surface: Source +36, Tests +196. Total +232 across 5 files.

Reproducibility: yes. Current main source shows raw assistant textSignature ids are still replayed without a local reasoning-pair check, and the PR body includes before/after provider evidence for the rejected message without required reasoning shape.

Review metrics: 1 noteworthy metric.

  • Responses replay policy: 2 converter paths changed. Both embedded and shared Responses payload builders now enforce the same provider-owned message-id pairing rule before merge.

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:

  • [P2] Resolve or rerun checks-node-agentic-agents-core before merge.

Risk before merge

  • [P1] Merging changes Responses replay continuity by omitting persisted provider-owned assistant message ids when the paired reasoning item is absent; existing sessions may lose provider-side continuity for that one assistant item even though visible text and phase are replayed.
  • [P1] One current check-run, checks-node-agentic-agents-core, is failing on the PR head; I could not inspect unauthenticated logs, so merge should wait for that validation to be resolved or rerun cleanly.

Maintainer options:

  1. Make validation green before merge (recommended)
    Resolve or rerun the failed agents-core check on fe7c3ad before treating the PR as merge-ready.
  2. Accept the replay-continuity tradeoff
    Maintainers can intentionally accept that orphan provider message ids are dropped because the alternative is a provider-rejected request shape.

Next step before merge

  • [P2] Keep this in maintainer review until the failed agents-core check is resolved and maintainers accept the Responses replay-continuity tradeoff; I found no narrow source defect for an automated repair.

Security
Cleared: The diff only changes OpenAI Responses payload construction and tests; it does not add dependencies, permissions, scripts, secrets handling, or new code-execution paths.

Review details

Best possible solution:

Land the narrow converter-level replay policy after the failed agents-core check is green, preserving text and phase replay while omitting provider-owned message ids when reasoning is absent.

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

Yes. Current main source shows raw assistant textSignature ids are still replayed without a local reasoning-pair check, and the PR body includes before/after provider evidence for the rejected message without required reasoning shape.

Is this the best way to solve the issue?

Yes. The PR is the best narrow fix because the merged sanitizer handles one history-rewrite path, while both Responses converters still need a final payload-level guard for stale persisted ids.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix SDK loopback output plus maintainer live OpenAI Responses API output at the current head showing the stale provider id omitted and the request completed.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body provides after-fix SDK loopback output plus maintainer live OpenAI Responses API output at the current head showing the stale provider id omitted and the request completed.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: This is a focused provider replay bug fix with limited blast radius but real session-continuation impact for OpenAI Responses users.
  • merge-risk: 🚨 compatibility: The PR intentionally changes replay behavior for persisted provider-owned assistant message ids, which can affect existing conversation continuity on upgrade.
  • merge-risk: 🚨 session-state: The affected data is persisted assistant/reasoning replay state used to build later agent turns.
  • 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 (live_output): The PR body provides after-fix SDK loopback output plus maintainer live OpenAI Responses API output at the current head showing the stale provider id omitted and the request completed.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix SDK loopback output plus maintainer live OpenAI Responses API output at the current head showing the stale provider id omitted and the request completed.
Evidence reviewed

PR surface:

Source +36, Tests +196. Total +232 across 5 files.

View PR surface stats
Area Files Added Removed Net
Source 3 65 29 +36
Tests 2 198 2 +196
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 5 263 31 +232

What I checked:

  • Repository policy read: Read the full root AGENTS.md and the scoped src/agents/AGENTS.md; the review applied the OpenClaw requirements to inspect sibling converter paths, dependency contracts, current main behavior, and compatibility risk for provider/session-state changes. (AGENTS.md:1, 9d54285b0d4a)
  • Current main embedded converter still trusts textSignature ids: On current main, the embedded Responses converter assigns msgId = textSignature.id whenever a text signature id exists, without requiring a replayed reasoning item immediately before the message. (src/agents/openai-transport-stream.ts:1154, 9d54285b0d4a)
  • Current main shared converter has the same replay surface: The shared OpenAI/Azure/Codex Responses converter on current main likewise uses parsedSignature?.id as the outgoing assistant message id, so the merged sanitizer fix does not cover every raw converter replay case. (src/llm/providers/openai-responses-shared.ts:237, 9d54285b0d4a)
  • PR head fixes the embedded converter path: At PR head fe7c3ad, the embedded converter tracks whether the previous replayed input item was reasoning and omits provider-owned assistant message ids when that pairing is absent, while still preserving phase metadata. (src/agents/openai-transport-stream.ts:1116, fe7c3ade2953)
  • PR head fixes the shared converter path: At PR head fe7c3ad, the shared converter applies the same previous-reasoning replay policy and emits assistant messages without id when a signed provider message id lacks its paired reasoning item. (src/llm/providers/openai-responses-shared.ts:257, fe7c3ade2953)
  • Regression coverage covers raw and phase-tagged orphan ids: The PR adds shared converter coverage for both phase-tagged assistant ids and raw signed assistant ids when reasoning is absent, and the embedded reasoning replay test covers the same policy through the transport path. (src/llm/providers/openai-responses-shared.test.ts:130, fe7c3ade2953)

Likely related people:

  • steipete: Peter Steinberger authored the current PR head fixup and is the assignee; the live PR metadata and commit list show fe7c3ad as his commit touching the replay policy files. (role: recent area contributor and fixup author; confidence: high; commits: fe7c3ade2953; files: src/agents/openai-transport-stream.ts, src/llm/providers/openai-responses-shared.ts, src/agents/openai-responses-replay.ts)
  • BSG2000: The merged related PR fix(responses): drop orphaned assistant msg_* id when reasoning is dropped (#88019) #88067 handled the sanitizer-side orphan msg_*/reasoning pairing behavior that this PR builds on. (role: recent related fix author; confidence: high; commits: 48980a0f414d; files: src/agents/embedded-agent-helpers/openai.ts, src/agents/openai-transport-stream.ts, src/llm/providers/openai-responses-shared.ts)
  • Thomas Krohnfuß: Local git history records the merge commit for the related current-main orphan-id sanitizer fix under this author name, so this is another useful routing breadcrumb when GitHub-handle mapping is needed. (role: merge commit author for related current-main behavior; confidence: medium; commits: 48980a0f414d; files: src/agents/embedded-agent-helpers/openai.ts, src/agents/openai-transport-stream.ts, src/llm/providers/openai-responses-shared.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.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 22, 2026
@clawsweeper

clawsweeper Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg: ✨ hatched 🥚 common Clockwork Shellbean. Rarity: 🥚 common. Trait: sparkles near resolved comments.

Details

Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Clockwork Shellbean in ClawSweeper.
Hatchability:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

About:

  • Eggs appear after real-behavior proof passes. They are collectible flavor only.
  • Review momentum changes the shell state: follow-up work warms it, re-review makes it wobble, and a clean final review lets it hatch.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@latensified
latensified force-pushed the fix/openai-responses-pruned-reasoning branch from 3f861ea to 28cb124 Compare May 22, 2026 12:04
@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels May 22, 2026
@latensified

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 22, 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.

Re-review progress:

@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. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 22, 2026
@latensified

Copy link
Copy Markdown
Contributor Author

Maintainer coordination note for the adjacent Responses replay PRs:

I checked #84267, #84904, and #85362 against this PR's item-id rule. Proposed final policy/layering:

  1. Store policy wins first (fix: avoid replaying Responses item ids when store is disabled #84904): when the final Responses payload is store:false, do not replay provider-owned item ids (reasoning.id, assistant message.id, or function_call.id). When a wrapper explicitly sends store:true, id replay can remain enabled.
  2. Pairing rule applies only after ids are allowed (fix(openai): avoid stale Responses message id replay #85277): a signed assistant message id is replayable only when the immediately preceding replayed input item is its paired reasoning item. If reasoning was pruned/dropped/unavailable, replay the visible text/phase but omit the signed message id.
  3. Reasoning-replay recovery (fix(agents): recover invalid OpenAI Responses reasoning replay #84267): on pre-start invalid encrypted reasoning, retry once after dropping replayable reasoning and paired function-call ids. With this PR layered in, that retry should also omit the signed assistant message id whose paired reasoning was dropped. "Preserve replayed message" should mean visible message content/phase, not necessarily provider item id.
  4. Replay-invalid session reset (Fix replay-invalid session recovery #85362): treat as fallback when replay-invalid state reaches reply-agent failure handling or native Codex/session state is poisoned. It should not replace fix(agents): recover invalid OpenAI Responses reasoning replay #84267's recoverable transport retry.

Suggested merge order: #84904 -> #85277 -> #84267 -> #85362. If maintainers choose a different order, the same policy still applies, but the rebase that combines #84267/#85362 should keep a single exported isOpenAIResponsesReasoningReplayInvalidErrorMessage helper and include invalid_encrypted_content in that helper so transport retry and session-reset classification share the same OpenAI Responses encrypted-content error contract.

Expected file-level coordination:

That gives a coherent final contract: store-disabled requests send no server-owned item ids; store-enabled requests only send ids that are still internally paired and replayable; invalid reasoning recovery retries without reasoning and without stale signed message ids; session reset remains the last-resort poisoned-history escape hatch.

@latensified

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 22, 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:

@latensified
latensified force-pushed the fix/openai-responses-pruned-reasoning branch from 28cb124 to 6e4da12 Compare May 24, 2026 02:16
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 24, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed 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. labels May 24, 2026
@latensified

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Refreshed the ## Real behavior proof section on the current head f0125dff3e8ed40c7927d0cad6c824f03bc74449.

What changed:

  • replaced the stale a9e4a7b... proof references with current-head evidence
  • reran the OpenAI SDK in-process /v1/responses loopback against buildOpenAIResponsesParams from this branch
  • confirmed the stale signed assistant message id is absent from both the OpenClaw payload and the serialized SDK request body while the phase-tagged replay id is still preserved

Verification:

  • inline node --import tsx --input-type=module current-head SDK loopback proof
  • git diff --check

No source files changed in this follow-up; this refresh only aligns the public proof with the live PR head.

@clawsweeper

clawsweeper Bot commented May 29, 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:

@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. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 29, 2026
@latensified
latensified force-pushed the fix/openai-responses-pruned-reasoning branch from f0125df to b60fd8b Compare May 30, 2026 23:52
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 30, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed 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. labels May 30, 2026
@steipete steipete self-assigned this May 31, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete

Copy link
Copy Markdown
Contributor

@clawsweeper re-review

Maintainer fixup pushed in fe7c3ad.

What changed:

  • phase-tagged provider-owned assistant message ids are now omitted when paired reasoning is absent
  • phase metadata is still preserved
  • embedded and shared Responses conversion paths now share the same replay-id policy
  • added regressions for phase-tagged ids without reasoning

Verification:

  • node scripts/run-vitest.mjs src/agents/openai-responses.reasoning-replay.test.ts src/llm/providers/openai-responses-shared.test.ts
  • node scripts/run-tsgo.mjs -p tsconfig.core.json
  • node scripts/run-oxlint.mjs on touched files
  • git diff --check
  • live OpenAI Responses API proof with gpt-5.5: replayed message kept final_answer phase, omitted the provider message id, and the request completed
  • autoreview clean: no accepted/actionable findings

@clawsweeper

clawsweeper Bot commented May 31, 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.

Re-review progress:

@steipete

Copy link
Copy Markdown
Contributor

@clawsweeper re-review

Rebased maintainer fixup pushed in d6902ed.

Verification after rebase:

  • node scripts/run-vitest.mjs src/agents/openai-transport-stream.test.ts src/agents/openai-responses.reasoning-replay.test.ts src/llm/providers/openai-responses-shared.test.ts
  • node scripts/run-oxlint.mjs on touched files
  • git diff --check
  • live OpenAI Responses API proof with gpt-5.5: replayed message kept final_answer phase, omitted the provider message id, and the request completed
  • autoreview clean: no accepted/actionable findings

Local node scripts/run-tsgo.mjs -p tsconfig.core.json is blocked by an unrelated latest-main UI missing three type dependency; PR CI should be the source of truth for the branch type lanes.

@clawsweeper

clawsweeper Bot commented May 31, 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.

Re-review progress:

@steipete

Copy link
Copy Markdown
Contributor

Land-ready verification for d6902ed.

Local proof:

  • node scripts/run-vitest.mjs src/agents/openai-transport-stream.test.ts src/agents/openai-responses.reasoning-replay.test.ts src/llm/providers/openai-responses-shared.test.ts
  • node scripts/run-oxlint.mjs on touched files
  • git diff --check
  • live OpenAI Responses API proof with gpt-5.5: setup returned reasoning and message items, replay payload preserved final_answer phase, omitted the provider message id, and the live request completed
  • autoreview --mode branch --base origin/main: clean, no accepted/actionable findings

CI proof:

  • PR CI for d6902ed is clean with no pending checks.
  • ClawSweeper durable review updated to needs-human / maintainer review, with proof sufficient and no blocking finding.

Known proof gap:

  • No live deployed gateway restart was run; this change is covered at request payload construction plus live provider request level.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M 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.

4 participants