mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 20:00:47 +00:00
refactor(open-sse): add reasoningDelta helper, dedup thinking deltas (B4)
Centralize the reasoning_content delta shape (optional assistant role) used by claude/gemini/kiro/codex/commandcode response translators. Keeps the cross-format convention consistent for future translators. Output byte-for-byte identical; golden + gate clean. Ollama left as-is (mutates existing delta object). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
// Build OpenAI delta carrying reasoning_content (optional leading assistant role)
|
||||||
|
export function reasoningDelta(text, withRole = false) {
|
||||||
|
return withRole
|
||||||
|
? { role: "assistant", reasoning_content: text }
|
||||||
|
: { reasoning_content: text };
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { register } from "../index.js";
|
|||||||
import { FORMATS } from "../formats.js";
|
import { FORMATS } from "../formats.js";
|
||||||
import { buildChunk } from "../helpers/chunkBuilder.js";
|
import { buildChunk } from "../helpers/chunkBuilder.js";
|
||||||
import { buildUsage } from "../helpers/usageHelper.js";
|
import { buildUsage } from "../helpers/usageHelper.js";
|
||||||
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
|
||||||
// Create OpenAI chunk helper
|
// Create OpenAI chunk helper
|
||||||
function createChunk(state, delta, finishReason = null) {
|
function createChunk(state, delta, finishReason = null) {
|
||||||
@@ -67,7 +68,7 @@ export function claudeToOpenAIResponse(chunk, state) {
|
|||||||
if (delta?.type === "text_delta" && delta.text) {
|
if (delta?.type === "text_delta" && delta.text) {
|
||||||
results.push(createChunk(state, { content: delta.text }));
|
results.push(createChunk(state, { content: delta.text }));
|
||||||
} else if (delta?.type === "thinking_delta" && delta.thinking) {
|
} else if (delta?.type === "thinking_delta" && delta.thinking) {
|
||||||
results.push(createChunk(state, { reasoning_content: delta.thinking }));
|
results.push(createChunk(state, reasoningDelta(delta.thinking)));
|
||||||
} else if (delta?.type === "input_json_delta" && delta.partial_json) {
|
} else if (delta?.type === "input_json_delta" && delta.partial_json) {
|
||||||
const toolCall = state.toolCalls.get(chunk.index);
|
const toolCall = state.toolCalls.get(chunk.index);
|
||||||
if (toolCall) {
|
if (toolCall) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
import { register } from "../index.js";
|
import { register } from "../index.js";
|
||||||
import { FORMATS } from "../formats.js";
|
import { FORMATS } from "../formats.js";
|
||||||
import { buildChunk } from "../helpers/chunkBuilder.js";
|
import { buildChunk } from "../helpers/chunkBuilder.js";
|
||||||
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
|
||||||
function ensureState(state, model) {
|
function ensureState(state, model) {
|
||||||
if (!state.responseId) {
|
if (!state.responseId) {
|
||||||
@@ -96,9 +97,7 @@ export function convertCommandCodeToOpenAI(chunk, state) {
|
|||||||
const text = event.text || "";
|
const text = event.text || "";
|
||||||
if (!text) break;
|
if (!text) break;
|
||||||
// Map reasoning to OpenAI "reasoning_content" field (used by deepseek-reasoner-style clients).
|
// Map reasoning to OpenAI "reasoning_content" field (used by deepseek-reasoner-style clients).
|
||||||
const delta = state.chunkIndex === 0
|
const delta = reasoningDelta(text, state.chunkIndex === 0);
|
||||||
? { role: "assistant", reasoning_content: text }
|
|
||||||
: { reasoning_content: text };
|
|
||||||
state.chunkIndex++;
|
state.chunkIndex++;
|
||||||
out.push(makeChunk(state, delta));
|
out.push(makeChunk(state, delta));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { register } from "../index.js";
|
|||||||
import { FORMATS } from "../formats.js";
|
import { FORMATS } from "../formats.js";
|
||||||
import { buildChunk } from "../helpers/chunkBuilder.js";
|
import { buildChunk } from "../helpers/chunkBuilder.js";
|
||||||
import { buildUsage } from "../helpers/usageHelper.js";
|
import { buildUsage } from "../helpers/usageHelper.js";
|
||||||
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
|
||||||
// Build chunk meta for current gemini state
|
// Build chunk meta for current gemini state
|
||||||
function chunkMeta(state) {
|
function chunkMeta(state) {
|
||||||
@@ -42,7 +43,7 @@ export function geminiToOpenAIResponse(chunk, state) {
|
|||||||
if (hasTextContent) {
|
if (hasTextContent) {
|
||||||
results.push(buildChunk(
|
results.push(buildChunk(
|
||||||
chunkMeta(state),
|
chunkMeta(state),
|
||||||
isThought ? { reasoning_content: part.text } : { content: part.text },
|
isThought ? reasoningDelta(part.text) : { content: part.text },
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -78,7 +79,7 @@ export function geminiToOpenAIResponse(chunk, state) {
|
|||||||
if (part.text !== undefined && part.text !== "") {
|
if (part.text !== undefined && part.text !== "") {
|
||||||
results.push(buildChunk(
|
results.push(buildChunk(
|
||||||
chunkMeta(state),
|
chunkMeta(state),
|
||||||
isThought ? { reasoning_content: part.text } : { content: part.text },
|
isThought ? reasoningDelta(part.text) : { content: part.text },
|
||||||
null
|
null
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { register } from "../index.js";
|
|||||||
import { FORMATS } from "../formats.js";
|
import { FORMATS } from "../formats.js";
|
||||||
import { buildChunk } from "../helpers/chunkBuilder.js";
|
import { buildChunk } from "../helpers/chunkBuilder.js";
|
||||||
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
|
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
|
||||||
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
|
||||||
// Build chunk meta for current kiro state
|
// Build chunk meta for current kiro state
|
||||||
function chunkMeta(state) {
|
function chunkMeta(state) {
|
||||||
@@ -94,10 +95,7 @@ export function convertKiroToOpenAI(chunk, state) {
|
|||||||
: (reasoning.text || reasoning.content || data.content || "");
|
: (reasoning.text || reasoning.content || data.content || "");
|
||||||
if (!content) return null;
|
if (!content) return null;
|
||||||
|
|
||||||
const openaiChunk = buildChunk(chunkMeta(state), {
|
const openaiChunk = buildChunk(chunkMeta(state), reasoningDelta(content, state.chunkIndex === 0), null);
|
||||||
...(state.chunkIndex === 0 ? { role: "assistant" } : {}),
|
|
||||||
reasoning_content: content
|
|
||||||
}, null);
|
|
||||||
|
|
||||||
state.chunkIndex++;
|
state.chunkIndex++;
|
||||||
return openaiChunk;
|
return openaiChunk;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { FORMATS } from "../formats.js";
|
|||||||
import { buildChunk } from "../helpers/chunkBuilder.js";
|
import { buildChunk } from "../helpers/chunkBuilder.js";
|
||||||
import { buildUsage } from "../helpers/usageHelper.js";
|
import { buildUsage } from "../helpers/usageHelper.js";
|
||||||
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
|
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
|
||||||
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translate OpenAI chunk to Responses API events
|
* Translate OpenAI chunk to Responses API events
|
||||||
@@ -519,7 +520,7 @@ export function openaiResponsesToOpenAIResponse(chunk, state) {
|
|||||||
if (!delta) return null;
|
if (!delta) return null;
|
||||||
return buildChunk(
|
return buildChunk(
|
||||||
{ id: state.chatId, created: state.created, model: state.model || "unknown" },
|
{ id: state.chatId, created: state.created, model: state.model || "unknown" },
|
||||||
{ reasoning_content: delta }
|
reasoningDelta(delta)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user