Skip to content

Commit b5a48a8

Browse files
committed
fix(provider): omit empty Copilot tool descriptions to prevent 400s
1 parent d1938a4 commit b5a48a8

File tree

2 files changed

+30
-22
lines changed

2 files changed

+30
-22
lines changed

packages/opencode/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export function prepareTools({
5050
type: "function",
5151
function: {
5252
name: tool.name,
53-
description: tool.description,
53+
description: tool.description?.trim() ? tool.description : undefined,
5454
parameters: tool.inputSchema,
5555
},
5656
})

packages/opencode/test/provider/copilot/copilot-chat-model.test.ts

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { OpenAICompatibleChatLanguageModel } from "@/provider/sdk/copilot/chat/openai-compatible-chat-language-model"
22
import { describe, test, expect, mock } from "bun:test"
3-
import type { LanguageModelV2Prompt } from "@ai-sdk/provider"
3+
import type { JSONSchema7, LanguageModelV2Prompt } from "@ai-sdk/provider"
44

55
async function convertReadableStreamToArray<T>(stream: ReadableStream<T>): Promise<T[]> {
66
const reader = stream.getReader()
@@ -536,10 +536,18 @@ describe("doStream", () => {
536536
})
537537

538538
describe("request body", () => {
539-
test("should send tools in OpenAI format", async () => {
540-
let capturedBody: unknown
539+
const inputSchema: JSONSchema7 = {
540+
type: "object",
541+
properties: {
542+
location: { type: "string" },
543+
},
544+
required: ["location"],
545+
}
546+
547+
async function tools(description: string) {
548+
let body: { tools: unknown[] } | undefined
541549
const mockFetch = mock(async (_url: string, init?: RequestInit) => {
542-
capturedBody = JSON.parse(init?.body as string)
550+
body = JSON.parse(init?.body as string)
543551
return new Response(
544552
new ReadableStream({
545553
start(controller) {
@@ -552,41 +560,41 @@ describe("request body", () => {
552560
})
553561

554562
const model = createModel(mockFetch)
555-
556563
await model.doStream({
557564
prompt: TEST_PROMPT,
558565
tools: [
559566
{
560567
type: "function",
561568
name: "get_weather",
562-
description: "Get the weather for a location",
563-
inputSchema: {
564-
type: "object",
565-
properties: {
566-
location: { type: "string" },
567-
},
568-
required: ["location"],
569-
},
569+
description,
570+
inputSchema,
570571
},
571572
],
572573
includeRawChunks: false,
573574
})
575+
return body?.tools ?? []
576+
}
574577

575-
expect((capturedBody as { tools: unknown[] }).tools).toEqual([
578+
test("should send tools in OpenAI format", async () => {
579+
expect(await tools("Get the weather for a location")).toEqual([
576580
{
577581
type: "function",
578582
function: {
579583
name: "get_weather",
580584
description: "Get the weather for a location",
581-
parameters: {
582-
type: "object",
583-
properties: {
584-
location: { type: "string" },
585-
},
586-
required: ["location"],
587-
},
585+
parameters: inputSchema,
588586
},
589587
},
590588
])
591589
})
590+
591+
test("should omit function description when it is empty", async () => {
592+
const body = await tools("")
593+
expect((body[0] as { function: { description?: string } })?.function).not.toHaveProperty("description")
594+
})
595+
596+
test("should omit function description when it is whitespace only", async () => {
597+
const body = await tools(" ")
598+
expect((body[0] as { function: { description?: string } })?.function).not.toHaveProperty("description")
599+
})
592600
})

0 commit comments

Comments
 (0)