Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions lib/server/proxy/anthropic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { proxyChatCompletions, type ChatRequestBody } from './codebuddy';
import {
getServerToolStreamEvent,
getServerToolExecutions,
getServerToolTurns,
type ServerToolExecution,
type ServerToolTurn,
} from './web-search-loop';
Expand Down Expand Up @@ -138,12 +139,6 @@ interface OpenAIChatResponse {
id?: string;
model?: string;
choices?: OpenAIChatChoice[];
/**
* Per-hop grouping emitted by the local server-tool loop. Not part of the
* OpenAI protocol — it survives only as far as this file, which turns it into
* Anthropic content blocks.
*/
turns?: ServerToolTurn[];
usage?: OpenAIUsage;
}

Expand Down Expand Up @@ -1662,6 +1657,10 @@ export const handleMessagesRequest = async (

const model = String(chatBody.model ?? 'unknown');
const serverToolExecutions = getServerToolExecutions(upstreamResponse);
// Carried beside the response rather than inside it: the OpenAI-shaped
// payload the loop emits must stay protocol-clean for chat-completions
// clients, so this file reads the grouping off the response itself.
const turns = getServerToolTurns(upstreamResponse);

if (body.stream) {
return mapOpenAIStreamToAnthropicSSE(upstreamResponse, model);
Expand All @@ -1670,12 +1669,7 @@ export const handleMessagesRequest = async (
const payload = (await upstreamResponse.json()) as OpenAIChatResponse;

return Response.json(
mapOpenAIResponseToAnthropic(
payload,
model,
serverToolExecutions,
payload.turns,
),
mapOpenAIResponseToAnthropic(payload, model, serverToolExecutions, turns),
);
} catch (error) {
return createAnthropicError(
Expand Down
23 changes: 13 additions & 10 deletions lib/server/proxy/codebuddy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from '../search/tool';
import {
attachServerToolExecutions,
attachServerToolTurns,
type ChatCompletionPayload,
executeWebSearchLoop,
type ServerToolCallbacks,
Expand Down Expand Up @@ -3116,11 +3117,17 @@ export const proxyChatCompletions = async (
}

if (webSearch?.response) {
if (!webSearch.response.ok) {
return attachServerToolExecutions(
webSearch.response,
webSearch.executions,
// The hop grouping rides beside the response rather than inside its
// body, so the OpenAI-shaped payload a chat client receives stays
// protocol-clean. See `attachServerToolTurns`.
const attachServerToolResult = (response: Response): Response =>
attachServerToolTurns(
attachServerToolExecutions(response, webSearch.executions),
webSearch.turns,
);

if (!webSearch.response.ok) {
return attachServerToolResult(webSearch.response);
}

if (
Expand All @@ -3130,19 +3137,15 @@ export const proxyChatCompletions = async (
?.toLowerCase()
.includes('text/event-stream')
) {
return attachServerToolExecutions(
return attachServerToolResult(
synthesizeChatCompletionStream(
(await webSearch.response.json()) as ChatCompletionPayload,
String(upstreamBody.model ?? 'unknown'),
),
webSearch.executions,
);
}

return attachServerToolExecutions(
webSearch.response,
webSearch.executions,
);
return attachServerToolResult(webSearch.response);
}
}

Expand Down
4 changes: 2 additions & 2 deletions lib/server/proxy/image-generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ export const executeImageGenerationLoop = async ({
payload,
reasonings: [],
texts: intermediateTexts,
}),
}).payload,
),
};
}
Expand Down Expand Up @@ -482,7 +482,7 @@ export const executeImageGenerationLoop = async ({
payload: lastPayload ?? {},
reasonings: [],
texts: intermediateTexts,
}),
}).payload,
),
};
};
Expand Down
Loading
Loading