@gonzih/cc-agent 0.14.7 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,356 @@
1
+ /**
2
+ * OpenAICompatibleDriver — embedded agentic loop for any OpenAI-API-compatible model.
3
+ *
4
+ * Supports: OpenAI, Qwen, Kimi, DeepSeek, Pi, and any other provider with an
5
+ * OpenAI-compatible /v1/chat/completions endpoint.
6
+ *
7
+ * The driver runs a tool-call loop inside cc-agent itself:
8
+ * 1. Call model API with messages + tool definitions
9
+ * 2. If model calls a tool → execute in cwd → append result → continue
10
+ * 3. If model returns text → emit as text events
11
+ * 4. If model outputs TASK_COMPLETE → terminate loop
12
+ * 5. Track token usage → emit usage events
13
+ *
14
+ * Security: tool execution has a 30s timeout; output is truncated to 8000 chars.
15
+ * Max 50 iterations to prevent runaway loops.
16
+ */
17
+ import { execFile } from "child_process";
18
+ import { promisify } from "util";
19
+ import { writeFile, readFile, readdir } from "fs/promises";
20
+ import { isAbsolute, resolve, relative } from "path";
21
+ import { existsSync } from "fs";
22
+ import { getPricing } from "./pricing.js";
23
+ import { BaseAgentProcess } from "./types.js";
24
+ const execFileAsync = promisify(execFile);
25
+ const TOOL_TIMEOUT_MS = 30_000;
26
+ const MAX_ITERATIONS = 50;
27
+ const OUTPUT_MAX_CHARS = 8_000;
28
+ // ── Driver name → (env key, default base URL) ──────────────────────────────
29
+ const DRIVER_CONFIG = {
30
+ qwen: { envKey: "QWEN_API_KEY", baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1" },
31
+ kimi: { envKey: "KIMI_API_KEY", baseUrl: "https://api.moonshot.cn/v1" },
32
+ deepseek: { envKey: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com/v1" },
33
+ pi: { envKey: "PI_API_KEY", baseUrl: "https://api.inflection.ai/v1" },
34
+ openai: { envKey: "OPENAI_API_KEY", baseUrl: "https://api.openai.com/v1" },
35
+ "openai-compatible": { envKey: "OPENAI_API_KEY", baseUrl: "https://api.openai.com/v1" },
36
+ };
37
+ const DEFAULT_MODELS = {
38
+ qwen: "qwen2.5-72b-instruct",
39
+ kimi: "kimi-k2",
40
+ deepseek: "deepseek-v3",
41
+ pi: "inflection_3_productivity",
42
+ openai: "gpt-4o",
43
+ "openai-compatible": "gpt-4o",
44
+ };
45
+ const SYSTEM_PROMPT = `You are an autonomous coding agent. You have access to the following tools to complete tasks in a working directory:
46
+ - bash(command): Run any shell command. Returns stdout+stderr.
47
+ - write_file(path, content): Write content to a file (creates directories as needed).
48
+ - read_file(path): Read a file's content.
49
+ - list_files(path): List files in a directory.
50
+
51
+ Complete the given task autonomously. When you have fully completed the task, output exactly: TASK_COMPLETE
52
+
53
+ Rules:
54
+ - Work only within the provided working directory
55
+ - Do not read files outside the working directory
56
+ - After completing all work, output TASK_COMPLETE on its own line`;
57
+ const TOOL_DEFINITIONS = [
58
+ {
59
+ type: "function",
60
+ function: {
61
+ name: "bash",
62
+ description: "Run a shell command in the working directory. Returns stdout and stderr.",
63
+ parameters: {
64
+ type: "object",
65
+ properties: {
66
+ command: { type: "string", description: "Shell command to execute" },
67
+ },
68
+ required: ["command"],
69
+ },
70
+ },
71
+ },
72
+ {
73
+ type: "function",
74
+ function: {
75
+ name: "write_file",
76
+ description: "Write content to a file path relative to the working directory.",
77
+ parameters: {
78
+ type: "object",
79
+ properties: {
80
+ path: { type: "string", description: "File path (relative to working directory)" },
81
+ content: { type: "string", description: "File content to write" },
82
+ },
83
+ required: ["path", "content"],
84
+ },
85
+ },
86
+ },
87
+ {
88
+ type: "function",
89
+ function: {
90
+ name: "read_file",
91
+ description: "Read the content of a file.",
92
+ parameters: {
93
+ type: "object",
94
+ properties: {
95
+ path: { type: "string", description: "File path (relative to working directory)" },
96
+ },
97
+ required: ["path"],
98
+ },
99
+ },
100
+ },
101
+ {
102
+ type: "function",
103
+ function: {
104
+ name: "list_files",
105
+ description: "List files and directories at a path.",
106
+ parameters: {
107
+ type: "object",
108
+ properties: {
109
+ path: { type: "string", description: "Directory path (relative to working directory, default '.')" },
110
+ },
111
+ },
112
+ },
113
+ },
114
+ ];
115
+ export class OpenAICompatibleDriver {
116
+ name;
117
+ constructor(name) {
118
+ this.name = name;
119
+ }
120
+ resolveBinary() {
121
+ return ""; // no binary — uses HTTP API
122
+ }
123
+ hasSession(_cwd) {
124
+ return false; // no persistent session for API agents
125
+ }
126
+ spawn(options) {
127
+ const emitter = new BaseAgentProcess();
128
+ let killed = false;
129
+ emitter.kill = (_signal) => {
130
+ killed = true;
131
+ };
132
+ (async () => {
133
+ try {
134
+ await this.runLoop(options, emitter, () => killed);
135
+ }
136
+ catch (err) {
137
+ emitter.emit("text", `[${this.name}] Fatal error: ${String(err)}`);
138
+ emitter.emit("exit", 1);
139
+ }
140
+ })();
141
+ return emitter;
142
+ }
143
+ resolveApiKey(options) {
144
+ // Per-call override takes highest precedence
145
+ if (options.env?.OPENAI_API_KEY)
146
+ return options.env.OPENAI_API_KEY;
147
+ if (options.token)
148
+ return options.token;
149
+ const cfg = DRIVER_CONFIG[this.name] ?? DRIVER_CONFIG.openai;
150
+ const fromEnv = process.env[cfg.envKey] ?? process.env.OPENAI_API_KEY;
151
+ if (fromEnv)
152
+ return fromEnv;
153
+ throw new Error(`No API key found for driver '${this.name}'. ` +
154
+ `Set ${cfg.envKey} or OPENAI_API_KEY environment variable.`);
155
+ }
156
+ resolveBaseUrl(options) {
157
+ if (options.env?.OPENAI_BASE_URL)
158
+ return options.env.OPENAI_BASE_URL.replace(/\/$/, "");
159
+ const fromEnv = process.env.OPENAI_BASE_URL;
160
+ if (fromEnv)
161
+ return fromEnv.replace(/\/$/, "");
162
+ const cfg = DRIVER_CONFIG[this.name] ?? DRIVER_CONFIG.openai;
163
+ return cfg.baseUrl;
164
+ }
165
+ resolveModel(options) {
166
+ if (options.model)
167
+ return options.model;
168
+ return DEFAULT_MODELS[this.name] ?? "gpt-4o";
169
+ }
170
+ /** Resolve a user-provided path safely within cwd. */
171
+ safePath(cwd, userPath) {
172
+ const p = isAbsolute(userPath) ? userPath : resolve(cwd, userPath);
173
+ // Ensure path is within cwd
174
+ const rel = relative(cwd, p);
175
+ if (rel.startsWith("..") || isAbsolute(rel)) {
176
+ throw new Error(`Path '${userPath}' is outside the working directory`);
177
+ }
178
+ return p;
179
+ }
180
+ async executeTool(cwd, toolName, args) {
181
+ if (toolName === "bash") {
182
+ const command = String(args.command ?? "");
183
+ if (!command.trim())
184
+ return "(empty command)";
185
+ try {
186
+ const { stdout, stderr } = await execFileAsync("sh", ["-c", command], {
187
+ cwd,
188
+ timeout: TOOL_TIMEOUT_MS,
189
+ maxBuffer: 1024 * 1024, // 1MB
190
+ });
191
+ const combined = (stdout + (stderr ? `\nSTDERR:\n${stderr}` : "")).trim();
192
+ return combined.slice(0, OUTPUT_MAX_CHARS) + (combined.length > OUTPUT_MAX_CHARS ? "\n[output truncated]" : "");
193
+ }
194
+ catch (err) {
195
+ const e = err;
196
+ if (e.killed)
197
+ return `[error] Command timed out after ${TOOL_TIMEOUT_MS / 1000}s`;
198
+ const out = ((e.stdout ?? "") + (e.stderr ? `\nSTDERR:\n${e.stderr}` : "")).trim();
199
+ return (out || String(e.message ?? err)).slice(0, OUTPUT_MAX_CHARS);
200
+ }
201
+ }
202
+ if (toolName === "write_file") {
203
+ const path = this.safePath(cwd, String(args.path ?? ""));
204
+ const content = String(args.content ?? "");
205
+ // Create parent directories if needed
206
+ const { mkdir } = await import("fs/promises");
207
+ const { dirname } = await import("path");
208
+ await mkdir(dirname(path), { recursive: true });
209
+ await writeFile(path, content, "utf-8");
210
+ return `Wrote ${content.length} bytes to ${args.path}`;
211
+ }
212
+ if (toolName === "read_file") {
213
+ const path = this.safePath(cwd, String(args.path ?? ""));
214
+ if (!existsSync(path))
215
+ return `File not found: ${args.path}`;
216
+ const content = await readFile(path, "utf-8");
217
+ return content.slice(0, OUTPUT_MAX_CHARS) + (content.length > OUTPUT_MAX_CHARS ? "\n[truncated]" : "");
218
+ }
219
+ if (toolName === "list_files") {
220
+ const dirPath = this.safePath(cwd, String(args.path ?? "."));
221
+ try {
222
+ const entries = await readdir(dirPath, { withFileTypes: true });
223
+ return entries
224
+ .map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`)
225
+ .join("\n");
226
+ }
227
+ catch (err) {
228
+ return `Error listing directory: ${String(err)}`;
229
+ }
230
+ }
231
+ return `Unknown tool: ${toolName}`;
232
+ }
233
+ async runLoop(options, emitter, isKilled) {
234
+ const apiKey = this.resolveApiKey(options);
235
+ const baseUrl = this.resolveBaseUrl(options);
236
+ const model = this.resolveModel(options);
237
+ const messages = [
238
+ { role: "system", content: SYSTEM_PROMPT },
239
+ { role: "user", content: `Working directory: ${options.cwd}\n\nTask:\n${options.task}` },
240
+ ];
241
+ emitter.emit("text", `[${this.name}] Starting with model ${model} at ${baseUrl}`);
242
+ for (let iter = 0; iter < MAX_ITERATIONS; iter++) {
243
+ if (isKilled()) {
244
+ emitter.emit("exit", null);
245
+ return;
246
+ }
247
+ // Call the API
248
+ let response;
249
+ try {
250
+ const res = await fetch(`${baseUrl}/chat/completions`, {
251
+ method: "POST",
252
+ headers: {
253
+ "Content-Type": "application/json",
254
+ "Authorization": `Bearer ${apiKey}`,
255
+ },
256
+ body: JSON.stringify({
257
+ model,
258
+ messages,
259
+ tools: TOOL_DEFINITIONS,
260
+ tool_choice: "auto",
261
+ max_tokens: 4096,
262
+ }),
263
+ signal: AbortSignal.timeout(120_000), // 2 minute HTTP timeout
264
+ });
265
+ if (!res.ok) {
266
+ const body = await res.text().catch(() => "");
267
+ throw new Error(`API error ${res.status}: ${body.slice(0, 500)}`);
268
+ }
269
+ response = await res.json();
270
+ }
271
+ catch (err) {
272
+ emitter.emit("text", `[${this.name}] API error: ${String(err)}`);
273
+ emitter.emit("exit", 1);
274
+ return;
275
+ }
276
+ // Emit usage if available
277
+ if (response.usage) {
278
+ const u = {
279
+ inputTokens: response.usage.prompt_tokens ?? 0,
280
+ outputTokens: response.usage.completion_tokens ?? 0,
281
+ };
282
+ emitter.emit("usage", u);
283
+ }
284
+ const choice = response.choices[0];
285
+ if (!choice) {
286
+ emitter.emit("text", `[${this.name}] Empty response from API`);
287
+ emitter.emit("exit", 1);
288
+ return;
289
+ }
290
+ const msg = choice.message;
291
+ // Emit any text content
292
+ if (msg.content) {
293
+ emitter.emit("text", msg.content);
294
+ if (/TASK_COMPLETE/i.test(msg.content)) {
295
+ emitter.emit("exit", 0);
296
+ return;
297
+ }
298
+ }
299
+ // Handle tool calls
300
+ if (msg.tool_calls && msg.tool_calls.length > 0) {
301
+ // Add assistant message with tool calls to history
302
+ messages.push({
303
+ role: "assistant",
304
+ content: msg.content ?? null,
305
+ tool_calls: msg.tool_calls,
306
+ });
307
+ for (const tc of msg.tool_calls) {
308
+ if (isKilled()) {
309
+ emitter.emit("exit", null);
310
+ return;
311
+ }
312
+ const toolName = tc.function.name;
313
+ let toolArgs = {};
314
+ try {
315
+ toolArgs = JSON.parse(tc.function.arguments);
316
+ }
317
+ catch {
318
+ toolArgs = {};
319
+ }
320
+ emitter.emit("tool", toolName);
321
+ let toolResult;
322
+ try {
323
+ toolResult = await this.executeTool(options.cwd, toolName, toolArgs);
324
+ }
325
+ catch (err) {
326
+ toolResult = `Tool error: ${String(err)}`;
327
+ }
328
+ messages.push({
329
+ role: "tool",
330
+ content: toolResult,
331
+ tool_call_id: tc.id,
332
+ });
333
+ }
334
+ // Continue the loop to let the model react to tool results
335
+ continue;
336
+ }
337
+ // finish_reason === "stop" with no tool calls — model is done
338
+ if (choice.finish_reason === "stop" || !msg.tool_calls) {
339
+ emitter.emit("exit", 0);
340
+ return;
341
+ }
342
+ }
343
+ emitter.emit("text", `[${this.name}] Max iterations (${MAX_ITERATIONS}) reached`);
344
+ emitter.emit("exit", 1);
345
+ }
346
+ estimateCost(usage, model) {
347
+ if (usage.costUsd != null)
348
+ return usage.costUsd;
349
+ const pricing = getPricing(model ?? DEFAULT_MODELS[this.name] ?? "gpt-4o");
350
+ const cost = (usage.inputTokens * pricing.inputPer1M +
351
+ usage.outputTokens * pricing.outputPer1M) /
352
+ 1_000_000;
353
+ return Math.round(cost * 10000) / 10000;
354
+ }
355
+ }
356
+ //# sourceMappingURL=openai-compatible.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compatible.js","sourceRoot":"","sources":["../../src/drivers/openai-compatible.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { AgentPricing } from "./types.js";
2
+ /**
3
+ * Return pricing for a model. Falls back to DEFAULT_PRICING for unknown models.
4
+ * Performs prefix matching so version-suffixed names resolve to the base model.
5
+ */
6
+ export declare function getPricing(model: string): AgentPricing;
7
+ //# sourceMappingURL=pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/drivers/pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAoD/C;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAYtD"}
@@ -0,0 +1,62 @@
1
+ /** Model pricing registry (USD per 1M tokens). */
2
+ const PRICING = {
3
+ // ── Claude models ────────────────────────────────────────────────────────
4
+ "claude-haiku-4-5": { inputPer1M: 0.80, outputPer1M: 4.00, cacheReadPer1M: 0.08, cacheWritePer1M: 1.00 },
5
+ "claude-haiku-4-5-20251001": { inputPer1M: 0.80, outputPer1M: 4.00, cacheReadPer1M: 0.08, cacheWritePer1M: 1.00 },
6
+ "claude-sonnet-4-5": { inputPer1M: 3.00, outputPer1M: 15.00, cacheReadPer1M: 0.30, cacheWritePer1M: 3.75 },
7
+ "claude-sonnet-4-5-20251101": { inputPer1M: 3.00, outputPer1M: 15.00, cacheReadPer1M: 0.30, cacheWritePer1M: 3.75 },
8
+ "claude-sonnet-4-6": { inputPer1M: 3.00, outputPer1M: 15.00, cacheReadPer1M: 0.30, cacheWritePer1M: 3.75 },
9
+ "claude-opus-4-6": { inputPer1M: 15.00, outputPer1M: 75.00, cacheReadPer1M: 1.50, cacheWritePer1M: 18.75 },
10
+ "claude-opus-4-5": { inputPer1M: 15.00, outputPer1M: 75.00, cacheReadPer1M: 1.50, cacheWritePer1M: 18.75 },
11
+ "claude-3-opus-20240229": { inputPer1M: 15.00, outputPer1M: 75.00, cacheReadPer1M: 1.50, cacheWritePer1M: 18.75 },
12
+ "claude-3-5-sonnet-20241022": { inputPer1M: 3.00, outputPer1M: 15.00, cacheReadPer1M: 0.30, cacheWritePer1M: 3.75 },
13
+ "claude-3-5-haiku-20241022": { inputPer1M: 0.80, outputPer1M: 4.00, cacheReadPer1M: 0.08, cacheWritePer1M: 1.00 },
14
+ // ── OpenAI models ────────────────────────────────────────────────────────
15
+ "gpt-4o": { inputPer1M: 2.50, outputPer1M: 10.00 },
16
+ "gpt-4o-2024-11-20": { inputPer1M: 2.50, outputPer1M: 10.00 },
17
+ "gpt-4o-mini": { inputPer1M: 0.15, outputPer1M: 0.60 },
18
+ "gpt-4-turbo": { inputPer1M: 10.00, outputPer1M: 30.00 },
19
+ "gpt-4-turbo-preview": { inputPer1M: 10.00, outputPer1M: 30.00 },
20
+ "gpt-4": { inputPer1M: 30.00, outputPer1M: 60.00 },
21
+ "gpt-3.5-turbo": { inputPer1M: 0.50, outputPer1M: 1.50 },
22
+ "o1": { inputPer1M: 15.00, outputPer1M: 60.00 },
23
+ "o1-mini": { inputPer1M: 3.00, outputPer1M: 12.00 },
24
+ "o3-mini": { inputPer1M: 1.10, outputPer1M: 4.40 },
25
+ // ── Qwen models ──────────────────────────────────────────────────────────
26
+ "qwen2.5-72b-instruct": { inputPer1M: 0.40, outputPer1M: 1.20 },
27
+ "qwen2.5-32b-instruct": { inputPer1M: 0.20, outputPer1M: 0.60 },
28
+ "qwen2.5-coder-32b-instruct": { inputPer1M: 0.20, outputPer1M: 0.60 },
29
+ "qwen2.5-7b-instruct": { inputPer1M: 0.10, outputPer1M: 0.30 },
30
+ "qwen3-235b-a22b": { inputPer1M: 0.60, outputPer1M: 2.40 },
31
+ "qwen3-32b": { inputPer1M: 0.20, outputPer1M: 0.60 },
32
+ // ── Kimi / Moonshot models ────────────────────────────────────────────────
33
+ "kimi-k1.5": { inputPer1M: 0.60, outputPer1M: 2.50 },
34
+ "kimi-k2": { inputPer1M: 0.60, outputPer1M: 2.50 },
35
+ "moonshot-v1-8k": { inputPer1M: 0.12, outputPer1M: 0.12 },
36
+ "moonshot-v1-32k": { inputPer1M: 0.24, outputPer1M: 0.24 },
37
+ "moonshot-v1-128k": { inputPer1M: 0.60, outputPer1M: 0.60 },
38
+ // ── DeepSeek models ───────────────────────────────────────────────────────
39
+ "deepseek-coder-v2": { inputPer1M: 0.14, outputPer1M: 0.28 },
40
+ "deepseek-v3": { inputPer1M: 0.14, outputPer1M: 0.28 },
41
+ "deepseek-r1": { inputPer1M: 0.55, outputPer1M: 2.19 },
42
+ "deepseek-chat": { inputPer1M: 0.14, outputPer1M: 0.28 },
43
+ };
44
+ const DEFAULT_PRICING = { inputPer1M: 1.0, outputPer1M: 3.0 };
45
+ /**
46
+ * Return pricing for a model. Falls back to DEFAULT_PRICING for unknown models.
47
+ * Performs prefix matching so version-suffixed names resolve to the base model.
48
+ */
49
+ export function getPricing(model) {
50
+ if (!model)
51
+ return DEFAULT_PRICING;
52
+ // Exact match first
53
+ if (PRICING[model])
54
+ return PRICING[model];
55
+ // Prefix match (e.g. "claude-sonnet-4-6-20260101" → "claude-sonnet-4-6")
56
+ for (const [key, pricing] of Object.entries(PRICING)) {
57
+ if (model.startsWith(key))
58
+ return pricing;
59
+ }
60
+ return DEFAULT_PRICING;
61
+ }
62
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/drivers/pricing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import { EventEmitter } from "events";
2
+ export interface SpawnOptions {
3
+ cwd: string;
4
+ task: string;
5
+ budgetUsd: number;
6
+ token?: string;
7
+ continueSession?: boolean;
8
+ sessionId?: string;
9
+ model?: string;
10
+ /** Additional env vars merged over process.env before spawning. */
11
+ env?: Record<string, string>;
12
+ }
13
+ export interface UsageEvent {
14
+ inputTokens: number;
15
+ outputTokens: number;
16
+ cacheReadTokens?: number;
17
+ cacheWriteTokens?: number;
18
+ costUsd?: number;
19
+ }
20
+ export interface AgentProcess {
21
+ pid?: number;
22
+ on(event: "text", handler: (chunk: string) => void): this;
23
+ on(event: "tool", handler: (name: string) => void): this;
24
+ on(event: "usage", handler: (u: UsageEvent) => void): this;
25
+ on(event: "sessionId", handler: (id: string) => void): this;
26
+ on(event: "exit", handler: (code: number | null) => void): this;
27
+ on(event: string, handler: (...args: unknown[]) => void): this;
28
+ kill(signal?: string): void;
29
+ writeStdin?(data: string): void;
30
+ }
31
+ export interface AgentDriver {
32
+ readonly name: string;
33
+ resolveBinary?(): string;
34
+ hasSession(cwd: string): boolean;
35
+ spawn(options: SpawnOptions): AgentProcess;
36
+ estimateCost(usage: UsageEvent, model?: string): number;
37
+ }
38
+ export interface AgentPricing {
39
+ inputPer1M: number;
40
+ outputPer1M: number;
41
+ cacheReadPer1M?: number;
42
+ cacheWritePer1M?: number;
43
+ }
44
+ /**
45
+ * Concrete base class for AgentProcess implementations.
46
+ * Extends EventEmitter so drivers can call .emit() and
47
+ * satisfies the AgentProcess interface by declaring all required members.
48
+ */
49
+ export declare class BaseAgentProcess extends EventEmitter implements AgentProcess {
50
+ pid?: number;
51
+ writeStdin?: (data: string) => void;
52
+ /** Implementations must override this. Default is a no-op. */
53
+ kill(_signal?: string): void;
54
+ }
55
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/drivers/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1D,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACzD,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3D,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC5D,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,CAAC;IAChE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,IAAI,MAAM,CAAC;IACzB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAAC;IAC3C,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzD;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,YAAa,YAAW,YAAY;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpC,8DAA8D;IAC9D,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;CAC7B"}
@@ -0,0 +1,13 @@
1
+ import { EventEmitter } from "events";
2
+ /**
3
+ * Concrete base class for AgentProcess implementations.
4
+ * Extends EventEmitter so drivers can call .emit() and
5
+ * satisfies the AgentProcess interface by declaring all required members.
6
+ */
7
+ export class BaseAgentProcess extends EventEmitter {
8
+ pid;
9
+ writeStdin;
10
+ /** Implementations must override this. Default is a no-op. */
11
+ kill(_signal) { }
12
+ }
13
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/drivers/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAiDtC;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAChD,GAAG,CAAU;IACb,UAAU,CAA0B;IAEpC,8DAA8D;IAC9D,IAAI,CAAC,OAAgB,IAAS,CAAC;CAChC"}
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
20
20
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
21
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
22
22
  import { JobManager, normalizeRepoUrl } from "./agent.js";
23
+ import { listDrivers, getDriverStatus } from "./drivers/index.js";
23
24
  import { MetaAgentManager } from "./meta-agent.js";
24
25
  import { buildEvaluatorTask } from "./evaluator.js";
25
26
  import { loadProfiles, upsertProfile, deleteProfile, getProfile, interpolate } from "./profiles.js";
@@ -137,6 +138,22 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
137
138
  type: "number",
138
139
  description: "Timeout for the smoke test in seconds (default 60). Only used when smoke_test is set.",
139
140
  },
141
+ agent_driver: {
142
+ type: "string",
143
+ description: "Which agent driver to use. One of: claude (default), aider, openai, qwen, kimi, deepseek, pi. Defaults to 'claude' (Claude Code).",
144
+ },
145
+ agent_model: {
146
+ type: "string",
147
+ description: "Model override for the selected driver (e.g. 'qwen2.5-72b-instruct', 'kimi-k2', 'gpt-4o'). Optional.",
148
+ },
149
+ openai_base_url: {
150
+ type: "string",
151
+ description: "Base URL for OpenAI-compatible API endpoint. Only used when agent_driver is openai/qwen/kimi/deepseek/pi.",
152
+ },
153
+ openai_api_key: {
154
+ type: "string",
155
+ description: "API key override for OpenAI-compatible drivers. Falls back to OPENAI_API_KEY / driver-specific env var.",
156
+ },
140
157
  coordinator_plan: {
141
158
  type: "object",
142
159
  description: "Optional plan for cc-tg coordinator. If set, cc-tg will spawn the nextStep when this job completes.",
@@ -639,6 +656,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
639
656
  required: ["namespace"],
640
657
  },
641
658
  },
659
+ {
660
+ name: "list_drivers",
661
+ description: "List all available agent drivers and their status (binary found / API key configured). Use this to check which drivers are ready to use before calling spawn_agent with agent_driver.",
662
+ inputSchema: { type: "object", properties: {} },
663
+ },
642
664
  ],
643
665
  }));
644
666
  server.setRequestHandler(CallToolRequestSchema, async (req) => {
@@ -667,6 +689,10 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
667
689
  smokeTest: a.smoke_test,
668
690
  smokeTestTimeout: a.smoke_test_timeout,
669
691
  requiresApproval: !isTrusted,
692
+ agentDriver: a.agent_driver,
693
+ agentModel: a.agent_model,
694
+ openaiBaseUrl: a.openai_base_url,
695
+ openaiApiKey: a.openai_api_key,
670
696
  });
671
697
  if (a.coordinator_plan) {
672
698
  const redis = getRedis();
@@ -1437,6 +1463,20 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1437
1463
  };
1438
1464
  }
1439
1465
  }
1466
+ case "list_drivers": {
1467
+ logger.info("tool:list_drivers");
1468
+ const drivers = getDriverStatus();
1469
+ return {
1470
+ content: [{
1471
+ type: "text",
1472
+ text: JSON.stringify({
1473
+ drivers,
1474
+ valid_names: listDrivers(),
1475
+ usage: "Pass agent_driver to spawn_agent to use a specific driver (default: 'claude')",
1476
+ }),
1477
+ }],
1478
+ };
1479
+ }
1440
1480
  default:
1441
1481
  throw new Error(`Unknown tool: ${name}`);
1442
1482
  }