77 lines
2.4 KiB
TypeScript
77 lines
2.4 KiB
TypeScript
import { createOpenAI } from "@ai-sdk/openai";
|
|
import { streamText, tool } from "ai";
|
|
import { z } from "zod";
|
|
import type { ConversationMessage } from "./types.js";
|
|
import { config } from "../../config.js";
|
|
|
|
const SYSTEM_PROMPT = `You are the GrowQR conversation agent.
|
|
Keep answers concise, practical, and focused on the user's goals.
|
|
When you learn durable information, call the memory tools. For now these tools
|
|
are intentionally stubbed so this actor can stay isolated and unwired.`;
|
|
|
|
function normalizeModel(model: string): string {
|
|
if (config.llmProvider === "opencode" && model.startsWith("opencode/")) {
|
|
return model.slice("opencode/".length);
|
|
}
|
|
return model;
|
|
}
|
|
|
|
const conversationProvider = createOpenAI({
|
|
apiKey: config.llmApiKey,
|
|
baseURL: config.llmBaseUrl.replace(/\/$/, ""),
|
|
name: config.llmProvider,
|
|
});
|
|
|
|
export function getConversationModel() {
|
|
const modelId = process.env.CONVERSATION_ACTOR_MODEL ?? config.agentModel;
|
|
if (!config.llmApiKey) {
|
|
throw new Error("Missing LLM_API_KEY/OPENCODE_API_KEY for conversation streaming.");
|
|
}
|
|
|
|
return conversationProvider.chat(normalizeModel(modelId));
|
|
}
|
|
|
|
export function buildModelMessages(messages: ConversationMessage[]) {
|
|
return messages.map((message) => ({
|
|
role: message.role,
|
|
content: message.content,
|
|
}));
|
|
}
|
|
|
|
export function streamConversationResponse(messages: ConversationMessage[]) {
|
|
return streamText({
|
|
model: getConversationModel(),
|
|
system: SYSTEM_PROMPT,
|
|
messages: buildModelMessages(messages),
|
|
tools: {
|
|
readMemory: tool({
|
|
description: "Read a markdown memory file. Stubbed until memoryActor is wired.",
|
|
inputSchema: z.object({
|
|
path: z.string().describe("Memory path, e.g. /profile.md"),
|
|
}),
|
|
execute: async ({ path }) => ({
|
|
path,
|
|
found: false,
|
|
content: "",
|
|
note: "memoryActor is not wired yet",
|
|
}),
|
|
}),
|
|
writeMemory: tool({
|
|
description: "Write a markdown memory file. Stubbed until memoryActor is wired.",
|
|
inputSchema: z.object({
|
|
path: z.string(),
|
|
contentMd: z.string(),
|
|
reason: z.string().optional(),
|
|
}),
|
|
execute: async ({ path, contentMd, reason }) => ({
|
|
path,
|
|
bytes: contentMd.length,
|
|
reason,
|
|
saved: false,
|
|
note: "memoryActor is not wired yet",
|
|
}),
|
|
}),
|
|
},
|
|
});
|
|
}
|