Skip to content

Commit c2a6d10

Browse files
committed
fix(opencode-go): send conversation session header
1 parent d033a14 commit c2a6d10

2 files changed

Lines changed: 43 additions & 4 deletions

File tree

‎src/api/providers/__tests__/opencode-go.spec.ts‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
import { OpencodeGoHandler } from "../opencode-go"
2323
import { getModels } from "../fetchers/modelCache"
2424
import { ApiHandlerOptions } from "../../../shared/api"
25+
import { Package } from "../../../shared/package"
2526
import { asyncStreamFrom, collectStream } from "../../../test-utils/stream"
2627
import { clearAllMocks } from "../../../test-utils/reset"
2728

@@ -94,6 +95,7 @@ describe("OpencodeGoHandler", () => {
9495
expect.objectContaining({
9596
baseURL: "https://opencode.ai/zen/go/v1",
9697
apiKey: "test-key",
98+
defaultHeaders: expect.objectContaining({ "User-Agent": `ZooCode/${Package.version}` }),
9799
}),
98100
)
99101
})
@@ -106,6 +108,7 @@ describe("OpencodeGoHandler", () => {
106108
// NOT include the trailing `/v1` used by the OpenAI client.
107109
baseURL: "https://opencode.ai/zen/go",
108110
apiKey: "test-key",
111+
defaultHeaders: expect.objectContaining({ "User-Agent": `ZooCode/${Package.version}` }),
109112
}),
110113
)
111114
})
@@ -208,6 +211,17 @@ describe("OpencodeGoHandler", () => {
208211
)
209212
})
210213

214+
it("sends the stable conversation ID to chat completions", async () => {
215+
const handler = new OpencodeGoHandler(mockOptions)
216+
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hi" }]
217+
218+
await collectStream(handler.createMessage("sys", messages, { taskId: "conversation-123" }))
219+
220+
expect(mockCreate.mock.calls[0][1]?.headers).toMatchObject({
221+
"x-opencode-session": "conversation-123",
222+
})
223+
})
224+
211225
it("forwards the model's default reasoning_effort for reasoning-capable models", async () => {
212226
const handler = new OpencodeGoHandler(mockOptions)
213227
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hi" }]
@@ -478,6 +492,17 @@ describe("OpencodeGoHandler", () => {
478492
expect(mockCreate).not.toHaveBeenCalled()
479493
})
480494

495+
it("sends the stable conversation ID to the Anthropic messages endpoint", async () => {
496+
const handler = new OpencodeGoHandler(anthropicOptions)
497+
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hi" }]
498+
499+
await collectStream(handler.createMessage("sys", messages, { taskId: "conversation-123" }))
500+
501+
expect(mockAnthropicCreate.mock.calls[0][1]?.headers).toMatchObject({
502+
"x-opencode-session": "conversation-123",
503+
})
504+
})
505+
481506
it("streams text, tool-call, usage and cost chunks from the Anthropic stream", async () => {
482507
const handler = new OpencodeGoHandler(anthropicOptions)
483508
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hi" }]
@@ -845,7 +870,10 @@ describe("OpencodeGoHandler", () => {
845870
handler.createMessage("sys", messages, { taskId: "test-task", abortSignal: controller.signal }),
846871
)
847872

848-
expect(mockResponsesCreate.mock.calls[0][1]).toEqual({ signal: controller.signal })
873+
expect(mockResponsesCreate.mock.calls[0][1]).toEqual({
874+
signal: controller.signal,
875+
headers: { "x-opencode-session": "test-task" },
876+
})
849877
})
850878

851879
it("closes the Responses iterator when the consumer stops early", async () => {

‎src/api/providers/opencode-go.ts‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,11 @@ export class OpencodeGoHandler extends RouterProvider implements SingleCompletio
247247
}),
248248
}
249249

250-
const completion = await this.client.chat.completions.create(body)
250+
const completion = metadata?.taskId
251+
? await this.client.chat.completions.create(body, {
252+
headers: { "x-opencode-session": metadata.taskId },
253+
})
254+
: await this.client.chat.completions.create(body)
251255

252256
for await (const chunk of completion) {
253257
const delta = chunk.choices[0]?.delta
@@ -378,7 +382,10 @@ export class OpencodeGoHandler extends RouterProvider implements SingleCompletio
378382

379383
let stream: AsyncIterable<OpenAI.Responses.ResponseStreamEvent>
380384
try {
381-
stream = await this.client.responses.create(requestBody, { signal: metadata?.abortSignal })
385+
stream = await this.client.responses.create(requestBody, {
386+
signal: metadata?.abortSignal,
387+
headers: metadata?.taskId ? { "x-opencode-session": metadata.taskId } : undefined,
388+
})
382389
} catch (error) {
383390
if (error instanceof Error) {
384391
throw new Error(`Opencode Go completion error: ${error.message}`)
@@ -505,7 +512,11 @@ export class OpencodeGoHandler extends RouterProvider implements SingleCompletio
505512
// errors propagate unchanged, matching the OpenAI streaming path.
506513
let stream
507514
try {
508-
stream = await this.anthropicClient.messages.create(requestParams)
515+
stream = metadata?.taskId
516+
? await this.anthropicClient.messages.create(requestParams, {
517+
headers: { "x-opencode-session": metadata.taskId },
518+
})
519+
: await this.anthropicClient.messages.create(requestParams)
509520
} catch (error) {
510521
if (error instanceof Error) {
511522
throw new Error(`Opencode Go completion error: ${error.message}`)

0 commit comments

Comments
 (0)