:Provider 重放前的內存級清理、配對修復與簽名處理機制全解)
OpenClaw 會話轉錄衛生Transcript HygieneProvider 重放前的內存級清理、配對修復與簽名處理機制全解【免費下載鏈接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 項目地址: https://gitcode.com/GitHub_Trending/cl/openclawOpenClaw 在每次模型調用構建模型上下文之前會對會話歷史做一層Provider 專屬的內存級轉錄修復以匹配不同模型供應商的嚴格協議要求工具調用 ID 格式、輪次交替、思考簽名、圖片尺寸等同時絕不改寫 SQLite 中持久化的運行時轉錄狀態。本文基于 docs/reference/transcript-hygiene.md 展開結合 transcript-policy.ts、replay-history.ts、session-transcript-repair.ts 等源碼完整梳理 OpenClaw 轉錄衛生的全局規則、Provider 矩陣行為、失敗重試恢復與歷史演進幫助你理解并排查“Provider 因轉錄形狀而拒絕請求”“跨 Provider 工具調用 ID 不匹配”一類問題。一、轉錄衛生是什么一次只發生在出站方向的內存投影OpenClaw 對轉錄的清理sanitization與修復repair遵循一條核心邊界所有 Provider 專屬的修復都只是「在構建出站模型上下文之前」對內存副本的調整目的是滿足嚴格 Provider 的協議要求。運行時轉錄狀態始終保存在 SQLite 中Provider 專屬的 assistant-prefill助手前綴剝離等操作只發生在構造出站 payload 時。因此任何一次重放修復都不會反向污染已存儲的會話事實。原文檔給出的 Scope 清單即轉錄衛生覆蓋的全部能力面如下本文后續各節將逐一展開僅存在于運行時runtime-only的提示上下文不進入用戶可見的轉錄輪次工具調用 ID 清理tool call id sanitization工具調用入參校驗tool call input validation工具結果配對修復tool result pairing repair輪次校驗 / 排序turn validation / ordering思考簽名thought signature清理思維塊簽名thinking signature清理圖片 payload 清理image payload sanitizationProvider 重放前空白文本塊清理Provider 重放前「不完整 reasoning-only 長度回合」清理用戶輸入來源標記inter-session 路由提示的 provenance taggingProvider 重放前空 assistant 錯誤回合移除需要強調這里的“重放”指的是把歷史轉錄再次組裝成模型上下文的過程而不是修改存檔。若你需要了解轉錄的存儲層細節請閱讀 Session management deep dive。二、失敗嘗試與恢復partial text、工具調用與錯誤如何落庫原文檔對“運行失敗后轉錄如何收尾”給出了明確的持久化語義純文本型 assistant 錯誤會被緩沖直到整個邏輯運行logical run塵埃落定。若后續恢復成功恢復后的回復會取代失敗嘗試的部分文本因此恢復路徑會丟棄失敗嘗試的 partial text終結性失敗terminal failure則保留最后一次嘗試的 partial text 與錯誤信息工具調用、可展示的非文本內容、附件事實attachment facts會立即持久化先于依賴它們的工具結果或恢復后的回復。這些事實行fact rows不攜帶錯誤并使用可重放的 stop reason從而保證 Provider 重放時仍保留這些調用對于「文本 事實」混合的消息partial text 與錯誤仍被單獨緩沖終結性結算不會重復落庫事實或 usage 記錄。從實現上看這套恢復語義復用現有的 assistant-row 形狀不需要數據庫遷移與 replay-history.ts 中normalizeAssistantReplayContent對失敗占位符如isStreamErrorFallbackContent且stopReason error的丟棄邏輯相互印證失敗的嘗試沒有模型內容重放副本中連其遺留占位符一并丟棄但保留已計費的靜默回復與不完整的工具/長度狀態。三、全局規則一運行時上下文不是用戶轉錄運行時可向某一輪模型提示中加入 system/runtime 上下文但這部分不是終端用戶撰寫的內容。OpenClaw 為此維護一份面向轉錄的獨立 prompt body用于 Gateway 回復、排隊中的 followup、ACP、CLI 與嵌入式embeddedOpenClaw 運行。已存儲的用戶可見輪次使用這份轉錄 body而非運行時增強后的 prompt。對于歷史上已經持久化了 runtime wrapper 的舊會話Gateway 歷史展示層在把消息返回給 WebChat、TUI、REST 或 SSE 客戶端前會應用**展示投影display projection**剝離內部元數據對應stripInternalMetadataForDisplay在 replay-history.ts 中的使用確保用戶看到的始終是干凈轉錄。四、在哪里運行策略解析與重放清理的職責邊界轉錄衛生的調度集中在嵌入式運行器embedded runner內部分兩個階段策略解析transcript-policy.ts 中的resolveTranscriptPolicy以provider、modelApi、modelId以及運行時模型元數據、配置、工作區、環境變量為鍵解析出當前生效的TranscriptPolicy清理/修復應用replay-history.ts 中的sanitizeSessionHistory按解析出的策略執行完整的重放清理管道。4.1 TranscriptPolicy 的結構TranscriptPolicy見 transcript-policy.ts是理解 Provider 差異的鑰匙它顯式聲明了每個 Provider 需要哪些能力字段含義sanitizeMode清理范圍full或images-onlysanitizeToolCallIds/toolCallIdMode是否清理工具調用 ID 及其模式如strictpreserveNativeAnthropicToolUseIds是否保留 Anthropic 原生 tool_use IDrepairToolUseResultPairing是否執行工具結果配對修復默認開啟preserveSignatures是否保留思維簽名appendOnlyRuntimeContext是否以追加方式保留運行時上下文載體前綴綁定模型sanitizeThoughtSignatures思考簽名清理選項如僅允許 base64dropThinkingBlocks是否丟棄思維塊dropReasoningFromHistory是否從歷史中剝離 reasoningapplyGoogleTurnOrdering是否應用 Google 式輪次排序修復validateGeminiTurns/validateAnthropicTurns是否做 Gemini / Anthropic 輪次校驗allowSyntheticToolResults是否允許合成工具結果4.2 默認策略與 Provider 專屬覆蓋DEFAULT_TRANSCRIPT_POLICYtranscript-policy.ts是保守基線默認sanitizeMode: images-only、repairToolUseResultPairing: true、其余開關基本關閉。解析流程是若 Provider 插件實現了buildReplayPolicy鉤子則以插件策略為準核心不再按傳輸族做默認推斷否則回退到buildUnownedProviderTransportReplayFallbacktranscript-policy.ts為 Google / Anthropic / 嚴格 OpenAI 兼容等無宿主插件的傳輸族提供窄回退策略。策略解析結果按config對象做WeakMap緩存transcriptPolicyCache緩存鍵涵蓋 provider、modelApi、modelId、canonicalModelId、是否丟棄思維塊、是否保留 reasoning 重放、工作區與插件控制面指紋等resolveTranscriptPolicyCacheKey同一 provider/model/config 元組不會重復解析。值得注意的細節buildUnownedProviderTransportReplayFallback會根據 model id 判斷 Claude 家族isClaudeFamilyModelId的正則匹配、根據model.reasoning true或REASONING_CONTENT_REPLAY_MODEL_IDS集合包含 Kimi、Mimo 等模型 id決定是否保留 reasoning 內容重放providerRequiresSignedThinking則把anthropic、amazon-bedrock、anthropic-vertex歸為“擁有簽名思維塊”的 Provider 家族。4.3 舊式 JSONL 校驗歸屬需要區分兩個系統Legacy JSONL 的校驗與導入屬于openclaw doctor --fix嵌入式運行器不會去修復或重新打開文件型運行時轉錄。也就是說轉錄衛生是運行時出站投影的職責文件導入修復是doctor命令的職責二者互不越界。五、全局規則二圖片清理image sanitization圖片 payload始終被清理目的是防止因尺寸超限導致 Provider 拒絕請求對超大的 base64 圖片做降采樣/重壓縮。這同時有助于控制視覺模型的 token 壓力最大邊長越小 token 占用越低越大細節保留越多。實現位置sanitizeSessionMessagesImages在 src/agents/embedded-agent-helpers/images.ts即sanitizeSessionMessagesImages定義處sanitizeContentBlocksImages在 src/agents/tool-images.ts最大邊長通過agents.defaults.imageMaxDimensionPx配置默認值為1200像素該限制通過resolveImageSanitizationLimits注入重放管道此外圖片清理這一遍遍歷重放內容時還會順帶移除空白文本塊清理后變空的 assistant 回合被丟棄除非它持有不透明的 Provider 重放狀態變空的 user 回合與 tool-result 回合則被替換為非空的內容省略占位符omitted-content placeholder保證輪次形狀完整。六、全局規則三畸形工具調用malformed tool calls同時缺失input和arguments的 assistant 工具調用塊在構建模型上下文前會被直接丟棄。這能防止因部分持久化的工具調用例如限流失敗后留下的殘片觸發 Provider 拒絕。實現sanitizeToolCallInputs定義于 session-transcript-repair.ts在sanitizeSessionHistoryreplay-history.ts中應用。從源碼看repairToolCallInputs還會校驗工具名isAllowedToolCallName僅允許allowedToolNames內的調用、剝離工具名首尾空白sanitizeToolCallBlock并在允許 Provider 思維重放時盡量保留「思維塊 合法工具調用」的回合isReplaySafeThinkingAssistantTurn因為 Anthropic 簽名思維塊必須字節級穩定。丟棄畸形調用時同步計數droppedToolCalls與droppedAssistantMessages保證修復報告可觀測。七、全局規則四工具結果配對修復tool result pairing工具結果在每個 assistant 回合內部與工具調用出現位置配對之后才會重寫 Provider 專屬的調用 ID。原因在于Provider 生成的 ID 可能在后續回合重復因此與重復調用相鄰的結果必須留在它所屬的那次出現上。配對修復的邊界條件如下被錯位displaced的結果只有在「恰好存在一個未解析的出現可歸屬」時才會被移動模棱兩可的多余結果被丟棄缺失的結果出現會被合成錯誤結果synthetic error result填充。實現sanitizeToolUseResultPairing對外導出sanitizeToolUseResultPairingForModel位于 session-transcript-repair.ts合成缺失結果走makeMissingToolResult復用packages/agent-core/src/harness/session/tool-result-pairing.js的配對分類邏輯。兩個重要的進階細節模型切換時Provider 重放會把延遲的異步工具結果移動到其發起調用的旁邊然后再移除源模型的異步元數據匹配前會先修剪調用 ID 與結果 ID 的首尾空白避免真實結果因為多余的空白被誤判為“缺失結果”而合成錯誤結果。此外OpenAI Responses 家族在配對修復之后還會執行一次不變式斷言assertOpenAIResponsesToolUseResultInvariant會掃描整個歷史任何懸空工具調用dangling tool call或孤兒工具結果orphan tool result都會拋出invalid_replay_transcript: OpenAI Responses replay contains ...錯誤并附帶 message index把“靜默出錯”變成“可定位的顯式失敗”。八、全局規則五不完整或靜默的 reasoning-only 回合在以下兩類事件發生后僅含 thinking 或 redacted-thinking 內容的 assistant 回合會從內存重放副本中省略Provider 輸出上限導致回合以「不完整 reasoning 狀態」結束靜默回復清理silent-reply cleanup移除了該回合唯一的可見NO_REPLY文本。靜默回復清理的目的很關鍵防止隱藏的 reasoning 在嚴格 Provider 重建對話時合并進后續的 assistant 工具使用回合。邊界條件同樣明確空長度回合empty length turns保持不變含可見文本、工具調用或未知內容塊的 length 回合保持不變含工具調用或未知內容塊的靜默回復回合保持不變存儲的轉錄不會被重寫。實現normalizeAssistantReplayContent位于 replay-history.ts。源碼中該函數還負責移除轉錄專用的 OpenClaw assistant 消息isTranscriptOnlyOpenClawAssistantMessage僅從重放副本丟棄、JSONL 保留丟棄空白的 user 文本塊剝離 assistant 文本的內部元數據并識別SILENT_REPLY_TOKEN靜默文本丟棄「裸 delivery-mirror 重復」回合零 usage、stop reason 為 stop、與前一 assistant 回合內容深度相等。這與原文檔「store 不重寫」的原則完全一致重放副本可增刪持久化事實不動。九、全局規則六會話間輸入來源標記inter-session provenance當 Agent 通過sessions_send向另一會話發送提示包括 agent 間回復/公告步驟時OpenClaw 會以message.provenance.kind inter_session持久化新建的 user 回合并且在路由提示文本前追加同一回合內的[Inter-session message] ... isUserfalse標記使當前模型調用能區分「外部會話的輸出」與「終端用戶的指令」該標記盡可能包含源會話、渠道與工具信息轉錄在 Provider 側仍使用role: user保證兼容性但可見文本與 provenance 元數據都標注其為 inter-session 數據上下文重建時OpenClaw 對只有 provenance 元數據、缺少標記的舊 inter-session user 回合應用同樣的標記。實現上annotateInterSessionUserMessagesreplay-history.ts在sanitizeSessionHistory管道第一步執行對字符串內容與內容塊數組中的文本塊分別注入annotateInterSessionPromptText無文本塊的 user 回合則前置一條Inter-session content follows.說明文本。相關 provenance 歸一化邏輯位于 src/sessions/input-provenance.ts。十、Provider 矩陣當前各家的轉錄行為對照原文檔給出了詳盡的 Provider 行為矩陣這是排查“為何這個 Provider 拒絕了這段歷史”的第一手對照表完整繼承如下。10.1 OpenAI / OpenAI Codex僅做圖片清理no-touch beyond image sanitization丟棄孤立的 reasoning 簽名后面沒有 content block 的獨立 reasoning 項并在模型路由切換后丟棄可重放的 OpenAI reasoning保留可重放的 OpenAI Responses reasoning item payload包括加密的空摘要項保證手動/WebSocket 重放時rs_*狀態與 assistant 輸出項配對原生 ChatGPT Codex Responses 按 Codex wire 對齊方式重放歷史 Responses reasoning/message/function payload不攜帶先前的 item ID同時保留會話prompt_cache_keyOpenAI Responses 家族重放保留同模型的call_*|fc_*reasoning 配對但在 pi-ai payload 轉換前確定性歸一化畸形或過長的call_id/function-call item id對應normalizeOpenAIResponsesToolCallIds工具結果配對修復可能移動真實匹配的輸出并為缺失的工具調用合成 Codex 風格的aborted輸出不做輪次校驗/排序不剝離 thought 簽名。10.2 OpenAI-compatible Chat Completions歷史 assistant thinking/reasoning 塊在重放前被剝離避免本地與代理式 OpenAI 兼容服務器收到reasoning、reasoning_content等前輪 reasoning 字段當前同輪的工具調用延續tool-call continuation在工具結果重放完成前保留附著在工具調用上的 assistant reasoning 塊自定義/自托管模型中reasoning: true的條目保留重放的 reasoning 元數據當其 wire 協議要求重放 reasoning 元數據時Provider 持有的例外可以退出剝離opt out。10.3 GoogleGenerative AI / Gemini CLI / Antigravity工具調用 ID 清理嚴格字母數字strict alphanumeric工具結果配對修復與合成工具結果輪次校驗Gemini 風格輪次交替validateGeminiTurnsGoogle 輪次排序修復歷史以 assistant 開頭時前置一個極小的 user 引導回合bootstrapAntigravity Claude歸一化 thinking 簽名丟棄未簽名的 thinking 塊。10.4 Anthropic / MinimaxAnthropic-compatible前綴綁定prefix-bindingClaude 模型如 Fable 5.1會把運行時上下文載體持久化為緊接其 user 回合的隱藏自定義消息并在重放時原位回放舊 user 回合上的內聯入站元數據也會保留。這一「按模型作用域的追加策略」覆蓋 Bedrock、Vertex、Foundry 路由。載體只包含定界上下文體共享指令只存在于穩定的 system prompt 中一次載體保持 user 角色不進入聊天歷史也不參與壓縮摘要。其他 Claude 模型與 Anthropic 兼容模型則使用瞬時載體避免在沒有前綴綁定時為舊載體反復支付緩存讀取費用與上下文占用工具結果配對修復與合成工具結果輪次校驗合并連續 user 回合以滿足嚴格交替。但對前綴綁定模型的 Messages API追加式重放會保持連續 user 回合分離命令回合后接提示回合按各自時間戳重放Bedrock Converse 仍會合并它們對應shouldMergeConsecutiveUserTurns僅appendOnlyRuntimeContext modelApi anthropic-messages時不合并啟用 thinking 時尾部 assistant prefill 回合會從出站 Anthropic Messages payload 中剝離包括 Cloudflare AI Gateway 路由壓縮compaction后的 pre-compaction assistant thinking 簽名會被剝離再重放壓縮改變了被簽名前綴摘要內容取代原文回放原簽名會導致 Anthropic 以 “Invalid signature in thinking block” 拒絕請求。思維文本保留為無符號塊交給下一條規則處理簽名缺失/為空/為空白blank的 thinking 塊在 Provider 轉換前被剝離若因此清空某 assistant 回合OpenClaw 用非空 omitted-reasoning 文本保持回合形狀必須被剝離的舊 thinking-only assistant 回合會被替換為非空 omitted-reasoning 文本避免 Provider 適配器丟棄重放回合。10.5 Amazon BedrockConverse API從內存重放副本中丟棄空的 assistant 流錯誤回合與舊式 fallback 占位符避免產生非法空 ContentBlocks 與合成 assistant prefill同時不改寫存儲轉錄零 usage 的空 stop 回合也被丟棄已計費的靜默回復與帶真實 assistant 內容的錯誤回合保留原有重放處理與 Anthropic 相同的原因壓縮后的 pre-compaction thinking 簽名在 Converse 重放前被剝離簽名缺失/為空/為空白的 Claude thinking 塊在 Converse 重放前被剝離清空回合時用非空 omitted-reasoning 文本保持輪次形狀必須剝離的舊 thinking-only assistant 回合替換為非空 omitted-reasoning 文本保持 Converse 嚴格輪次形狀重放會過濾 OpenClaw 的 delivery-mirror 與 gateway 注入的 assistant 回合圖片清理經由全局規則生效。10.6 Mistral含基于 model-id 的檢測工具調用 ID 清理strict9字母數字長度固定為 9。10.7 OpenRouter Gemini思考簽名清理剝離非 base64 的thought_signature值保留 base64 值。10.8 OpenRouter Anthropic對已驗證的 OpenRouter OpenAI 兼容 Anthropic 模型在啟用 reasoning 時剝離尾部 assistant prefill 回合與直連 Anthropic 和 Cloudflare Anthropic 的重放行為保持一致。10.9 其他一切 Provider僅做圖片清理image sanitization only。十一、重放清理管道全景sanitizeSessionHistory 內部順序把上述規則落到代碼上sanitizeSessionHistoryreplay-history.ts的執行順序即一次完整的內存投影流水線解析策略未顯式傳入時調用resolveTranscriptPolicy注入 inter-session 標記annotateInterSessionUserMessages規范化 assistant/user 重放內容normalizeAssistantReplayContent空文本、靜默回復、流錯誤占位、reasoning-only 回合、mirror 重復等圖片清理sanitizeSessionMessagesImages受sanitizeMode與圖片尺寸限制控制壓縮導致的過期 thinking 簽名剝離stripStaleThinkingSignaturesForCompactionReplay僅簽名 Provider 或preserveSignatures時無效 thinking 簽名剝離stripInvalidThinkingSignatures保留最新 assistant thinking按策略剝離 reasoningdropReasoningFromHistory與 thinking 塊dropThinkingBlocks工具調用入參清理sanitizeToolCallInputsOpenAI Responses 分支配對修復 → 剝離過期 reasoning → 歸一化工具調用 ID → 降級 function-call reasoning 對sanitizeToolUseResultPairingForModeldropStaleOpenAIReasoningnormalizeOpenAIResponsesToolCallIdsdowngradeOpenAIFunctionCallReasoningPairs非 Responses 分支通用配對修復工具調用 ID 清理sanitizeToolCallIdsForCloudCodeAssist按toolCallIdMode工具結果細節剝離stripToolResultDetails與 usage 快照歸一化ensureAssistantUsageSnapshots保留 Provider 計費的totalOriginProvider 插件重放鉤子sanitizeProviderReplayHistoryWithPlugin鉤子后重新斷言配對策略與 Responses 不變式assertOpenAIResponsesToolUseResultInvariant模型切換快照記錄appendModelSnapshotMODEL_SNAPSHOT_CUSTOM_TYPE需要時執行 Google 輪次排序修復sanitizeGoogleTurnOrdering嚴格 OpenAI 兼容的 vLLM/Gemma 等同樣會拒絕 assistant 開頭的對話Responses 分支最后再做一次不變式斷言。與管道并行的還有validateReplayTurnsreplay-history.ts先嘗試 Provider 插件的輪次校驗鉤子否則按策略執行validateGeminiTurns與validateAnthropicTurns連續 user 回合是否合并由shouldMergeConsecutiveUserTurns決定。十二、歷史行為2026.1.22 之前與架構收斂在 2026.1.22 版本之前OpenClaw 的轉錄衛生存在多層疊加一個transcript-sanitize 擴展在每次上下文構建時運行能修復工具使用/結果配對、清理工具調用 ID包括保留_/-的非嚴格模式運行器同時做 Provider 專屬清理與擴展職責重復在 Provider 策略之外還有額外變更持久化前剝離 assistant 文本中的final標簽、丟棄空 assistant 錯誤回合、在工具調用后裁剪 assistant 內容。這套復雜度引發了跨 Provider 回歸最典型的是openai-responses的call_id|fc_id配對問題。2026.1.22 的清理動作是移除該擴展、把邏輯集中到運行器、并讓 OpenAI 在圖片清理之外變成 no-touch。這一歷史沿革解釋了為什么現在所有修復都收斂在sanitizeSessionHistory單一管道中、并由resolveTranscriptPolicy統一裁決。十三、排查實踐建議與相關文檔根據原文檔的read_when指引以下場景應優先查閱本機制正在調試「Provider 因轉錄形狀而拒絕請求」先確認resolveTranscriptPolicy對該 provider/modelApi/modelId 解析出的TranscriptPolicy尤其是sanitizeMode、validateAnthropicTurns、dropThinkingBlocks、sanitizeToolCallIds正在修改轉錄清理或工具調用修復邏輯以 replay-history.ts 的sanitizeSessionHistory管道為主入口新增規則應保持「內存投影、不改寫存儲」的邊界正在排查跨 Provider 的工具調用 ID 不匹配對照「全局規則四」的回合內配對語義、ID 修剪規則以及 OpenAI Responses 的assertOpenAIResponsesToolUseResultInvariant不變式遇到 Anthropic 的 “Invalid signature in thinking block”優先檢查是否經過壓縮前綴已變以及 thinking 簽名是否缺失/為空/為空白——這兩類都是設計內會被剝離的場景。相關縱深閱讀Session management、Session pruning、Session management compaction。如果你還負責排查壓縮與簽名問題thinking-signatures.ts 中的stripStaleThinkingSignaturesForCompactionReplay是定位簽名過期的直接入口。【免費下載鏈接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 項目地址: https://gitcode.com/GitHub_Trending/cl/openclaw創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考