fix(translator): keep tool-result images, restore Kiro tool names, preserve thinking display

Forward images inside tool_result to OpenAI and Kiro upstreams via following user messages, restore original client tool names on Kiro responses via _toolNameMap, and preserve thinking display settings across translations.
This commit is contained in:
Manan Santoki
2026-09-17 18:11:20 +07:00
parent 0c6ab4f99b
commit f4f06f290c
12 changed files with 328 additions and 23 deletions

View File

@@ -46,6 +46,14 @@ function convertFinishReason(reason) {
* Convert one OpenAI-format chunk (from KiroExecutor) into Claude SSE events.
* Returns an array of Claude events, or null when the chunk yields nothing.
*/
// Kiro only accepts sanitized tool names; the request translator leaves the
// reverse map on the stream state so calls come back under the client's names.
function restoreToolName(state, name) {
const raw = name || "";
const map = state?.toolNameMap;
return map && typeof map.get === "function" && map.has(raw) ? map.get(raw) : raw;
}
export function kiroToClaudeResponse(chunk, state) {
// KiroExecutor emits chat.completion.chunk objects; tolerate string chunks
// by attempting a parse (defensive — the direct path is always objects).
@@ -161,7 +169,7 @@ export function kiroToClaudeResponse(chunk, state) {
const toolBlockIndex = state.nextBlockIndex++;
state.toolCalls.set(idx, {
id: tc.id,
name: tc.function?.name || "",
name: restoreToolName(state, tc.function?.name),
blockIndex: toolBlockIndex,
});
results.push({
@@ -170,7 +178,7 @@ export function kiroToClaudeResponse(chunk, state) {
content_block: {
type: "tool_use",
id: tc.id,
name: tc.function?.name || "",
name: restoreToolName(state, tc.function?.name),
input: {},
},
});
@@ -246,7 +254,7 @@ export function kiroToClaudeNonStreaming(data) {
content.push({
type: "tool_use",
id: tc.id || `toolu_${Date.now()}`,
name: tc.function?.name || "",
name: restoreToolName(state, tc.function?.name),
input,
});
}

View File

@@ -20,13 +20,38 @@ function chunkMeta(state) {
* Parse Kiro SSE event and convert to OpenAI format
* Kiro events: assistantResponseEvent, codeEvent, supplementaryWebLinksEvent, etc.
*/
// Kiro only accepts sanitized tool names; the request translator leaves the
// reverse map on the stream state so calls come back under the client's names.
function restoreToolName(state, name) {
const raw = name || "";
const map = state?.toolNameMap;
return map && typeof map.get === "function" && map.has(raw) ? map.get(raw) : raw;
}
export function kiroToOpenAIResponse(chunk, state) {
if (!chunk) return null;
// If chunk is already in OpenAI format (from executor transform), return as-is
// If chunk is already in OpenAI format (from executor transform), return it
// with the client's tool names restored.
if (chunk.object === "chat.completion.chunk" && chunk.choices) {
return chunk;
if (!state?.toolNameMap?.size) return chunk;
return {
...chunk,
choices: chunk.choices.map((choice) => {
const calls = choice?.delta?.tool_calls;
if (!Array.isArray(calls)) return choice;
return {
...choice,
delta: {
...choice.delta,
tool_calls: calls.map((tc) => tc?.function?.name
? { ...tc, function: { ...tc.function, name: restoreToolName(state, tc.function.name) } }
: tc),
},
};
}),
};
}
// Handle string chunk (raw SSE data)
@@ -109,7 +134,7 @@ export function kiroToOpenAIResponse(chunk, state) {
state.hadToolUse = true;
const toolUse = data.toolUseEvent || data;
const toolCallId = toolUse.toolUseId || fallbackToolCallId();
const toolName = toolUse.name || "";
const toolName = restoreToolName(state, toolUse.name);
const toolInput = toolUse.input || {};
const openaiChunk = buildChunk(chunkMeta(state), {