Skip to content

Commit d417a7c

Browse files
HXYerrorclaude
andcommitted
fix(responses): type fixes + error handling + route tests (#2, #7)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent a36fa09 commit d417a7c

4 files changed

Lines changed: 63 additions & 6 deletions

File tree

src/routes/responses/handler.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import consola from "consola"
55
import type { ResponsesPayload } from "./types"
66

77
export async function handleResponses(c: Context): Promise<Response> {
8-
const payload = await c.req.json<ResponsesPayload>()
9-
consola.debug("Responses API request payload:", JSON.stringify(payload))
8+
try {
9+
const payload = await c.req.json<ResponsesPayload>()
10+
consola.debug("Responses API request payload:", JSON.stringify(payload))
11+
} catch {
12+
consola.debug("Responses API request received (could not parse body)")
13+
}
1014

1115
// TODO(#4): wire up createResponses() service client
12-
// For now return a structured 501 so the route is exercisable
1316
consola.warn(
1417
"POST /v1/responses is not yet implemented — service client pending (#4)",
1518
)

src/routes/responses/types.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface ResponsesPayload {
1313
top_p?: number | null
1414
max_output_tokens?: number | null
1515
reasoning?: {
16-
effort?: "minimal" | "low" | "medium" | "high"
16+
effort?: "low" | "medium" | "high"
1717
summary?: "auto" | "concise" | "detailed"
1818
} | null
1919
previous_response_id?: string | null
@@ -30,6 +30,7 @@ export interface ResponsesPayload {
3030
// Input item types (union)
3131
export type ResponsesInputItem =
3232
| ResponsesInputMessage
33+
| ResponsesInputFunctionCall
3334
| ResponsesFunctionCallOutput
3435
| ResponsesReasoningItem
3536

@@ -41,6 +42,15 @@ export interface ResponsesInputMessage {
4142
status?: "completed" | "incomplete" | null
4243
}
4344

45+
export interface ResponsesInputFunctionCall {
46+
type: "function_call"
47+
id?: string
48+
call_id: string
49+
name: string
50+
arguments: string
51+
status?: "completed" | "in_progress" | "incomplete" | null
52+
}
53+
4454
export interface ResponsesFunctionCallOutput {
4555
type: "function_call_output"
4656
call_id: string
@@ -57,7 +67,12 @@ export interface ResponsesReasoningItem {
5767

5868
export type ResponsesContentPart =
5969
| { type: "input_text"; text: string }
60-
| { type: "input_image"; image_url: string; detail?: "low" | "high" | "auto" }
70+
| {
71+
type: "input_image"
72+
image_url?: string | null
73+
file_id?: string | null
74+
detail?: "low" | "high" | "auto"
75+
}
6176

6277
// Tool types
6378
export interface ResponsesTool {

src/services/copilot/create-chat-completions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export interface ChatCompletionsPayload {
150150
| { type: "function"; function: { name: string } }
151151
| null
152152
user?: string | null
153-
reasoning_effort?: "minimal" | "low" | "medium" | "high" | null
153+
reasoning_effort?: "low" | "medium" | "high" | null
154154
}
155155

156156
export interface Tool {

tests/responses-route.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { describe, test, expect } from "bun:test"
2+
3+
import { server } from "../src/server"
4+
5+
describe("POST /v1/responses stub", () => {
6+
test("returns 501 with structured error body", async () => {
7+
const res = await server.request("/v1/responses", {
8+
method: "POST",
9+
headers: { "Content-Type": "application/json" },
10+
body: JSON.stringify({ model: "gpt-4o", input: [] }),
11+
})
12+
expect(res.status).toBe(501)
13+
const body = (await res.json()) as {
14+
error: { type: string; code: string; message: string }
15+
}
16+
expect(body.error.type).toBe("not_implemented")
17+
expect(body.error.code).toBe("responses_not_implemented")
18+
expect(typeof body.error.message).toBe("string")
19+
})
20+
21+
test("bare /responses path also returns 501", async () => {
22+
const res = await server.request("/responses", {
23+
method: "POST",
24+
headers: { "Content-Type": "application/json" },
25+
body: JSON.stringify({ model: "gpt-4o", input: [] }),
26+
})
27+
expect(res.status).toBe(501)
28+
const body = (await res.json()) as { error: { code: string } }
29+
expect(body.error.code).toBe("responses_not_implemented")
30+
})
31+
32+
test("empty body returns 501 (not 500)", async () => {
33+
const res = await server.request("/v1/responses", {
34+
method: "POST",
35+
// no body
36+
})
37+
expect(res.status).toBe(501)
38+
})
39+
})

0 commit comments

Comments
 (0)