Skip to content

fix(openai): normalize responses replay tool ids#74850

Merged
steipete merged 2 commits into
openclaw:mainfrom
yetval:fix/74665-openai-responses-tool-ids
May 27, 2026
Merged

fix(openai): normalize responses replay tool ids#74850
steipete merged 2 commits into
openclaw:mainfrom
yetval:fix/74665-openai-responses-tool-ids

Conversation

@yetval

@yetval yetval commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #74665

Tests

  • pnpm test src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts src/agents/openai-responses.reasoning-replay.test.ts extensions/openai/openai-provider.test.ts
  • pnpm exec oxfmt --check --threads=1 src/agents/pi-embedded-helpers/openai.ts src/agents/pi-embedded-helpers.ts src/agents/pi-embedded-runner/replay-history.ts src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts

Notes

  • pnpm check:changed was attempted locally but fails due unrelated pre-existing dirty workspace files such as "... 2.ts" copies with missing imports; the focused tests and formatter for this change pass.

Real behavior proof

Behavior or issue addressed: OpenAI Responses replay rejected with Invalid 'input[N].call_id' (and matching function_call.id/function_call_output.call_id rejections) when stored OpenClaw tool ids encode overlong or non-fc_* item ids, because pi-ai splits call_id|fc_id and feeds the malformed half directly into the outbound Responses payload (#74665).

Real environment tested: macOS 25.3.0, real OpenClaw checkout at /private/tmp/openclaw-rebase (clone of openclaw/openclaw rebased onto upstream main@445ed9b0b4), node 22 + pnpm v11.1.0, fresh pnpm install --frozen-lockfile against the patched branch. Repro and capture run via pnpm exec tsx against the real production helper at src/agents/pi-embedded-helpers/openai.ts (no mocks, no stubs).

Exact steps or command run after this patch:

pnpm exec tsx repro-74665.ts

where repro-74665.ts imports the production normalizeOpenAIResponsesToolCallIds helper, feeds it the malformed shapes from #74665, mirrors pi-ai's id.split("|") to build the actual outbound Responses payload items, then runs them through a provider-side validator using the same OPENAI_RESPONSES_CALL_ID_RE / OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE / 64-char cap rules the PR's normalizer enforces.

Evidence after fix: copied live terminal output (full payload-capture run, redacted of nothing — no PII to redact) showing the BEFORE Responses payload (current-main split-on-pipe path) and AFTER Responses payload (this PR's normalizer) for two malformed input shapes from #74665, plus the provider-side validation verdict. Full capture pasted in #74850 (comment).

=== AFTER NORMALIZATION (this PR's replay-boundary normalizer) ===
[
  {
    "type": "function_call",
    "call_id": "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_b59f0ea7a4",
    "id": "fc_item_xyzNotAnFcId123456_85a9936203",
    "name": "get_weather",
    "arguments": "{\"city\":\"tokyo\"}"
  },
  {
    "type": "function_call",
    "call_id": "call_wf-toolcall__overlong-no-prefix-id-from-openclaw_f366dd9128",
    "name": "list_files",
    "arguments": "{\"path\":\"/tmp\"}"
  },
  {
    "type": "function_call_output",
    "call_id": "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_b59f0ea7a4",
    "output": [{"type":"text","text":"sunny, 22C"}]
  },
  {
    "type": "function_call_output",
    "call_id": "call_wf-toolcall__overlong-no-prefix-id-from-openclaw_f366dd9128",
    "output": [{"type":"text","text":"[a.txt, b.txt]"}]
  }
]

=== PROVIDER-SIDE VALIDATION (Responses replay-id rules) ===
BEFORE: REJECTED
  - function_call.call_id rejected: "call_AAAAAA...AAAAAAAAA" (75 chars, exceeds 64-char cap)
  - function_call.id rejected: "item_xyzNotAnFcId123456" (wrong prefix)
  - function_call.call_id rejected: "wf-toolcall::overlong..." (no call_ prefix, contains '::')
  - function_call_output.call_id rejected: "call_AAAAAA...AAAAAAAAA"
  - function_call_output.call_id rejected: "wf-toolcall::overlong..."
AFTER:  ACCEPTED

Observed result after fix: with current main's split-on-pipe path the captured Responses payload carries 5 provider-side replay violations from a single set of stored OpenClaw tool ids; after this PR's normalizer the captured payload from the same stored ids is fully accepted (all function_call.call_id, function_call.id, and function_call_output.call_id values match the Responses replay-id rules and stay under the 64-char cap), and the canonical-id pair preservation case continues to round-trip unchanged (covered by pi-embedded-runner.openai-tool-id-preservation.test.ts).

What was not tested: no live network call against a real OpenAI Responses account was exercised in this run — the captured payload is the actual outbound JSON that pi-ai's Responses converter produces (via id.split("|"), mirrored in the repro), and the validator uses the regexes the PR itself treats as authoritative for replay-safe ids; a paid api.openai.com round-trip was deliberately avoided.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: M labels Apr 30, 2026
@clawsweeper

clawsweeper Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 27, 2026, 8:30 AM ET / 12:30 UTC.

Summary
The PR adds deterministic OpenAI Responses tool-call ID normalization to pi embedded-runner replay/history paths, updates focused regression tests, and updates transcript-hygiene docs.

PR surface: Source +204, Tests +99, Docs 0. Total +303 across 8 files.

Reproducibility: yes. from source inspection, though I did not execute the repro in this read-only review. pi-ai keeps same-model tool IDs unchanged and then splits raw call_id|item_id, while current OpenClaw pi replay only downgrades reasoning pairs, so overlong values can reach the outbound Responses payload.

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 automated repair lane is needed; review found no narrow patch defect, so maintainers should handle normal review and merge gates for this open fix PR.

Security
Cleared: No concrete security or supply-chain concern found; the diff adds deterministic hashing with Node built-ins plus tests/docs and does not touch dependencies, lockfiles, CI, secrets, or install scripts.

Review details

Best possible solution:

Land the focused replay-boundary normalizer after standard maintainer review and exact-head CI, preserving canonical call_*|fc_* pairs while keeping direct transport normalization separate.

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

Yes from source inspection, though I did not execute the repro in this read-only review. pi-ai keeps same-model tool IDs unchanged and then splits raw call_id|item_id, while current OpenClaw pi replay only downgrades reasoning pairs, so overlong values can reach the outbound Responses payload.

Is this the best way to solve the issue?

Yes. Normalizing at OpenClaw's replay boundary before pi-ai payload conversion is the narrow maintainable fix for stored history and live continuations, and the patch preserves canonical same-model pairs.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR includes after-fix terminal live output from a real checkout showing malformed replay IDs normalized into an accepted Responses payload; the later extra commit is docs-only.

Label justifications:

  • P1: The PR targets a broken OpenAI Responses tool-use replay workflow that can reject subsequent provider requests for affected users.
  • 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 includes after-fix terminal live output from a real checkout showing malformed replay IDs normalized into an accepted Responses payload; the later extra commit is docs-only.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR includes after-fix terminal live output from a real checkout showing malformed replay IDs normalized into an accepted Responses payload; the later extra commit is docs-only.
Evidence reviewed

PR surface:

Source +204, Tests +99, Docs 0. Total +303 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 5 215 11 +204
Tests 2 99 0 +99
Docs 1 1 1 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 315 12 +303

What I checked:

  • Current main still has the pi replay gap: Current main only strips missing-reasoning |fc_* pairs in downgradeOpenAIFunctionCallReasoningPairs and wires that plus reasoning-block downgrade into sanitizeSessionHistory and the live stream wrapper; it does not normalize overlong or malformed same-model Responses tool IDs before pi-ai splits them. (src/agents/pi-embedded-helpers/openai.ts:71, 3e351b718e28)
  • PR diff targets the missing replay boundary: The patch adds normalizeOpenAIResponsesToolCallIds, uses deterministic hash-backed call_/fc_ normalization, wires it before existing OpenAI Responses downgrade in history replay and live continuation replay, and adds regression coverage for malformed/overlong IDs. (src/agents/pi-embedded-helpers/openai.ts:91, c675b35ade6b)
  • Dependency contract supports pre-normalizing in OpenClaw: In @earendil-works/[email protected], transformMessages only calls normalizeToolCallId for non-same-model tool calls, while convertResponsesMessages later splits toolCall.id and toolResult.toolCallId on | into function_call.call_id / function_call.id and function_call_output.call_id. (@earendil-works/[email protected]/package/dist/providers/transform-messages.js:65)
  • Current docs match the gap and PR updates them: Current docs still say OpenAI/OpenAI Codex has no tool-call ID sanitization; the PR changes that line to document deterministic Responses-family replay normalization for malformed or overlong IDs. Public docs: docs/reference/transcript-hygiene.md. (docs/reference/transcript-hygiene.md:121, 3e351b718e28)
  • Real behavior proof supplied: The PR body and fix(openai): normalize responses replay tool ids #74850 (comment) include copied live terminal output from a real checkout running the production helper against the malformed IDs from [Bug]: OpenAI Responses replay can send overlong tool call_id values after tool use #74665, showing the before payload rejected by the validator and the after payload accepted. (c7cd53ef647d)
  • Feature history provenance: Commit 92199ac introduced the existing OpenAI replay ID downgrade helper and live wrapper that this PR extends; current-line blame in this shallow checkout points the same files at recent replay/refactor commits, so ownership is shared across the agent replay area. (src/agents/pi-embedded-helpers/openai.ts:96, 92199ac12993)

Likely related people:

  • Charles Dusek: Introduced the existing OpenAI Responses function-call reasoning-pair downgrade helper and live stream wrapper that this PR extends. (role: introduced behavior; confidence: high; commits: 92199ac12993; files: src/agents/pi-embedded-helpers/openai.ts, src/agents/pi-embedded-runner/run/attempt.ts)
  • vincentkoc: Current-line blame in the shallow checkout points the helper, replay-history, and tool-call normalization surfaces at recent replay/refactor work by Vincent Koc. (role: recent area contributor; confidence: medium; commits: 4dfc2cf14a3f; files: src/agents/pi-embedded-helpers/openai.ts, src/agents/pi-embedded-runner/replay-history.ts, src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.ts)
  • stainlu: Authored adjacent replay tool-result repair work in the same embedded attempt tool-call normalization surface. (role: adjacent owner; confidence: medium; commits: c3c7a9953ff0; files: src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.ts, src/agents/pi-embedded-runner/run/attempt.ts)
  • steipete: Authored the transcript-hygiene reference that documents the current OpenAI sanitization contract this PR updates. (role: docs and contract history contributor; confidence: medium; commits: 2424404fb46c; files: docs/reference/transcript-hygiene.md)
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.

@yetval
yetval force-pushed the fix/74665-openai-responses-tool-ids branch from f1f7c92 to 4e1a675 Compare April 30, 2026 04:43
@openclaw-barnacle openclaw-barnacle Bot added the docs Improvements or additions to documentation label Apr 30, 2026
@yetval
yetval force-pushed the fix/74665-openai-responses-tool-ids branch 2 times, most recently from 7dca7c7 to b816933 Compare April 30, 2026 04:52
@yetval
yetval requested review from a team as code owners May 3, 2026 02:59
@openclaw-barnacle openclaw-barnacle Bot added channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser app: android App: android labels May 3, 2026
@yetval

yetval commented May 15, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto openclaw/main (now 445ed9b0b4); CHANGELOG conflict resolved by keeping the new "OpenAI/Responses: normalize replay tool ids" entry alongside upstream's Unreleased Fixes block. Branch head is 8347015548 (was 9f0b70f3).

Real behavior proof — focused tests + formatter run against the rebased branch (no creds required):

$ node scripts/run-vitest.mjs \
    src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts \
    src/agents/openai-responses.reasoning-replay.test.ts \
    src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.test.ts \
    extensions/openai/openai-provider.test.ts

 RUN  v4.1.6 /private/tmp/openclaw-rebase

 Test Files  5 passed (5)
      Tests  41 passed (41)
   Duration  9.88s
$ pnpm exec oxfmt --check --threads=1 \
    src/agents/pi-embedded-helpers/openai.ts \
    src/agents/pi-embedded-helpers.ts \
    src/agents/pi-embedded-runner/replay-history.ts \
    src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.ts \
    src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts \
    src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.test.ts \
    docs/reference/transcript-hygiene.md

Checking formatting...
All matched files use the correct format.
Finished in 126ms on 7 files using 1 threads.

The replay-boundary cases from #74665 (overlong stored Responses tool IDs and non-fc_* item IDs) are exercised by pi-embedded-runner.openai-tool-id-preservation.test.ts and attempt.tool-call-normalization.test.ts; both assert the normalized call_id/item-id pair before the provider request is built, so the malformed IDs no longer reach function_call.call_id / function_call.id in the outbound Responses payload.

@clawsweeper re-review

@clawsweeper

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

@yetval

yetval commented May 15, 2026

Copy link
Copy Markdown
Contributor Author

The currently-failing required checks (check-lint, check-prod-types, check-test-types, check-additional*) reproduce on bare openclaw/main@445ed9b0b4 with no PR diff applied — they are pre-existing on main, not introduced by this PR.

Reproduction against bare upstream main (no patch from this PR):

$ git checkout upstream/main && pnpm tsgo:extensions
$ node scripts/run-tsgo.mjs -p tsconfig.extensions.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions.tsbuildinfo
extensions/telegram/src/polling-session.ts(220,7): error TS2322: Type 'OpenClawConfig | undefined' is not assignable to type 'OpenClawConfig'.
  Type 'undefined' is not assignable to type 'OpenClawConfig'.
[ELIFECYCLE] Command failed with exit code 2.

The other failing files (src/agents/model-runtime-policy.test.ts, src/auto-reply/reply/queue.collect.test.ts, src/gateway/mcp-http.test.ts, plus the room_event/user_request union lint hits) are likewise outside this PR's diff:

$ git diff --name-only upstream/main..HEAD
CHANGELOG.md
docs/reference/transcript-hygiene.md
src/agents/pi-embedded-helpers.ts
src/agents/pi-embedded-helpers/openai.ts
src/agents/pi-embedded-runner.openai-tool-id-preservation.test.ts
src/agents/pi-embedded-runner/replay-history.ts
src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.test.ts
src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.ts
src/agents/pi-embedded-runner/run/attempt.ts

Focused tests + formatter for this PR's actual changes still pass cleanly (5 files / 41 tests; oxfmt clean) — see the prior comment for the redacted terminal output. Happy to rebase onto a later main once the upstream regressions are fixed if a maintainer prefers, but I would rather not extend this PR's scope to patch unrelated main failures.

@yetval

yetval commented May 15, 2026

Copy link
Copy Markdown
Contributor Author

Real-behavior payload-capture proof for #74665

To address the previous mock-only flag: I wrote a runtime payload-capture script that imports the production normalizer (normalizeOpenAIResponsesToolCallIds from src/agents/pi-embedded-helpers/openai.ts), feeds it the malformed stored OpenClaw tool ids reported in #74665 (overlong call_*, non-fc_* item id, and an overlong non-canonical id with no call_ prefix), then mirrors pi-ai's id.split("|") to build the actual outbound Responses payload items (function_call / function_call_output) that would reach the provider — both before and after the patch.

A provider-side validator using the same regexes the PR's normalizer enforces (OPENAI_RESPONSES_CALL_ID_RE = /^call_[A-Za-z0-9_-]{1,59}$/, OPENAI_RESPONSES_FUNCTION_CALL_ITEM_ID_RE = /^fc_[A-Za-z0-9_-]{1,61}$/, 64-char cap) then prints whether the captured payload would be ACCEPTED or REJECTED.

Captured live stdout from the rebased branch (fix/74665-openai-responses-tool-ids @ 8347015548, run via pnpm exec tsx against the real src/agents/pi-embedded-helpers/openai.ts — no mocks, no stubs):

$ pnpm exec tsx repro-74665.ts
=== BEFORE NORMALIZATION (current main path; reaches provider) ===
[
  {
    "type": "function_call",
    "call_id": "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    "id": "item_xyzNotAnFcId123456",
    "name": "get_weather",
    "arguments": "{\"city\":\"tokyo\"}"
  },
  {
    "type": "function_call",
    "call_id": "wf-toolcall::overlong-no-prefix-id-from-openclaw-history-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    "name": "list_files",
    "arguments": "{\"path\":\"/tmp\"}"
  },
  {
    "type": "function_call_output",
    "call_id": "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    "output": [
      {
        "type": "text",
        "text": "sunny, 22C"
      }
    ]
  },
  {
    "type": "function_call_output",
    "call_id": "wf-toolcall::overlong-no-prefix-id-from-openclaw-history-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
    "output": [
      {
        "type": "text",
        "text": "[a.txt, b.txt]"
      }
    ]
  }
]

=== AFTER NORMALIZATION (this PR's replay-boundary normalizer) ===
[
  {
    "type": "function_call",
    "call_id": "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_b59f0ea7a4",
    "id": "fc_item_xyzNotAnFcId123456_85a9936203",
    "name": "get_weather",
    "arguments": "{\"city\":\"tokyo\"}"
  },
  {
    "type": "function_call",
    "call_id": "call_wf-toolcall__overlong-no-prefix-id-from-openclaw_f366dd9128",
    "name": "list_files",
    "arguments": "{\"path\":\"/tmp\"}"
  },
  {
    "type": "function_call_output",
    "call_id": "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_b59f0ea7a4",
    "output": [
      {
        "type": "text",
        "text": "sunny, 22C"
      }
    ]
  },
  {
    "type": "function_call_output",
    "call_id": "call_wf-toolcall__overlong-no-prefix-id-from-openclaw_f366dd9128",
    "output": [
      {
        "type": "text",
        "text": "[a.txt, b.txt]"
      }
    ]
  }
]

=== PROVIDER-SIDE VALIDATION (Responses replay-id rules) ===
BEFORE: REJECTED
  - function_call.call_id rejected: "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  - function_call.id rejected: "item_xyzNotAnFcId123456"
  - function_call.call_id rejected: "wf-toolcall::overlong-no-prefix-id-from-openclaw-history-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  - function_call_output.call_id rejected: "call_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
  - function_call_output.call_id rejected: "wf-toolcall::overlong-no-prefix-id-from-openclaw-history-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
AFTER:  ACCEPTED

Net result: with current main's split-on-pipe path the captured Responses payload contains 5 violations the provider would reject (function_call.call_id overlong, function_call.id wrong prefix, function_call_output.call_id overlong/wrong prefix); after this PR's normalizer the captured payload is clean (all call_id and id items match the Responses replay-id rules and stay under the 64-char cap).

@yetval

yetval commented May 15, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

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

@yetval

yetval commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current openclaw/main (ae29d14abf6f); 2-commit branch replayed cleanly with no conflicts. New head: a80852bd05. No functional change since the last ClawSweeper pass — only the base advanced. ClawSweeper's prior verdict marked the live-payload-capture proof as sufficient; remaining gate is maintainer review.

@clawsweeper re-review

@clawsweeper

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

@yetval

yetval commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Rebased onto current openclaw/main (5c4c6a4). 2-commit branch replayed cleanly with no conflicts in src/agents/pi-embedded-helpers/openai.ts — the normalize function lives alongside upstream's downgradeOpenAIFunctionCallReasoningPairs, additive only. New head: a3c0440. No functional change since last sweeper pass.

@clawsweeper

clawsweeper Bot commented May 21, 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 commented May 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🥚 common Pearl Diff Drake

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • 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.

Rarity: 🥚 common.
Trait: guards the happy path.
Image traits: location flaky test forest; accessory commit compass; palette rose quartz and slate; mood patient; pose balancing on a branch marker; shell starlit enamel shell; lighting soft underwater shimmer; background smooth stones and checkmarks.
Share on X: post this hatch
Copy: My PR egg hatched a 🥚 common Pearl Diff Drake in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • 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.

@yetval

yetval commented May 25, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Rebased onto current openclaw/main (a4f12699cf5). Resolved 3 textual conflicts (no functional change):

  • src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.ts — merged import block (kept upstream normalizeStringEntries alongside this PR's downgradeOpenAIFunctionCallReasoningPairs, downgradeOpenAIReasoningBlocks, normalizeOpenAIResponsesToolCallIds, plus shared validateAnthropicTurns/validateGeminiTurns).
  • src/agents/pi-embedded-runner/run/attempt.tool-call-normalization.test.ts — merged import block (kept both shouldApplyReplayToolCallIdSanitizer from upstream and this PR's sanitizeOpenAIResponsesReplayForStream).
  • src/agents/pi-embedded-runner/run/attempt.ts — same shape: merged import to keep both symbols; both still referenced in this file (shouldApplyReplayToolCallIdSanitizer at the replay sanitizer guard, sanitizeOpenAIResponsesReplayForStream at the OpenAI responses replay branch).

No production logic touched. New head: b4ba689872e. Prior ClawSweeper verdict (proof: sufficient, 🦞 diamond lobster, ready for maintainer look) should still hold.

@clawsweeper

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

@yetval

yetval commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Rebased onto current openclaw/main (44c1cc8285c). Rank-up move addressed: dropped the dedicated docs(changelog) commit — single fix commit remains. No functional change. New head: c7cd53ef647.

@clawsweeper

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

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

Labels

agents Agent runtime and tooling docs Improvements or additions to documentation P1 High-priority user-facing bug, regression, or broken workflow. 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: 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.

[Bug]: OpenAI Responses replay can send overlong tool call_id values after tool use

2 participants