1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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" });
}
}
}
|