refactor(translator): P4 concern #6 finishReasonMap — switch-by-format, default common
- concerns/finishReasonMap.js: toOpenAIFinish/fromOpenAIFinish, switch special formats, default passthrough - Replace 3 inline switch maps (claude→oai, oai→claude, commandcode→oai) - Golden translator tests pass, behavior identical Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
43
open-sse/translator/concerns/finishReasonMap.js
Normal file
43
open-sse/translator/concerns/finishReasonMap.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Concern #6: finish_reason / stop_reason mapping.
|
||||||
|
// One entry per direction; switch by special format, default handles common providers.
|
||||||
|
|
||||||
|
// upstream finish/stop reason → OpenAI finish_reason
|
||||||
|
export function toOpenAIFinish(reason, format) {
|
||||||
|
switch (format) {
|
||||||
|
case "claude":
|
||||||
|
switch (reason) {
|
||||||
|
case "end_turn": return "stop";
|
||||||
|
case "max_tokens": return "length";
|
||||||
|
case "tool_use": return "tool_calls";
|
||||||
|
case "stop_sequence": return "stop";
|
||||||
|
default: return "stop";
|
||||||
|
}
|
||||||
|
case "commandcode":
|
||||||
|
switch (reason) {
|
||||||
|
case "stop": return "stop";
|
||||||
|
case "length": return "length";
|
||||||
|
case "tool-calls":
|
||||||
|
case "tool_use": return "tool_calls";
|
||||||
|
case "content-filter": return "content_filter";
|
||||||
|
case "error": return "stop";
|
||||||
|
default: return reason || "stop";
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return reason || "stop";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenAI finish_reason → upstream stop reason
|
||||||
|
export function fromOpenAIFinish(reason, format) {
|
||||||
|
switch (format) {
|
||||||
|
case "claude":
|
||||||
|
switch (reason) {
|
||||||
|
case "stop": return "end_turn";
|
||||||
|
case "length": return "max_tokens";
|
||||||
|
case "tool_calls": return "tool_use";
|
||||||
|
default: return "end_turn";
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,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 { reasoningDelta } from "../helpers/reasoningHelper.js";
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
import { toOpenAIFinish } from "../concerns/finishReasonMap.js";
|
||||||
|
|
||||||
// Create OpenAI chunk helper
|
// Create OpenAI chunk helper
|
||||||
function createChunk(state, delta, finishReason = null) {
|
function createChunk(state, delta, finishReason = null) {
|
||||||
@@ -164,16 +165,7 @@ export function claudeToOpenAIResponse(chunk, state) {
|
|||||||
return results.length > 0 ? results : null;
|
return results.length > 0 ? results : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Claude stop_reason to OpenAI finish_reason
|
const convertStopReason = (reason) => toOpenAIFinish(reason, "claude");
|
||||||
function convertStopReason(reason) {
|
|
||||||
switch (reason) {
|
|
||||||
case "end_turn": return "stop";
|
|
||||||
case "max_tokens": return "length";
|
|
||||||
case "tool_use": return "tool_calls";
|
|
||||||
case "stop_sequence": return "stop";
|
|
||||||
default: return "stop";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
register(FORMATS.CLAUDE, FORMATS.OPENAI, null, claudeToOpenAIResponse);
|
register(FORMATS.CLAUDE, FORMATS.OPENAI, null, claudeToOpenAIResponse);
|
||||||
|
|||||||
@@ -19,6 +19,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 { reasoningDelta } from "../helpers/reasoningHelper.js";
|
import { reasoningDelta } from "../helpers/reasoningHelper.js";
|
||||||
|
import { toOpenAIFinish } from "../concerns/finishReasonMap.js";
|
||||||
|
|
||||||
function ensureState(state, model) {
|
function ensureState(state, model) {
|
||||||
if (!state.responseId) {
|
if (!state.responseId) {
|
||||||
@@ -43,17 +44,7 @@ function makeChunk(state, delta, finishReason = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapFinishReason(reason) {
|
const mapFinishReason = (reason) => toOpenAIFinish(reason, "commandcode");
|
||||||
switch (reason) {
|
|
||||||
case "stop": return "stop";
|
|
||||||
case "length": return "length";
|
|
||||||
case "tool-calls":
|
|
||||||
case "tool_use": return "tool_calls";
|
|
||||||
case "content-filter": return "content_filter";
|
|
||||||
case "error": return "stop";
|
|
||||||
default: return reason || "stop";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertCommandCodeToOpenAI(chunk, state) {
|
export function convertCommandCodeToOpenAI(chunk, state) {
|
||||||
if (!chunk) return null;
|
if (!chunk) return null;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { register } from "../index.js";
|
import { register } from "../index.js";
|
||||||
import { FORMATS } from "../formats.js";
|
import { FORMATS } from "../formats.js";
|
||||||
|
import { fromOpenAIFinish } from "../concerns/finishReasonMap.js";
|
||||||
|
|
||||||
// Prefix for Claude OAuth tool names (must match request translator)
|
// Prefix for Claude OAuth tool names (must match request translator)
|
||||||
const CLAUDE_OAUTH_TOOL_PREFIX = "proxy_";
|
const CLAUDE_OAUTH_TOOL_PREFIX = "proxy_";
|
||||||
@@ -252,15 +253,7 @@ export function openaiToClaudeResponse(chunk, state) {
|
|||||||
return results.length > 0 ? results : null;
|
return results.length > 0 ? results : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert OpenAI finish_reason to Claude stop_reason
|
const convertFinishReason = (reason) => fromOpenAIFinish(reason, "claude");
|
||||||
function convertFinishReason(reason) {
|
|
||||||
switch (reason) {
|
|
||||||
case "stop": return "end_turn";
|
|
||||||
case "length": return "max_tokens";
|
|
||||||
case "tool_calls": return "tool_use";
|
|
||||||
default: return "end_turn";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
register(FORMATS.OPENAI, FORMATS.CLAUDE, null, openaiToClaudeResponse);
|
register(FORMATS.OPENAI, FORMATS.CLAUDE, null, openaiToClaudeResponse);
|
||||||
|
|||||||
Reference in New Issue
Block a user