copilot-api / tests /messages-handler.test.ts
imspsycho's picture
Initial upload from Google Colab
98c9143 verified
Raw
History Blame Contribute Delete
14.6 kB
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test"
import { Hono } from "hono"
import type { AnthropicMessagesPayload } from "../src/routes/messages/anthropic-types"
import {
compactSummaryPromptStart,
compactTextOnlyGuard,
} from "../src/lib/compact"
const actualStateModule = await import("../src/lib/state")
const actualConfigModule = await import("../src/lib/config")
const actualModelsModule = await import("../src/lib/models")
const actualRateLimitModule = await import("../src/lib/rate-limit")
const actualUtilsModule = await import("../src/lib/utils")
const state = {
...actualStateModule.state,
manualApprove: false,
verbose: false,
}
let messagesApiEnabled = true
let modelMappings: Record<string, string> = {}
type SelectedModel = {
id: string
supported_endpoints?: Array<string>
}
type FlowCallOptions = {
compactType?: number
requestId: string
sessionId?: string
subagentMarker?: unknown
anthropicBetaHeader?: string
}
let selectedModel: SelectedModel | undefined
const findEndpointModel = mock((_: string) => selectedModel)
const checkRateLimit = mock(async () => {})
const handleWithMessagesApi = mock(
(
_c: unknown,
_payload: AnthropicMessagesPayload,
_options: FlowCallOptions,
) => Promise.resolve(new Response("messages")),
)
const handleWithResponsesApi = mock(
(
_c: unknown,
_payload: AnthropicMessagesPayload,
_options: FlowCallOptions,
) => Promise.resolve(new Response("responses")),
)
const handleWithChatCompletions = mock(
(
_c: unknown,
_payload: AnthropicMessagesPayload,
_options: FlowCallOptions,
) => Promise.resolve(new Response("chat")),
)
await mock.module("~/lib/state", () => ({
...actualStateModule,
state,
}))
await mock.module("~/lib/rate-limit", () => ({
...actualRateLimitModule,
checkRateLimit,
}))
await mock.module("~/lib/config", () => ({
...actualConfigModule,
getSmallModel: () => "small-model",
isMessagesApiEnabled: () => messagesApiEnabled,
resolveMappedModel: (model: string) => modelMappings[model] ?? model,
}))
await mock.module("~/lib/models", () => ({
...actualModelsModule,
findEndpointModel,
}))
await mock.module("~/lib/utils", () => ({
...actualUtilsModule,
}))
const { handleCompletion, messagesFlowHandlers } = await import(
"../src/routes/messages/handler"
)
const defaultMessagesFlowHandlers = { ...messagesFlowHandlers }
const createApp = () => {
const app = new Hono()
app.post("/", handleCompletion)
return app
}
const createPayload = (
overrides: Partial<AnthropicMessagesPayload> = {},
): AnthropicMessagesPayload => ({
model: "original-model",
max_tokens: 128,
messages: [{ role: "user", content: "hello" }],
...overrides,
})
beforeEach(() => {
state.manualApprove = false
state.verbose = false
messagesApiEnabled = true
modelMappings = {}
selectedModel = undefined
messagesFlowHandlers.handleWithMessagesApi = handleWithMessagesApi
messagesFlowHandlers.handleWithResponsesApi = handleWithResponsesApi
messagesFlowHandlers.handleWithChatCompletions = handleWithChatCompletions
checkRateLimit.mockClear()
findEndpointModel.mockClear()
handleWithMessagesApi.mockClear()
handleWithResponsesApi.mockClear()
handleWithChatCompletions.mockClear()
})
afterEach(() => {
messagesFlowHandlers.handleWithMessagesApi =
defaultMessagesFlowHandlers.handleWithMessagesApi
messagesFlowHandlers.handleWithResponsesApi =
defaultMessagesFlowHandlers.handleWithResponsesApi
messagesFlowHandlers.handleWithChatCompletions =
defaultMessagesFlowHandlers.handleWithChatCompletions
})
describe("messages handler orchestration", () => {
test("removes executeCode and rewrites getDiagnostics before forwarding tools", async () => {
selectedModel = {
id: "messages-model",
supported_endpoints: ["/v1/messages"],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(
createPayload({
tools: [
{
name: "mcp__ide__executeCode",
description: "Execute code in VS Code",
input_schema: { type: "object" },
},
{
name: "mcp__ide__getDiagnostics",
description: "Old description",
input_schema: { type: "object" },
},
{
name: "keep_me",
description: "Keep me",
input_schema: { type: "object" },
},
],
}),
),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("messages")
const [, forwardedPayload] = handleWithMessagesApi.mock.calls[0]
expect(forwardedPayload.tools).toEqual([
{
name: "mcp__ide__getDiagnostics",
description:
"Get language diagnostics from VS Code. Returns errors, warnings, information, and hints for files in the workspace.",
input_schema: { type: "object" },
},
{
name: "keep_me",
description: "Keep me",
input_schema: { type: "object" },
},
])
})
test("adds cache_control to the last content block after merging tool_result content", async () => {
selectedModel = {
id: "messages-model",
supported_endpoints: ["/v1/messages"],
}
const payload: AnthropicMessagesPayload = {
model: "original-model",
max_tokens: 128,
messages: [
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "tool-1",
content: "Launching skill: foo",
},
{
type: "text",
text: "[Pasted ~4 lines]",
},
],
},
],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(payload),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("messages")
const [, forwardedPayload] = handleWithMessagesApi.mock.calls[0]
expect(forwardedPayload.messages[0]).toEqual({
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "tool-1",
content: "Launching skill: foo\n\n[Pasted ~4 lines]",
cache_control: {
type: "ephemeral",
},
},
],
})
})
test("preserves cache_control captured before Tool loaded is stripped", async () => {
selectedModel = {
id: "messages-model",
supported_endpoints: ["/v1/messages"],
}
const payload: AnthropicMessagesPayload = {
model: "original-model",
max_tokens: 128,
messages: [
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "tool-1",
content: [
{
type: "tool_reference",
tool_name: "AskUserQuestion",
},
],
},
{
type: "text",
text: "Tool loaded.",
cache_control: {
type: "ephemeral",
scope: "user",
},
},
],
},
],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(payload),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("messages")
const [, forwardedPayload] = handleWithMessagesApi.mock.calls[0]
expect(forwardedPayload.messages[0]).toEqual({
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "tool-1",
content: [
{
type: "tool_reference",
tool_name: "AskUserQuestion",
},
],
cache_control: {
type: "ephemeral",
scope: "user",
},
},
],
})
})
test("delegates to the Messages API flow when the model supports /v1/messages", async () => {
selectedModel = {
id: "messages-model",
supported_endpoints: ["/v1/messages"],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(createPayload()),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("messages")
expect(handleWithMessagesApi).toHaveBeenCalledTimes(1)
expect(handleWithResponsesApi).not.toHaveBeenCalled()
expect(handleWithChatCompletions).not.toHaveBeenCalled()
const [, forwardedPayload] = handleWithMessagesApi.mock.calls[0]
expect(forwardedPayload.model).toBe("messages-model")
})
test("maps the requested model before resolving the endpoint model", async () => {
modelMappings = {
"claude-opus-4-7": "messages-model",
}
selectedModel = {
id: "messages-model",
supported_endpoints: ["/v1/messages"],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(createPayload({ model: "claude-opus-4-7" })),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("messages")
expect(findEndpointModel).toHaveBeenCalledWith("messages-model")
const [, forwardedPayload] = handleWithMessagesApi.mock.calls[0]
expect(forwardedPayload.model).toBe("messages-model")
})
test("delegates to the Responses API flow when the model supports /responses", async () => {
selectedModel = {
id: "responses-model",
supported_endpoints: ["/responses"],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(createPayload()),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("responses")
expect(handleWithMessagesApi).not.toHaveBeenCalled()
expect(handleWithResponsesApi).toHaveBeenCalledTimes(1)
expect(handleWithChatCompletions).not.toHaveBeenCalled()
})
test("delegates to the Responses API flow when the model supports ws:/responses", async () => {
selectedModel = {
id: "responses-ws-model",
supported_endpoints: ["ws:/responses"],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(createPayload()),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("responses")
expect(handleWithMessagesApi).not.toHaveBeenCalled()
expect(handleWithResponsesApi).toHaveBeenCalledTimes(1)
expect(handleWithChatCompletions).not.toHaveBeenCalled()
})
test("does not delegate compact requests to a ws-only Responses API model", async () => {
selectedModel = {
id: "responses-ws-model",
supported_endpoints: ["ws:/responses"],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(
createPayload({
messages: [
{
role: "user",
content: `${compactTextOnlyGuard}\n\n${compactSummaryPromptStart}\n\nPending Tasks:\n- one\n\nCurrent Work:\n- two`,
},
],
}),
),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("chat")
expect(handleWithMessagesApi).not.toHaveBeenCalled()
expect(handleWithResponsesApi).not.toHaveBeenCalled()
expect(handleWithChatCompletions).toHaveBeenCalledTimes(1)
})
test("falls back to the Chat Completions flow when no endpoint matches", async () => {
selectedModel = {
id: "chat-model",
supported_endpoints: [],
}
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(createPayload()),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("chat")
expect(handleWithMessagesApi).not.toHaveBeenCalled()
expect(handleWithResponsesApi).not.toHaveBeenCalled()
expect(handleWithChatCompletions).toHaveBeenCalledTimes(1)
})
test("applies warmup model override and passes request metadata to the selected flow", async () => {
selectedModel = {
id: "messages-model",
supported_endpoints: ["/v1/messages"],
}
const payload = createPayload({
messages: [
{
role: "user",
content: [
{
type: "text",
text: '<system-reminder>__SUBAGENT_MARKER__{"session_id":"sub-session","agent_id":"agent-1","agent_type":"Explore"}</system-reminder>',
},
{
type: "text",
text: "hello",
},
],
},
],
})
const app = createApp()
const response = await app.request("/", {
method: "POST",
headers: {
"content-type": "application/json",
"anthropic-beta": "warmup-beta",
"x-session-id": "session-123",
},
body: JSON.stringify(payload),
})
expect(response.status).toBe(200)
expect(await response.text()).toBe("messages")
expect(findEndpointModel).toHaveBeenCalledWith("small-model")
const expectedSessionId = actualUtilsModule.getUUID("session-123")
const expectedRequestId = actualUtilsModule.generateRequestIdFromPayload(
payload,
expectedSessionId,
)
const options = handleWithMessagesApi.mock.calls[0][2]
expect(options.requestId).toBe(expectedRequestId)
expect(options.sessionId).toBe(expectedSessionId)
expect(options.subagentMarker).toEqual({
session_id: "sub-session",
agent_id: "agent-1",
agent_type: "Explore",
})
expect(options.anthropicBetaHeader).toBe("warmup-beta")
})
})