refactor(open-sse): dedup fallback tool_call id helper (B3)

Add fallbackToolCallId() and apply to kiro/ollama/openai-responses response
translators (identical id shape). Leave commandcode (different order) and
request-side gemini/antigravity (random suffix) untouched. Golden + gate clean.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
decolua
2026-06-13 18:12:40 +07:00
parent f4c39042a0
commit 997860aa1f
5 changed files with 12 additions and 4 deletions

View File

@@ -3,6 +3,11 @@
// Anthropic tool_use.id must match: ^[a-zA-Z0-9_-]+$
const TOOL_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
// Fallback streaming tool_call id when provider omits one (index optional)
export function fallbackToolCallId(index) {
return index === undefined ? `call_${Date.now()}` : `call_${index}_${Date.now()}`;
}
// Generate deterministic tool call ID from position + tool name (cache-friendly)
export function generateToolCallId(msgIndex = 0, tcIndex = 0, toolName = "") {
const name = toolName ? `_${toolName.replace(/[^a-zA-Z0-9_-]/g, "")}` : "";

View File

@@ -5,6 +5,7 @@
import { register } from "../index.js";
import { FORMATS } from "../formats.js";
import { buildChunk } from "../helpers/chunkBuilder.js";
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
// Build chunk meta for current kiro state
function chunkMeta(state) {
@@ -105,7 +106,7 @@ export function convertKiroToOpenAI(chunk, state) {
// Handle tool use events
if (eventType === "toolUseEvent" || data.toolUseEvent) {
const toolUse = data.toolUseEvent || data;
const toolCallId = toolUse.toolUseId || `call_${Date.now()}`;
const toolCallId = toolUse.toolUseId || fallbackToolCallId();
const toolName = toolUse.name || "";
const toolInput = toolUse.input || {};

View File

@@ -1,6 +1,7 @@
import { register } from "../index.js";
import { FORMATS } from "../formats.js";
import { buildChunk } from "../helpers/chunkBuilder.js";
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
/**
* Convert Ollama NDJSON response to OpenAI SSE format
@@ -91,7 +92,7 @@ function extractUsage(ollamaChunk) {
function convertToolCalls(toolCalls) {
return toolCalls.map((tc, i) => ({
index: tc.function?.index ?? i,
id: tc.id || `call_${i}_${Date.now()}`,
id: tc.id || fallbackToolCallId(i),
type: "function",
function: {
name: tc.function?.name || "",

View File

@@ -6,6 +6,7 @@ import { register } from "../index.js";
import { FORMATS } from "../formats.js";
import { buildChunk } from "../helpers/chunkBuilder.js";
import { buildUsage } from "../helpers/usageHelper.js";
import { fallbackToolCallId } from "../helpers/toolCallHelper.js";
/**
* Translate OpenAI chunk to Responses API events
@@ -424,7 +425,7 @@ export function openaiResponsesToOpenAIResponse(chunk, state) {
// Function call started (standard function_call or custom_tool_call)
if (eventType === "response.output_item.added" && (data.item?.type === "function_call" || data.item?.type === "custom_tool_call")) {
const item = data.item;
state.currentToolCallId = item.call_id || `call_${Date.now()}`;
state.currentToolCallId = item.call_id || fallbackToolCallId();
return buildChunk(
{ id: state.chatId, created: state.created, model: state.model || "unknown" },

File diff suppressed because one or more lines are too long