feat(ai): route copilot claude via anthropic messages api

This commit is contained in:
Nate Smyth
2026-02-06 05:09:52 -05:00
committed by Mario Zechner
parent cf1353b8e7
commit 0a132a30a1
9 changed files with 196 additions and 76 deletions

View File

@@ -14,6 +14,7 @@ import type {
Usage,
} from "../types.js";
import { AssistantMessageEventStream } from "../utils/event-stream.js";
import { buildCopilotDynamicHeaders, hasCopilotVisionInput } from "./github-copilot-headers.js";
import { convertResponsesMessages, convertResponsesTools, processResponsesStream } from "./openai-responses-shared.js";
import { buildBaseOptions, clampReasoning } from "./simple-options.js";
@@ -159,28 +160,12 @@ function createClient(
const headers = { ...model.headers };
if (model.provider === "github-copilot") {
// Copilot expects X-Initiator to indicate whether the request is user-initiated
// or agent-initiated (e.g. follow-up after assistant/tool messages). If there is
// no prior message, default to user-initiated.
const messages = context.messages || [];
const lastMessage = messages[messages.length - 1];
const isAgentCall = lastMessage ? lastMessage.role !== "user" : false;
headers["X-Initiator"] = isAgentCall ? "agent" : "user";
headers["Openai-Intent"] = "conversation-edits";
// Copilot requires this header when sending images
const hasImages = messages.some((msg) => {
if (msg.role === "user" && Array.isArray(msg.content)) {
return msg.content.some((c) => c.type === "image");
}
if (msg.role === "toolResult" && Array.isArray(msg.content)) {
return msg.content.some((c) => c.type === "image");
}
return false;
const hasImages = hasCopilotVisionInput(context.messages);
const copilotHeaders = buildCopilotDynamicHeaders({
messages: context.messages,
hasImages,
});
if (hasImages) {
headers["Copilot-Vision-Request"] = "true";
}
Object.assign(headers, copilotHeaders);
}
// Merge options headers last so they can override defaults