summaryrefslogtreecommitdiffhomepage
path: root/packages/api/src/agent-manager.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/api/src/agent-manager.ts')
-rw-r--r--packages/api/src/agent-manager.ts86
1 files changed, 86 insertions, 0 deletions
diff --git a/packages/api/src/agent-manager.ts b/packages/api/src/agent-manager.ts
new file mode 100644
index 0000000..f60b8d3
--- /dev/null
+++ b/packages/api/src/agent-manager.ts
@@ -0,0 +1,86 @@
+import {
+ Agent,
+ type AgentEvent,
+ type AgentStatus,
+ createListFilesTool,
+ createReadFileTool,
+ createWriteFileTool,
+} from "@dispatch/core";
+
+const SYSTEM_PROMPT = `You are Dispatch, a helpful AI coding assistant. You have access to the following tools for working with files in the current working directory:
+
+- read_file: Read the contents of a file
+- write_file: Write content to a file (creates parent directories if needed)
+- list_files: List files and directories
+
+When asked to work with files, use these tools. Always confirm what you did after completing an action. Be concise and helpful.`;
+
+export class AgentManager {
+ private agent: Agent | null = null;
+ private status: AgentStatus = "idle";
+ private messageCount = 0;
+ private eventListeners: Set<(event: AgentEvent) => void> = new Set();
+
+ private getOrCreateAgent(): Agent {
+ if (!this.agent) {
+ const apiKey = process.env.OPENCODE_API_KEY ?? "";
+ const model = process.env.DISPATCH_MODEL ?? "deepseek-v4-flash-free";
+ const workingDirectory = process.env.DISPATCH_WORKING_DIR ?? process.cwd();
+
+ const tools = [
+ createReadFileTool(workingDirectory),
+ createWriteFileTool(workingDirectory),
+ createListFilesTool(workingDirectory),
+ ];
+
+ this.agent = new Agent({
+ model,
+ apiKey,
+ baseURL: "https://opencode.ai/zen/v1",
+ systemPrompt: SYSTEM_PROMPT,
+ tools,
+ workingDirectory,
+ });
+ }
+ return this.agent;
+ }
+
+ getStatus(): AgentStatus {
+ return this.status;
+ }
+
+ getMessageCount(): number {
+ return this.messageCount;
+ }
+
+ onEvent(listener: (event: AgentEvent) => void): () => void {
+ this.eventListeners.add(listener);
+ return () => {
+ this.eventListeners.delete(listener);
+ };
+ }
+
+ private emit(event: AgentEvent): void {
+ for (const listener of this.eventListeners) {
+ listener(event);
+ }
+ }
+
+ async processMessage(message: string): Promise<void> {
+ const agent = this.getOrCreateAgent();
+
+ this.messageCount += 1;
+
+ try {
+ for await (const event of agent.run(message)) {
+ this.status = event.type === "status" ? event.status : this.status;
+ this.emit(event);
+ }
+ } catch (err) {
+ const errorMsg = err instanceof Error ? err.message : String(err);
+ this.status = "error";
+ this.emit({ type: "error", error: errorMsg });
+ this.emit({ type: "status", status: "error" });
+ }
+ }
+}