Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
277
docs/reference/transcript-hygiene.md
Normal file
277
docs/reference/transcript-hygiene.md
Normal file
@@ -0,0 +1,277 @@
|
||||
---
|
||||
summary: "Reference: provider-specific transcript sanitization and repair rules"
|
||||
read_when:
|
||||
- You are debugging provider request rejections tied to transcript shape
|
||||
- You are changing transcript sanitization or tool-call repair logic
|
||||
- You are investigating tool-call id mismatches across providers
|
||||
title: "Transcript hygiene"
|
||||
---
|
||||
|
||||
OpenClaw applies **provider-specific fixes** to transcripts before a run
|
||||
(building model context). Most of these are **in-memory** adjustments used to
|
||||
satisfy strict provider requirements. A separate session-file repair pass may
|
||||
also rewrite stored JSONL before the session is loaded, but only for
|
||||
malformed lines or persisted turns that are invalid durable records.
|
||||
Delivered assistant replies are preserved on disk; provider-specific
|
||||
assistant-prefill stripping happens only while constructing outbound
|
||||
payloads.
|
||||
|
||||
When a repair occurs, the original file is written to a transient
|
||||
`*.bak-<pid>-<ts>` sibling before the atomic replace, then removed once the
|
||||
replace succeeds. The backup is retained only if cleanup itself fails, in
|
||||
which case the path is reported back.
|
||||
|
||||
Scope includes:
|
||||
|
||||
- Runtime-only prompt context staying out of user-visible transcript turns
|
||||
- Tool call id sanitization
|
||||
- Tool call input validation
|
||||
- Tool result pairing repair
|
||||
- Turn validation / ordering
|
||||
- Thought signature cleanup
|
||||
- Thinking signature cleanup
|
||||
- Image payload sanitization
|
||||
- Blank text-block cleanup before provider replay
|
||||
- Incomplete reasoning-only length-turn cleanup before provider replay
|
||||
- User-input provenance tagging (for inter-session routed prompts)
|
||||
- Empty assistant error-turn repair for Bedrock Converse replay
|
||||
|
||||
If you need transcript storage details, see
|
||||
[Session management deep dive](/reference/session-management-compaction).
|
||||
|
||||
---
|
||||
|
||||
## Global rule: runtime context is not user transcript
|
||||
|
||||
Runtime/system context can be added to the model prompt for a turn, but it is
|
||||
not end-user-authored content. OpenClaw keeps a separate transcript-facing
|
||||
prompt body for Gateway replies, queued followups, ACP, CLI, and embedded
|
||||
OpenClaw runs. Stored visible user turns use that transcript body instead of
|
||||
the runtime-enriched prompt.
|
||||
|
||||
For legacy sessions that already persisted runtime wrappers, Gateway history
|
||||
surfaces apply a display projection before returning messages to WebChat,
|
||||
TUI, REST, or SSE clients.
|
||||
|
||||
---
|
||||
|
||||
## Where this runs
|
||||
|
||||
All transcript hygiene is centralized in the embedded runner:
|
||||
|
||||
- Policy selection: `src/agents/transcript-policy.ts`
|
||||
(`resolveTranscriptPolicy`, keyed on `provider`, `modelApi`, and `modelId`)
|
||||
- Sanitization/repair application: `sanitizeSessionHistory` in
|
||||
`src/agents/embedded-agent-runner/replay-history.ts`
|
||||
|
||||
Separate from transcript hygiene, session files are repaired (if needed)
|
||||
before load:
|
||||
|
||||
- `repairSessionFileIfNeeded` in `src/agents/session-file-repair.ts`
|
||||
- Called from `src/agents/embedded-agent-runner/run/attempt.ts` and
|
||||
`src/agents/embedded-agent-runner/compact.ts`
|
||||
|
||||
---
|
||||
|
||||
## Global rule: image sanitization
|
||||
|
||||
Image payloads are always sanitized to prevent provider-side rejection due to
|
||||
size limits (downscale/recompress oversized base64 images). This also helps
|
||||
control image-driven token pressure for vision-capable models: lower max
|
||||
dimensions reduce token usage, higher dimensions preserve detail.
|
||||
|
||||
Implementation:
|
||||
|
||||
- `sanitizeSessionMessagesImages` in
|
||||
`src/agents/embedded-agent-helpers/images.ts`
|
||||
- `sanitizeContentBlocksImages` in `src/agents/tool-images.ts`
|
||||
- Max image side is configurable via `agents.defaults.imageMaxDimensionPx`
|
||||
(default: `1200`)
|
||||
- Blank text blocks are removed while this pass walks replay content.
|
||||
Assistant turns that become empty are dropped from the replay copy; user
|
||||
and tool-result turns that become empty receive a non-empty
|
||||
omitted-content placeholder.
|
||||
|
||||
---
|
||||
|
||||
## Global rule: malformed tool calls
|
||||
|
||||
Assistant tool-call blocks missing both `input` and `arguments` are dropped
|
||||
before model context is built. This prevents provider rejections from
|
||||
partially persisted tool calls (for example, after a rate limit failure).
|
||||
|
||||
Implementation:
|
||||
|
||||
- `sanitizeToolCallInputs` in `src/agents/session-transcript-repair.ts`
|
||||
- Applied in `sanitizeSessionHistory`
|
||||
(`src/agents/embedded-agent-runner/replay-history.ts`)
|
||||
|
||||
---
|
||||
|
||||
## Global rule: incomplete reasoning-only turns
|
||||
|
||||
Assistant turns that hit the provider output limit with only thinking or
|
||||
redacted-thinking content are omitted from the in-memory replay copy. Such
|
||||
turns contain incomplete provider state and may carry a partial thinking
|
||||
signature.
|
||||
|
||||
Empty length turns remain unchanged, as do length turns with visible text,
|
||||
tool calls, or unknown content blocks. Stored transcripts are not rewritten.
|
||||
|
||||
Implementation: `normalizeAssistantReplayContent` in
|
||||
`src/agents/embedded-agent-runner/replay-history.ts`
|
||||
|
||||
---
|
||||
|
||||
## Global rule: inter-session input provenance
|
||||
|
||||
When an agent sends a prompt into another session via `sessions_send`
|
||||
(including agent-to-agent reply/announce steps), OpenClaw persists the
|
||||
created user turn with `message.provenance.kind = "inter_session"`.
|
||||
|
||||
OpenClaw also prepends a same-turn `[Inter-session message] ... isUser=false`
|
||||
marker before the routed prompt text so the active model call can
|
||||
distinguish foreign session output from external end-user instructions. This
|
||||
marker includes the source session, channel, and tool when available. The
|
||||
transcript still uses `role: "user"` for provider compatibility, but the
|
||||
visible text and provenance metadata both mark the turn as inter-session
|
||||
data.
|
||||
|
||||
During context rebuild, OpenClaw applies the same marker to older persisted
|
||||
inter-session user turns that only have provenance metadata.
|
||||
|
||||
---
|
||||
|
||||
## Provider matrix (current behavior)
|
||||
|
||||
**OpenAI / OpenAI Codex**
|
||||
|
||||
- Image sanitization only.
|
||||
- Drop orphaned reasoning signatures (standalone reasoning items without a
|
||||
following content block) for OpenAI Responses/Codex transcripts, and drop
|
||||
replayable OpenAI reasoning after a model route switch.
|
||||
- Preserve replayable OpenAI Responses reasoning item payloads, including
|
||||
encrypted empty-summary items, so manual/WebSocket replay keeps required
|
||||
`rs_*` state paired with assistant output items.
|
||||
- Native ChatGPT Codex Responses follows Codex wire parity by replaying
|
||||
prior Responses reasoning/message/function payloads without prior item
|
||||
IDs while preserving session `prompt_cache_key`.
|
||||
- OpenAI Responses-family replay preserves canonical `call_*|fc_*`
|
||||
same-model reasoning pairs, but deterministically normalizes malformed or
|
||||
overlong `call_id`/function-call item ids before pi-ai payload conversion.
|
||||
- Tool result pairing repair may move real matched outputs and synthesize
|
||||
Codex-style `aborted` outputs for missing tool calls.
|
||||
- No turn validation or reordering; no thought signature stripping.
|
||||
|
||||
**OpenAI-compatible Chat Completions**
|
||||
|
||||
- Historical assistant thinking/reasoning blocks are stripped before replay
|
||||
so local and proxy-style OpenAI-compatible servers do not receive
|
||||
prior-turn reasoning fields such as `reasoning` or `reasoning_content`.
|
||||
- Current same-turn tool-call continuations keep the assistant reasoning
|
||||
block attached to the tool call until the tool result has been replayed.
|
||||
- Custom/self-hosted model entries with `reasoning: true` preserve replayed
|
||||
reasoning metadata.
|
||||
- Provider-owned exceptions can opt out when their wire protocol requires
|
||||
replayed reasoning metadata.
|
||||
|
||||
**Google (Generative AI / Gemini CLI / Antigravity)**
|
||||
|
||||
- Tool call id sanitization: strict alphanumeric.
|
||||
- Tool result pairing repair and synthetic tool results.
|
||||
- Turn validation (Gemini-style turn alternation).
|
||||
- Google turn ordering fixup (prepend a tiny user bootstrap if history
|
||||
starts with assistant).
|
||||
- Antigravity Claude: normalize thinking signatures; drop unsigned thinking
|
||||
blocks.
|
||||
|
||||
**Anthropic / Minimax (Anthropic-compatible)**
|
||||
|
||||
- Tool result pairing repair and synthetic tool results.
|
||||
- Turn validation (merge consecutive user turns to satisfy strict
|
||||
alternation).
|
||||
- Trailing assistant prefill turns are stripped from outgoing Anthropic
|
||||
Messages payloads when thinking is enabled, including Cloudflare AI
|
||||
Gateway routes.
|
||||
- Pre-compaction assistant thinking signatures are stripped before provider
|
||||
replay when a session has been compacted. Thinking signatures are
|
||||
cryptographically bound to the conversation prefix at generation time;
|
||||
after compaction the prefix changes (summarized content replaces the
|
||||
original), so replaying the original signatures causes Anthropic to
|
||||
reject the request with "Invalid signature in thinking block". The
|
||||
thinking text is preserved as an unsigned block and then handled by the
|
||||
rule below.
|
||||
- Thinking blocks with missing, empty, or blank replay signatures are
|
||||
stripped before provider conversion. If that empties an assistant turn,
|
||||
OpenClaw keeps turn shape with non-empty omitted-reasoning text.
|
||||
- Older thinking-only assistant turns that must be stripped are replaced
|
||||
with non-empty omitted-reasoning text so provider adapters do not drop
|
||||
the replay turn.
|
||||
|
||||
**Amazon Bedrock (Converse API)**
|
||||
|
||||
- Empty assistant stream-error turns are repaired to a non-empty fallback
|
||||
text block before replay. Bedrock Converse rejects assistant messages
|
||||
with `content: []`, so persisted assistant turns with `stopReason:
|
||||
"error"` and empty content are also repaired on disk before load.
|
||||
- Assistant stream-error turns with only blank text blocks are dropped from
|
||||
the in-memory replay copy instead of replaying an invalid blank block.
|
||||
- Pre-compaction assistant thinking signatures are stripped before Converse
|
||||
replay when a session has been compacted, for the same reason as
|
||||
Anthropic above.
|
||||
- Claude thinking blocks with missing, empty, or blank replay signatures
|
||||
are stripped before Converse replay. If that empties an assistant turn,
|
||||
OpenClaw keeps turn shape with non-empty omitted-reasoning text.
|
||||
- Older thinking-only assistant turns that must be stripped are replaced
|
||||
with non-empty omitted-reasoning text so the Converse replay keeps
|
||||
strict turn shape.
|
||||
- Replay filters OpenClaw delivery-mirror and gateway-injected assistant
|
||||
turns.
|
||||
- Image sanitization applies through the global rule.
|
||||
|
||||
**Mistral (including model-id based detection)**
|
||||
|
||||
- Tool call id sanitization: strict9 (alphanumeric, length 9).
|
||||
|
||||
**OpenRouter Gemini**
|
||||
|
||||
- Thought signature cleanup: strip non-base64 `thought_signature` values
|
||||
(keep base64).
|
||||
|
||||
**OpenRouter Anthropic**
|
||||
|
||||
- Trailing assistant prefill turns are stripped from verified OpenRouter
|
||||
OpenAI-compatible Anthropic model payloads when reasoning is enabled,
|
||||
matching direct Anthropic and Cloudflare Anthropic replay behavior.
|
||||
|
||||
**Everything else**
|
||||
|
||||
- Image sanitization only.
|
||||
|
||||
---
|
||||
|
||||
## Historical behavior (pre-2026.1.22)
|
||||
|
||||
Before the 2026.1.22 release, OpenClaw applied multiple layers of transcript
|
||||
hygiene:
|
||||
|
||||
- A **transcript-sanitize extension** ran on every context build and could:
|
||||
- Repair tool use/result pairing.
|
||||
- Sanitize tool call ids (including a non-strict mode that preserved
|
||||
`_`/`-`).
|
||||
- The runner also performed provider-specific sanitization, which
|
||||
duplicated work.
|
||||
- Additional mutations occurred outside the provider policy, including
|
||||
stripping `<final>` tags from assistant text before persistence, dropping
|
||||
empty assistant error turns, and trimming assistant content after tool
|
||||
calls.
|
||||
|
||||
This complexity caused cross-provider regressions (notably
|
||||
`openai-responses` `call_id|fc_id` pairing). The 2026.1.22 cleanup removed
|
||||
the extension, centralized logic in the runner, and made OpenAI **no-touch**
|
||||
beyond image sanitization.
|
||||
|
||||
## Related
|
||||
|
||||
- [Session management](/concepts/session)
|
||||
- [Session pruning](/concepts/session-pruning)
|
||||
Reference in New Issue
Block a user