Skip to content

fix(codex): avoid broken emoji in dynamic tool timeout logs#102509

Merged
steipete merged 3 commits into
openclaw:mainfrom
zhangguiping-xydt:fix/problem-codex-dynamic-tool-log-utf16
Jul 9, 2026
Merged

fix(codex): avoid broken emoji in dynamic tool timeout logs#102509
steipete merged 3 commits into
openclaw:mainfrom
zhangguiping-xydt:fix/problem-codex-dynamic-tool-log-utf16

Conversation

@zhangguiping-xydt

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where Codex dynamic tool timeout logs could contain malformed emoji or other split surrogate-pair text when a long dynamic tool log field crosses the truncation boundary.

Why This Change Was Made

Codex dynamic tool timeout diagnostics now use the existing UTF-16-safe truncation helper for normalized log fields while preserving the current 160-character cap and ... marker. This is limited to timeout diagnostic/log formatting and does not change tool execution, timeout behavior, protocol payloads, or persisted data.

User Impact

Operators and developers inspecting Codex dynamic tool timeout output can now expect valid UTF-16 snippets for long tool/process fields, including emoji-containing user or tool text, instead of broken surrogate characters at the truncation edge.

Evidence

Pre-submit freshness and competition check:

  • Refreshed origin/main before implementation; extensions/codex/src/app-server/dynamic-tool-execution.ts still used raw normalized.slice(0, LOG_FIELD_MAX_LENGTH - 3).
  • Enumerated current open PR file lists before implementation; no open PR touched extensions/codex/src/app-server/dynamic-tool-execution.ts.

Issue-specific runtime proof:

  • Directly executed the Codex app-server dynamic tool timeout handler with long emoji-containing process action/session fields and observed UTF-16-safe truncated fields.
{
  "success": false,
  "processAction": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...",
  "processSessionId": "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss...",
  "containsSplitSurrogate": false
}

Regression test:

node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-codex-app-server-tools.config.ts codex/src/app-server/dynamic-tool-execution.test.ts

Test Files  1 passed (1)
Tests       26 passed (26)

Additional checks:

pnpm exec oxfmt --check --threads=1 extensions/codex/src/app-server/dynamic-tool-execution.ts extensions/codex/src/app-server/dynamic-tool-execution.test.ts

All matched files use the correct format.
pnpm exec oxlint extensions/codex/src/app-server/dynamic-tool-execution.ts extensions/codex/src/app-server/dynamic-tool-execution.test.ts

Validation result: pass, exit_code=0
git diff --check

Validation result: pass, exit_code=0

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 9, 2026, 3:49 AM ET / 07:49 UTC.

Summary
This PR changes Codex dynamic tool timeout log formatting to use truncateUtf16Safe for normalized tool/process fields and adds a regression test for emoji at the truncation boundary.

PR surface: Source +1, Tests +39. Total +40 across 2 files.

Reproducibility: yes. source-level reproduction is high confidence: current main uses raw UTF-16 slice at the timeout log truncation boundary, so an emoji beginning at that boundary can produce a lone surrogate. I did not execute the runtime path locally in this read-only review, but the PR body includes direct handler output showing containsSplitSurrogate: false after the change.

Review metrics: none identified.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
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:

  • Resolve or rerun the failing check-test-types job once logs are available.

Risk before merge

  • [P1] At review time, check-test-types was failed and some CI shards were still in progress; because logs were unavailable while the run was active, this needs ordinary CI follow-up before merge.

Maintainer options:

  1. Decide the mitigation before merge
    Land this narrow helper reuse once required CI is green or the failing type-check job is understood, keeping the fix limited to timeout diagnostics.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • No ClawSweeper repair lane is needed because source review found no patch defect; the remaining action is ordinary CI completion or failing-check follow-up before maintainer merge.

Security
Cleared: The diff only reuses an existing text helper and adds a focused test, with no dependency, workflow, lockfile, secret, or supply-chain surface change.

Review details

Best possible solution:

Land this narrow helper reuse once required CI is green or the failing type-check job is understood, keeping the fix limited to timeout diagnostics.

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

Yes, source-level reproduction is high confidence: current main uses raw UTF-16 slice at the timeout log truncation boundary, so an emoji beginning at that boundary can produce a lone surrogate. I did not execute the runtime path locally in this read-only review, but the PR body includes direct handler output showing containsSplitSurrogate: false after the change.

Is this the best way to solve the issue?

Yes, this is the best code shape for the reported bug: normalize once at normalizeLogField and reuse the existing plugin SDK UTF-16-safe truncation helper. Duplicating surrogate checks locally would add a second text-boundary implementation without improving ownership.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 51bb5f684778.

Label changes

Label changes:

  • add P3: This is a small diagnostic-log formatting bug fix with low runtime blast radius and no user workflow blockage.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output from directly executing the dynamic tool timeout handler with emoji-containing fields and observing containsSplitSurrogate: false, which is sufficient real behavior proof for this log-formatting change.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • add 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 output from directly executing the dynamic tool timeout handler with emoji-containing fields and observing containsSplitSurrogate: false, which is sufficient real behavior proof for this log-formatting change.

Label justifications:

  • P3: This is a small diagnostic-log formatting bug fix with low runtime blast radius and no user workflow blockage.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit 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 output from directly executing the dynamic tool timeout handler with emoji-containing fields and observing containsSplitSurrogate: false, which is sufficient real behavior proof for this log-formatting change.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix terminal output from directly executing the dynamic tool timeout handler with emoji-containing fields and observing containsSplitSurrogate: false, which is sufficient real behavior proof for this log-formatting change.
Evidence reviewed

PR surface:

Source +1, Tests +39. Total +40 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 1 +1
Tests 1 39 0 +39
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 41 1 +40

What I checked:

Likely related people:

  • steipete: GitHub history shows steipete introduced the split Codex app-server dynamic-tool execution module and appears repeatedly in recent Codex app-server/runtime history. (role: introduced behavior and recent area contributor; confidence: high; commits: a4c2e7f5cf1b, 7139f473332f, f53346944db0; files: extensions/codex/src/app-server/dynamic-tool-execution.ts, extensions/codex/src/app-server/run-attempt.ts, extensions/codex/src/app-server/side-question.ts)
  • cxbAsDev: The merged timeoutSeconds fix recently changed the same dynamic-tool timeout resolver and tests, making this account a strong routing candidate for timeout-path review context. (role: recent adjacent contributor of dynamic-tool timeout behavior; confidence: medium; commits: 68487e4c1e34; files: extensions/codex/src/app-server/dynamic-tool-execution.ts, extensions/codex/src/app-server/dynamic-tool-execution.test.ts)
  • obviyus: Recent history on src/plugin-sdk/text-utility-runtime.ts involved the public plugin SDK utility barrel that this PR imports from, though the helper itself predates this PR. (role: adjacent SDK surface contributor; confidence: medium; commits: d498b1cce49c, 210877a73e25; files: src/plugin-sdk/text-utility-runtime.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 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. P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. labels Jul 9, 2026
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Land-ready maintainer verification at exact head dd6de265b6292010a7f2c96387481adfce457a37:

  • The timeout path now truncates dynamic-tool log fields through the public plugin-SDK UTF-16 helper while preserving the existing 160-code-unit limit and ellipsis.
  • Focused dynamic-tool execution suite: 26 passed.
  • Fresh autoreview: clean (0.99).
  • Exact-head hosted code CI/Testbox gates: passed. The unrelated label maintenance job does not exercise this code.
  • Direct Codex contract inspection: codex-rs/app-server-protocol/src/protocol/common.rs:1486-1490, codex-rs/app-server-protocol/src/protocol/v2/item.rs:1541-1569, codex-rs/app-server/src/bespoke_event_handling.rs:825-863, and codex-rs/app-server/src/dynamic_tools.rs:16-89 confirm JSON dynamic-tool arguments flow through item/tool/call without a narrower character contract.

The timer-driven regression proves process action/session metadata and returned timeout text contain no dangling surrogate.

@steipete
steipete merged commit b23fdcf into openclaw:main Jul 9, 2026
90 of 91 checks passed
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…#102509)

* fix(codex): keep dynamic tool log fields UTF-16 safe

* test(codex): narrow dynamic tool response item

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: codex P3 Low-priority cleanup, docs, polish, ergonomics, or speculative work. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS 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.

2 participants