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 }], }); }