From b35c5fc98577b77d8d67d298c6254e0cd138c9d5 Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:05:36 -0500 Subject: [PATCH] fix(core): detect copilot PDF input support (#41854) --- packages/core/src/github-copilot/models.ts | 8 +++++- .../core/test/github-copilot/models.test.ts | 28 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/core/src/github-copilot/models.ts b/packages/core/src/github-copilot/models.ts index 34dfe2e4cc8..e401f20f4ef 100644 --- a/packages/core/src/github-copilot/models.ts +++ b/packages/core/src/github-copilot/models.ts @@ -126,6 +126,12 @@ function build(id: Model.ID, remote: UsableModel, baseURL: string, previous?: Mo const image = (remote.capabilities.supports.vision ?? false) || (remote.capabilities.limits.vision?.supported_media_types ?? []).some((item) => item.startsWith("image/")) + const pdf = + (remote.capabilities.supports.vision ?? false) && + (remote.capabilities.limits.vision?.supported_media_types.includes("application/pdf") ?? false) + const input = ["text"] + if (image) input.push("image") + if (pdf) input.push("pdf") const prices = remote.billing?.token_prices // Copilot reports AIC per billing batch; OpenCode stores USD per million tokens. const usdPerMillion = prices && prices.batch_size > 0 ? 10_000 / prices.batch_size : 0 @@ -150,7 +156,7 @@ function build(id: Model.ID, remote: UsableModel, baseURL: string, previous?: Mo body: previous?.body, capabilities: { tools: remote.capabilities.supports.tool_calls, - input: image ? ["text", "image"] : ["text"], + input, output: ["text"], }, variants: variants(remote, messages), diff --git a/packages/core/test/github-copilot/models.test.ts b/packages/core/test/github-copilot/models.test.ts index cba3001d691..0a7dceffaba 100644 --- a/packages/core/test/github-copilot/models.test.ts +++ b/packages/core/test/github-copilot/models.test.ts @@ -27,8 +27,32 @@ test("defensively syncs advertised Copilot models", async () => { max_context_window_tokens: 200000, max_output_tokens: 16384, max_prompt_tokens: 180000, + vision: { + max_prompt_image_size: 10000000, + max_prompt_images: 10, + supported_media_types: ["image/png", "application/pdf"], + }, }, - supports: { tool_calls: true, reasoning_effort: ["low", "high"] }, + supports: { tool_calls: true, vision: true, reasoning_effort: ["low", "high"] }, + }, + }, + { + model_picker_enabled: true, + id: "vision-only", + name: "Vision only", + version: "vision-only-2026-06-01", + capabilities: { + family: "vision", + limits: { + max_output_tokens: 16384, + max_prompt_tokens: 180000, + vision: { + max_prompt_image_size: 10000000, + max_prompt_images: 10, + supported_media_types: ["image/png"], + }, + }, + supports: { tool_calls: true, vision: true }, }, }, { @@ -67,6 +91,8 @@ test("defensively syncs advertised Copilot models", async () => { Model.VariantID.make("low"), Model.VariantID.make("high"), ]) + expect(model?.capabilities.input).toEqual(["text", "image", "pdf"]) + expect(models.get(Model.ID.make("vision-only"))?.capabilities.input).toEqual(["text", "image"]) expect(models.get(Model.ID.make("utility"))?.enabled).toBe(false) expect(models.has(Model.ID.make("stale"))).toBe(false) expect(models.has(Model.ID.make("incomplete"))).toBe(false)