From 61b10189006d70e22d392b02f2b72837f71fd209 Mon Sep 17 00:00:00 2001 From: Huarch Date: Wed, 13 May 2026 18:12:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A8=A1=E5=9E=8B=E6=94=AF?= =?UTF-8?q?=E6=8C=81=EF=BC=8C=E6=9B=B4=E6=96=B0=E6=8F=90=E7=A4=BA=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E4=BB=A5=E6=8E=A5=E6=94=B6=E6=A8=A1=E5=9E=8B=E5=8F=82?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/chat.ts | 28 +++++++++++++++++++++++++++- src/runtime/opencode.ts | 8 +++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/routes/chat.ts b/src/routes/chat.ts index 8896fd7..60b1931 100644 --- a/src/routes/chat.ts +++ b/src/routes/chat.ts @@ -8,9 +8,17 @@ import { type OpencodeRuntimeAdapter } from "../runtime/opencode.js"; import { type ChatSessionBridge } from "../chat/sessionBridge.js"; import { writeLlmRequestAuditLog } from "../audit/llmRequestAudit.js"; +const supportedModels = [ + "deepseek/deepseek-v4-flash", + "deepseek/deepseek-v4-pro", +] as const; + +type SupportedModel = (typeof supportedModels)[number]; + const payloadSchema = z.object({ message: z.string().min(1).max(10000), session_id: z.string().max(128).optional(), + model: z.enum(supportedModels).optional(), }); const abortPayloadSchema = z.object({ @@ -169,6 +177,7 @@ export const buildChatRouter = ( clientSessionId: requestContext.clientSessionId, sessionId: binding.sessionId, created, + model: parsed.data.model, traceId: requestContext.traceId, projectId: requestContext.projectId, }, @@ -207,6 +216,7 @@ export const buildChatRouter = ( opencodeSessionId: binding.sessionId, clientSessionId, message: preparedMessage, + model: parsed.data.model, traceId: requestContext.traceId, projectId: requestContext.projectId, signal: abortController.signal, @@ -329,11 +339,26 @@ const extractSkillAuditInfo = (event: OpencodeEvent) => { const hasToolParams = (params: Record) => Object.keys(params).length > 0; +const toRuntimeModel = (model?: SupportedModel) => { + if (!model) { + return undefined; + } + const [providerID, modelID] = model.split("/"); + if (!providerID || !modelID) { + return undefined; + } + return { + providerID, + modelID, + }; +}; + type StreamPromptOptions = { runtime: OpencodeRuntimeAdapter; opencodeSessionId: string; clientSessionId: string; message: string; + model?: SupportedModel; traceId?: string; projectId?: string; signal?: AbortSignal; @@ -355,6 +380,7 @@ const streamPromptResponse = async ({ opencodeSessionId, clientSessionId, message, + model, traceId, projectId, signal, @@ -437,7 +463,7 @@ const streamPromptResponse = async ({ }); const promptPromise = runtime - .prompt(opencodeSessionId, message) + .prompt(opencodeSessionId, message, toRuntimeModel(model)) .then(() => { promptSettled = true; }) diff --git a/src/runtime/opencode.ts b/src/runtime/opencode.ts index f83bdd6..b4b17b3 100644 --- a/src/runtime/opencode.ts +++ b/src/runtime/opencode.ts @@ -12,6 +12,11 @@ export type RuntimeHealth = { version: string; }; +type RuntimeModelOverride = { + providerID: string; + modelID: string; +}; + export class OpencodeRuntimeAdapter { private clientPromise: Promise | null = null; private closeServer: (() => void) | null = null; @@ -52,10 +57,11 @@ export class OpencodeRuntimeAdapter { return this.messages(sessionId); } - async prompt(sessionId: string, text: string) { + async prompt(sessionId: string, text: string, model?: RuntimeModelOverride) { const client = await this.ensureClient(); await client.session.prompt({ sessionID: sessionId, + model, parts: [{ type: "text", text }], }); }