



























@@ -2469,13 +2469,56 @@ function sanitizeOpenRouterReasoningReplayFields(record: Record<string, unknown>
24692469}
24702470}
247124712472+function sanitizeReasoningContentReplayFields(record: Record<string, unknown>): void {
2473+if ("reasoning_content" in record && typeof record.reasoning_content !== "string") {
2474+delete record.reasoning_content;
2475+}
2476+delete record.reasoning_details;
2477+delete record.reasoning;
2478+delete record.reasoning_text;
2479+}
2480+2481+const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
2482+"deepseek-v4-flash",
2483+"deepseek-v4-pro",
2484+"mimo-v2-pro",
2485+"mimo-v2-omni",
2486+"mimo-v2.5",
2487+"mimo-v2.5-pro",
2488+]);
2489+2490+function normalizeReasoningContentReplayModelId(modelId: unknown): string | undefined {
2491+if (typeof modelId !== "string") {
2492+return undefined;
2493+}
2494+const normalized = modelId.trim().toLowerCase().split(":", 1)[0];
2495+if (!normalized) {
2496+return undefined;
2497+}
2498+const parts = normalized.split("/").filter(Boolean);
2499+return parts[parts.length - 1] ?? normalized;
2500+}
2501+2502+function shouldPreserveReasoningContentReplay(
2503+model: OpenAIModeModel,
2504+compat: { requiresReasoningContentOnAssistantMessages: boolean },
2505+): boolean {
2506+if (compat.requiresReasoningContentOnAssistantMessages) {
2507+return true;
2508+}
2509+const normalizedModelId = normalizeReasoningContentReplayModelId(model.id);
2510+return (
2511+normalizedModelId !== undefined && REASONING_CONTENT_REPLAY_MODEL_IDS.has(normalizedModelId)
2512+);
2513+}
2514+24722515// OpenAI Chat Completions assistant-message input does not define reasoning
2473-// replay fields, while OpenRouter documents a compatible pass-back contract.
2474-// Keep OpenRouter's valid shapes, but normalize leaked string reasoning_details
2475-// from pi-ai thinking signatures before a follow-up request hits the wire.
2516+// replay fields, while OpenRouter and DeepSeek-style providers document
2517+// compatible pass-back contracts. Keep valid provider-owned replay fields, but
2518+// strip them for stock OpenAI before a follow-up request hits the wire.
24762519function sanitizeCompletionsReasoningReplayFields(
24772520messages: unknown,
2478-options: { preserveOpenRouterReasoning: boolean },
2521+options: { preserveOpenRouterReasoning: boolean; preserveReasoningContent: boolean },
24792522): void {
24802523if (!Array.isArray(messages)) {
24812524return;
@@ -2490,6 +2533,8 @@ function sanitizeCompletionsReasoningReplayFields(
24902533}
24912534if (options.preserveOpenRouterReasoning) {
24922535sanitizeOpenRouterReasoningReplayFields(record);
2536+} else if (options.preserveReasoningContent) {
2537+sanitizeReasoningContentReplayFields(record);
24932538} else {
24942539stripCompletionsReasoningReplayFields(record);
24952540}
@@ -2513,6 +2558,7 @@ export function buildOpenAICompletionsParams(
25132558injectToolCallThoughtSignatures(messages as unknown[], context, model);
25142559sanitizeCompletionsReasoningReplayFields(messages, {
25152560preserveOpenRouterReasoning: compat.thinkingFormat === "openrouter",
2561+preserveReasoningContent: shouldPreserveReasoningContentReplay(model, compat),
25162562});
25172563if (compat.strictMessageKeys) {
25182564messages = stripCompletionMessagesToRoleContent(messages) as typeof messages;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。