mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-10 17:22:17 +03:00
fix(translator): make K3 reasoning preservation model-driven
This commit is contained in:
@@ -1 +1 @@
|
||||
- fix(translator): preserve Kimi K3 Responses reasoning through Kimi Coding Claude-format and native Moonshot requests, keeping it on the matching assistant tool call or completed turn instead of dropping it or carrying it across a user boundary (#9496)
|
||||
- fix(translator): preserve authentic K3 Responses reasoning by model across providers, projecting it onto the matching assistant tool call or completed turn instead of dropping it or carrying it across a user boundary (#9496)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Convert OpenAI Responses API format to standard chat completions format.
|
||||
* Delegates to the canonical translator to avoid logic duplication.
|
||||
*/
|
||||
import { shouldPreserveResponsesReasoningContent } from "../../utils/reasoningContentInjector.ts";
|
||||
import { requiresAuthenticReasoningContent } from "../../utils/reasoningContentInjector.ts";
|
||||
import { openaiResponsesToOpenAIRequest } from "../request/openai-responses.ts";
|
||||
import { toRecord } from "../request/openai-responses/helpers.ts";
|
||||
|
||||
@@ -23,7 +23,7 @@ export function convertResponsesApiFormat(
|
||||
credentials && typeof credentials === "object" && !Array.isArray(credentials)
|
||||
? (credentials as Record<string, unknown>)
|
||||
: {};
|
||||
const translationCredentials = shouldPreserveResponsesReasoningContent(provider, model)
|
||||
const translationCredentials = requiresAuthenticReasoningContent(provider, model)
|
||||
? { ...credentialRecord, _preserveReasoningContent: true }
|
||||
: credentials;
|
||||
const converted = openaiResponsesToOpenAIRequest(
|
||||
|
||||
@@ -13,10 +13,7 @@ import {
|
||||
providerHonorsOpenAIFormatCacheControl,
|
||||
resolveConnectionCacheOverride,
|
||||
} from "../utils/cacheControlPolicy.ts";
|
||||
import {
|
||||
requiresAuthenticReasoningContent,
|
||||
shouldPreserveResponsesReasoningContent,
|
||||
} from "../utils/reasoningContentInjector.ts";
|
||||
import { requiresAuthenticReasoningContent } from "../utils/reasoningContentInjector.ts";
|
||||
import { isInternalReasoningPlaceholder } from "../utils/reasoningPlaceholder.ts";
|
||||
import {
|
||||
coerceToolSchemas,
|
||||
@@ -245,8 +242,7 @@ export function translateRequest(
|
||||
normalizedModel
|
||||
);
|
||||
const preserveResponsesReasoning =
|
||||
sourceFormat === FORMATS.OPENAI_RESPONSES &&
|
||||
shouldPreserveResponsesReasoningContent(normalizedProvider, normalizedModel);
|
||||
sourceFormat === FORMATS.OPENAI_RESPONSES && requiresAuthenticReasoning;
|
||||
|
||||
// Phase 2: Apply thinking budget control before normalization
|
||||
result = applyThinkingBudget(result);
|
||||
|
||||
@@ -30,35 +30,24 @@ const THINKING_MODEL_PATTERNS: RegExp[] = [
|
||||
/\bmimo\b/i, // xiaomi-tokenplan mimo family (e.g. xiaomi-tokenplan/mimo-v2.5-pro)
|
||||
];
|
||||
|
||||
const AUTHENTIC_REASONING_MODEL_PATTERN = /(?:^|\/)kimi-k(?:3|2\.7-code)(?:$|-)/i;
|
||||
const K3_AUTHENTIC_REASONING_PATTERN = /(?:^|\/)(?:kimi-)?k3(?:$|-)/i;
|
||||
const NATIVE_K27_AUTHENTIC_REASONING_PATTERN = /(?:^|\/)kimi-k2\.7-code(?:$|-)/i;
|
||||
|
||||
/**
|
||||
* Native Moonshot K3/K2.7 replay must use the original reasoning content.
|
||||
* A fabricated placeholder changes preserved-thinking history and is not a
|
||||
* valid substitute when the client and reasoning cache both lack the field.
|
||||
* K3 requires authentic reasoning regardless of which provider serves it.
|
||||
* Native Moonshot K2.7 retains the same preserved-thinking contract. Empty
|
||||
* protocol markers remain valid only after client content and replay miss.
|
||||
*/
|
||||
export function requiresAuthenticReasoningContent(provider: unknown, model: unknown): boolean {
|
||||
const normalizedModel = String(model ?? "").trim();
|
||||
if (K3_AUTHENTIC_REASONING_PATTERN.test(normalizedModel)) return true;
|
||||
|
||||
const normalizedProvider = String(provider ?? "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
const normalizedModel = String(model ?? "").trim();
|
||||
return (
|
||||
(normalizedProvider === "moonshot" || normalizedProvider === "kimi") &&
|
||||
AUTHENTIC_REASONING_MODEL_PATTERN.test(normalizedModel)
|
||||
);
|
||||
}
|
||||
|
||||
export function shouldPreserveResponsesReasoningContent(
|
||||
provider: unknown,
|
||||
model: unknown
|
||||
): boolean {
|
||||
const normalizedProvider = String(provider ?? "")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
return (
|
||||
normalizedProvider === "kimi-coding" ||
|
||||
normalizedProvider === "kimi-coding-apikey" ||
|
||||
requiresAuthenticReasoningContent(normalizedProvider, model)
|
||||
NATIVE_K27_AUTHENTIC_REASONING_PATTERN.test(normalizedModel)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,9 +57,13 @@ test("production Responses conversion preserves Kimi K3 reasoning history", () =
|
||||
};
|
||||
|
||||
for (const { provider, model } of [
|
||||
{ provider: "kimi-coding", model: "k3" },
|
||||
{ provider: "kimi-coding-apikey", model: "k3-256k" },
|
||||
{ provider: "moonshot", model: "kimi-k3" },
|
||||
{ provider: "kimi", model: "kimi-k3" },
|
||||
{ provider: "some-other", model: "k3" },
|
||||
{ provider: "some-other", model: "k3-256k" },
|
||||
{ provider: "some-other", model: "kimi-k3" },
|
||||
]) {
|
||||
const converted = convertResponsesApiFormat(body, {}, provider, model) as {
|
||||
messages: Array<Record<string, unknown>>;
|
||||
@@ -67,10 +71,12 @@ test("production Responses conversion preserves Kimi K3 reasoning history", () =
|
||||
assert.equal(converted.messages[1].reasoning_content, "I should search first.");
|
||||
}
|
||||
|
||||
const generic = convertResponsesApiFormat(body, {}, "openai", "gpt-5") as {
|
||||
messages: Array<Record<string, unknown>>;
|
||||
};
|
||||
assert.equal(Object.hasOwn(generic.messages[1], "reasoning_content"), false);
|
||||
for (const provider of ["kimi-coding", "kimi-coding-apikey"]) {
|
||||
const generic = convertResponsesApiFormat(body, {}, provider, "kimi-k2.6") as {
|
||||
messages: Array<Record<string, unknown>>;
|
||||
};
|
||||
assert.equal(Object.hasOwn(generic.messages[1], "reasoning_content"), false, provider);
|
||||
}
|
||||
});
|
||||
|
||||
test("Responses→Chat: input_image converted to image_url with detail", () => {
|
||||
|
||||
Reference in New Issue
Block a user