@gonzih/cc-agent 0.14.8 → 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 @@
1
+ {"version":3,"file":"aider.js","sourceRoot":"","sources":["../../src/drivers/aider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { AgentDriver, AgentProcess, SpawnOptions, UsageEvent } from "./types.js";
2
+ /**
3
+ * ClaudeCodeDriver wraps the existing runClaude() function from claude.ts.
4
+ * All session management, binary resolution, and stream-json parsing is
5
+ * delegated to the existing implementation — behaviour is byte-for-byte identical.
6
+ */
7
+ export declare class ClaudeCodeDriver implements AgentDriver {
8
+ readonly name = "claude";
9
+ resolveBinary(): string;
10
+ hasSession(cwd: string): boolean;
11
+ spawn(options: SpawnOptions): AgentProcess;
12
+ estimateCost(usage: UsageEvent, model?: string): number;
13
+ }
14
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/drivers/claude-code.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEtF;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,YAAY;IAEzB,aAAa,IAAI,MAAM;IAIvB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAiBhC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY;IA6C1C,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;CAWxD"}
@@ -0,0 +1,86 @@
1
+ import { existsSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ import { runClaude, resolveClaude } from "../claude.js";
5
+ import { getPricing } from "./pricing.js";
6
+ import { BaseAgentProcess } from "./types.js";
7
+ /**
8
+ * ClaudeCodeDriver wraps the existing runClaude() function from claude.ts.
9
+ * All session management, binary resolution, and stream-json parsing is
10
+ * delegated to the existing implementation — behaviour is byte-for-byte identical.
11
+ */
12
+ export class ClaudeCodeDriver {
13
+ name = "claude";
14
+ resolveBinary() {
15
+ return resolveClaude();
16
+ }
17
+ hasSession(cwd) {
18
+ // Claude stores sessions under ~/.claude/projects/<encoded-cwd>/
19
+ // Path encoding: leading slash stripped, remaining slashes → dashes
20
+ const projectsDir = join(homedir(), ".claude", "projects");
21
+ if (!existsSync(projectsDir))
22
+ return false;
23
+ try {
24
+ // Claude Code encodes the path by stripping the leading '/' and replacing all '/' with '-'
25
+ const encoded = cwd.replace(/^\//, "").replace(/\//g, "-");
26
+ if (existsSync(join(projectsDir, encoded)))
27
+ return true;
28
+ // Some versions prefix with a leading dash
29
+ if (existsSync(join(projectsDir, `-${encoded}`)))
30
+ return true;
31
+ }
32
+ catch {
33
+ // ignore
34
+ }
35
+ return false;
36
+ }
37
+ spawn(options) {
38
+ // Extract ollama config encoded in env by agent.ts
39
+ const ollamaModel = options.env?.CC_DRIVER_OLLAMA_MODEL;
40
+ const ollamaHost = options.env?.CC_DRIVER_OLLAMA_HOST;
41
+ const proc = runClaude(options.task, options.cwd, options.token, {
42
+ continueSession: options.continueSession,
43
+ maxBudgetUsd: options.budgetUsd,
44
+ sessionId: options.sessionId,
45
+ model: options.model,
46
+ ollamaModel,
47
+ ollamaHost,
48
+ });
49
+ // Adapt OneShot interface → AgentProcess interface
50
+ // Main difference: "session" event → "sessionId" event
51
+ const emitter = new BaseAgentProcess();
52
+ proc.on("text", (text) => emitter.emit("text", text));
53
+ proc.on("tool", (name) => emitter.emit("tool", name));
54
+ proc.on("usage", (u) => emitter.emit("usage", u));
55
+ proc.on("session", (id) => emitter.emit("sessionId", id));
56
+ proc.on("error", (err) => {
57
+ // Translate error events into a non-zero exit so agent.ts sees a failure
58
+ emitter.emit("text", `[cc-agent] Claude error: ${err.message}`);
59
+ emitter.emit("exit", 1);
60
+ });
61
+ proc.on("exit", (code) => emitter.emit("exit", code));
62
+ emitter.pid = proc.pid;
63
+ emitter.kill = (signal) => {
64
+ void signal; // ClaudeCodeDriver always SIGTERMs the process group
65
+ proc.kill();
66
+ };
67
+ emitter.writeStdin = (data) => {
68
+ if (proc.stdin && !proc.stdin.destroyed) {
69
+ proc.stdin.write(data);
70
+ }
71
+ };
72
+ return emitter;
73
+ }
74
+ estimateCost(usage, model) {
75
+ if (usage.costUsd != null)
76
+ return usage.costUsd;
77
+ const pricing = getPricing(model ?? "claude-sonnet-4-6");
78
+ const cost = (usage.inputTokens * pricing.inputPer1M +
79
+ usage.outputTokens * pricing.outputPer1M +
80
+ (usage.cacheReadTokens ?? 0) * (pricing.cacheReadPer1M ?? 0) +
81
+ (usage.cacheWriteTokens ?? 0) * (pricing.cacheWritePer1M ?? 0)) /
82
+ 1_000_000;
83
+ return Math.round(cost * 10000) / 10000;
84
+ }
85
+ }
86
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/drivers/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { AgentDriver } from "./types.js";
2
+ export { ClaudeCodeDriver } from "./claude-code.js";
3
+ export { AiderDriver } from "./aider.js";
4
+ export { OpenAICompatibleDriver } from "./openai-compatible.js";
5
+ export type { AgentDriver, AgentProcess, SpawnOptions, UsageEvent, AgentPricing } from "./types.js";
6
+ export { getPricing } from "./pricing.js";
7
+ declare const VALID_DRIVERS: readonly ["claude", "claude-code", "aider", "openai", "openai-compatible", "qwen", "kimi", "deepseek", "pi"];
8
+ export type DriverName = typeof VALID_DRIVERS[number];
9
+ /**
10
+ * Return an AgentDriver instance for the given name.
11
+ * Throws a descriptive error for unknown names.
12
+ */
13
+ export declare function getDriver(name: string): AgentDriver;
14
+ /** Return the list of valid driver names. */
15
+ export declare function listDrivers(): string[];
16
+ /**
17
+ * Return status info for each driver (whether the binary / API key is available).
18
+ */
19
+ export declare function getDriverStatus(): Array<{
20
+ name: string;
21
+ available: boolean;
22
+ note: string;
23
+ }>;
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/drivers/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACpG,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,QAAA,MAAM,aAAa,8GAA+G,CAAC;AACnI,MAAM,MAAM,UAAU,GAAG,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAsBnD;AAED,6CAA6C;AAC7C,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAiD3F"}
@@ -0,0 +1,84 @@
1
+ import { existsSync } from "fs";
2
+ import { ClaudeCodeDriver } from "./claude-code.js";
3
+ import { AiderDriver } from "./aider.js";
4
+ import { OpenAICompatibleDriver } from "./openai-compatible.js";
5
+ export { ClaudeCodeDriver } from "./claude-code.js";
6
+ export { AiderDriver } from "./aider.js";
7
+ export { OpenAICompatibleDriver } from "./openai-compatible.js";
8
+ export { getPricing } from "./pricing.js";
9
+ const VALID_DRIVERS = ["claude", "claude-code", "aider", "openai", "openai-compatible", "qwen", "kimi", "deepseek", "pi"];
10
+ /**
11
+ * Return an AgentDriver instance for the given name.
12
+ * Throws a descriptive error for unknown names.
13
+ */
14
+ export function getDriver(name) {
15
+ switch (name) {
16
+ case "claude":
17
+ case "claude-code":
18
+ return new ClaudeCodeDriver();
19
+ case "aider":
20
+ return new AiderDriver();
21
+ case "openai":
22
+ case "openai-compatible":
23
+ case "qwen":
24
+ case "kimi":
25
+ case "deepseek":
26
+ case "pi":
27
+ return new OpenAICompatibleDriver(name);
28
+ default:
29
+ throw new Error(`Unknown agent driver: '${name}'. Valid drivers: ${VALID_DRIVERS.join(", ")}`);
30
+ }
31
+ }
32
+ /** Return the list of valid driver names. */
33
+ export function listDrivers() {
34
+ return [...VALID_DRIVERS];
35
+ }
36
+ /**
37
+ * Return status info for each driver (whether the binary / API key is available).
38
+ */
39
+ export function getDriverStatus() {
40
+ const drivers = [];
41
+ // Claude Code
42
+ {
43
+ const d = new ClaudeCodeDriver();
44
+ const bin = d.resolveBinary?.() ?? "claude";
45
+ const hasToken = !!(process.env.ANTHROPIC_API_KEY ?? process.env.CLAUDE_CODE_OAUTH_TOKEN ?? process.env.CLAUDE_CODE_TOKEN);
46
+ const hasBin = existsSync(bin);
47
+ drivers.push({
48
+ name: "claude",
49
+ available: hasBin,
50
+ note: hasBin
51
+ ? hasToken ? "binary found, token configured" : "binary found (no token — uses ~/.claude auth)"
52
+ : `binary not found at: ${bin}`,
53
+ });
54
+ }
55
+ // Aider
56
+ {
57
+ const d = new AiderDriver();
58
+ const bin = d.resolveBinary?.() ?? "aider";
59
+ const hasBin = existsSync(bin);
60
+ drivers.push({
61
+ name: "aider",
62
+ available: hasBin,
63
+ note: hasBin ? "binary found" : `aider not installed — run: pip install aider-install && aider-install`,
64
+ });
65
+ }
66
+ // OpenAI-compatible drivers
67
+ const apiDrivers = [
68
+ { name: "openai", envKey: "OPENAI_API_KEY" },
69
+ { name: "qwen", envKey: "QWEN_API_KEY" },
70
+ { name: "kimi", envKey: "KIMI_API_KEY" },
71
+ { name: "deepseek", envKey: "DEEPSEEK_API_KEY" },
72
+ { name: "pi", envKey: "PI_API_KEY" },
73
+ ];
74
+ for (const { name, envKey } of apiDrivers) {
75
+ const hasKey = !!(process.env[envKey] ?? process.env.OPENAI_API_KEY);
76
+ drivers.push({
77
+ name,
78
+ available: hasKey,
79
+ note: hasKey ? `${envKey} configured` : `set ${envKey} or OPENAI_API_KEY to enable`,
80
+ });
81
+ }
82
+ return drivers;
83
+ }
84
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/drivers/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
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 type { AgentDriver, AgentProcess, SpawnOptions, UsageEvent } from "./types.js";
18
+ export declare class OpenAICompatibleDriver implements AgentDriver {
19
+ readonly name: string;
20
+ constructor(name: string);
21
+ resolveBinary(): string;
22
+ hasSession(_cwd: string): boolean;
23
+ spawn(options: SpawnOptions): AgentProcess;
24
+ private resolveApiKey;
25
+ private resolveBaseUrl;
26
+ private resolveModel;
27
+ /** Resolve a user-provided path safely within cwd. */
28
+ private safePath;
29
+ private executeTool;
30
+ private runLoop;
31
+ estimateCost(usage: UsageEvent, model?: string): number;
32
+ }
33
+ //# sourceMappingURL=openai-compatible.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-compatible.d.ts","sourceRoot":"","sources":["../../src/drivers/openai-compatible.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAmItF,qBAAa,sBAAuB,YAAW,WAAW;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;IAIxB,aAAa,IAAI,MAAM;IAIvB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY;IAoB1C,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,YAAY;IAKpB,sDAAsD;IACtD,OAAO,CAAC,QAAQ;YAUF,WAAW;YAyDX,OAAO;IAsIrB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;CASxD"}
@@ -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