From 09de81c3446f0c18ea6914e235b4ee3fce7d4cb6 Mon Sep 17 00:00:00 2001 From: "uzqw.lenovo" Date: Sun, 23 Aug 2026 19:00:05 +0800 Subject: [PATCH] fix(runtime): route OpenCode Go Muse Spark through Responses The gateway serves muse-spark-1.2-contributor correctly through the Responses API, while its Chat Completions stream lacks a reliable terminal finish reason. Pin this provider/model pair to Responses instead of weakening the shared truncation guard, and cover both the scoped protocol choice and final request endpoint. Fixes #3548 Generated-by: OpenAI Codex --- .../core/src/__tests__/model-metadata.test.ts | 9 +++++++ packages/core/src/model-metadata.ts | 1 + .../__tests__/responses-wire-contract.test.ts | 26 +++++++++++++++++++ 3 files changed, 36 insertions(+) diff --git a/packages/core/src/__tests__/model-metadata.test.ts b/packages/core/src/__tests__/model-metadata.test.ts index c30c1e2639..9eb6090bf8 100644 --- a/packages/core/src/__tests__/model-metadata.test.ts +++ b/packages/core/src/__tests__/model-metadata.test.ts @@ -95,4 +95,13 @@ describe('openAiAdapterApiProtocol', () => { assert.equal(openAiAdapterApiProtocol('deepseek-v4-pro', 'deepseek'), 'openai-responses'); assert.equal(openAiAdapterApiProtocol('deepseek-chat', 'deepseek'), 'openai-chat'); }); + + it('routes only OpenCode Go Muse Spark through its supported Responses wire', () => { + assert.equal( + openAiAdapterApiProtocol('muse-spark-1.2-contributor', 'opencode-go'), + 'openai-responses', + ); + assert.equal(openAiAdapterApiProtocol('muse-spark-1.2-contributor', 'opencode'), 'openai-chat'); + assert.equal(openAiAdapterApiProtocol('minimax-m3', 'opencode-go'), 'openai-chat'); + }); }); diff --git a/packages/core/src/model-metadata.ts b/packages/core/src/model-metadata.ts index eab94234dd..5d65b8fc4a 100644 --- a/packages/core/src/model-metadata.ts +++ b/packages/core/src/model-metadata.ts @@ -137,6 +137,7 @@ export function openAiAdapterApiProtocol( ): 'openai-responses' | 'openai-chat' { const id = modelId.trim(); return (providerType === 'deepseek' && deepSeekModelSupportsResponses(id)) || + (providerType === 'opencode-go' && id === 'muse-spark-1.2-contributor') || /^gpt-5/i.test(id) || ((providerType === 'xai' || providerType === 'xai-oauth') && id === 'grok-4.5') ? 'openai-responses' diff --git a/packages/runtime/src/__tests__/responses-wire-contract.test.ts b/packages/runtime/src/__tests__/responses-wire-contract.test.ts index d42a28652f..88b6c7b83a 100644 --- a/packages/runtime/src/__tests__/responses-wire-contract.test.ts +++ b/packages/runtime/src/__tests__/responses-wire-contract.test.ts @@ -68,6 +68,32 @@ describe('responses wire contract', () => { ); }); + test('routes OpenCode Go Muse Spark through the Responses endpoint', async () => { + const urls: string[] = []; + const fetch = (async (url: string | URL | Request) => { + urls.push(String(url)); + return Response.json({ + id: 'r', + object: 'response', + status: 'completed', + output: [], + usage: { input_tokens: 1, output_tokens: 1 }, + }); + }) as typeof globalThis.fetch; + const model = getAIModel({ + connection: conn('opencode-go'), + apiKey: '[redacted]', + modelId: 'muse-spark-1.2-contributor', + fetch, + }); + + await model.doGenerate({ + prompt: [{ role: 'user', content: [{ type: 'text', text: 'ping' }] }], + }); + + assert.deepEqual(urls, ['https://opencode.ai/zen/go/v1/responses']); + }); + test('normalizes the upstream Open Responses endpoint exactly once', () => { assert.equal( openResponsesUrl('https://api.deepseek.com/v1'),