agent-worker 0.3.0 → 0.5.0
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.
- package/README.md +335 -296
- package/dist/backends-B8rYTNqn.mjs +3 -0
- package/dist/backends-CEYiMUgC.mjs +1037 -0
- package/dist/cli/index.mjs +2085 -829
- package/dist/context-C7nBmU5D.mjs +4 -0
- package/dist/index.d.mts +279 -178
- package/dist/index.mjs +27 -36
- package/dist/mcp-server-DtIApaBD.mjs +549 -0
- package/dist/{skills-CVdxwuvV.mjs → skills-iya7NbH7.mjs} +263 -136
- package/dist/workflow-K1Zd655A.mjs +1792 -0
- package/package.json +10 -4
- package/dist/backends-BZ866Ij9.mjs +0 -564
- package/dist/backends-DXpJ7FJI.mjs +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "SDK and CLI for creating and testing agent workers with Vercel AI SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.mjs",
|
|
@@ -30,10 +30,16 @@
|
|
|
30
30
|
"prepublishOnly": "bun run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
33
34
|
"ai": "^6.0.69",
|
|
34
35
|
"bash-tool": "^1.3.12",
|
|
36
|
+
"chalk": "^5.6.2",
|
|
35
37
|
"commander": "^14.0.3",
|
|
38
|
+
"execa": "^9.6.1",
|
|
36
39
|
"just-bash": "^2.8.0",
|
|
40
|
+
"nanoid": "^5.1.6",
|
|
41
|
+
"string-width": "^8.1.1",
|
|
42
|
+
"wrap-ansi": "^9.0.2",
|
|
37
43
|
"yaml": "^2.7.0",
|
|
38
44
|
"zod": "^3.24.1"
|
|
39
45
|
},
|
|
@@ -52,14 +58,14 @@
|
|
|
52
58
|
"tsdown": "^0.20.1"
|
|
53
59
|
},
|
|
54
60
|
"peerDependencies": {
|
|
55
|
-
"typescript": "^5",
|
|
56
61
|
"@ai-sdk/anthropic": "^3.0.0",
|
|
57
|
-
"@ai-sdk/openai": "^3.0.0",
|
|
58
62
|
"@ai-sdk/deepseek": "^1.0.0",
|
|
59
63
|
"@ai-sdk/google": "^1.0.0",
|
|
60
64
|
"@ai-sdk/groq": "^1.0.0",
|
|
61
65
|
"@ai-sdk/mistral": "^1.0.0",
|
|
62
|
-
"@ai-sdk/
|
|
66
|
+
"@ai-sdk/openai": "^3.0.0",
|
|
67
|
+
"@ai-sdk/xai": "^1.0.0",
|
|
68
|
+
"typescript": "^5"
|
|
63
69
|
},
|
|
64
70
|
"peerDependenciesMeta": {
|
|
65
71
|
"@ai-sdk/anthropic": {
|
|
@@ -1,564 +0,0 @@
|
|
|
1
|
-
import { gateway, generateText } from "ai";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
|
|
4
|
-
//#region src/models.ts
|
|
5
|
-
const providerCache = {};
|
|
6
|
-
/**
|
|
7
|
-
* Lazy load a provider, caching the result
|
|
8
|
-
* Supports custom baseURL and apiKey for providers using compatible APIs (e.g., MiniMax using Claude API)
|
|
9
|
-
*/
|
|
10
|
-
async function loadProvider(name, packageName, exportName, options) {
|
|
11
|
-
if (name in providerCache) return providerCache[name];
|
|
12
|
-
try {
|
|
13
|
-
const module = await import(packageName);
|
|
14
|
-
if (options?.baseURL || options?.apiKeyEnvVar) {
|
|
15
|
-
const createProvider = module[`create${exportName.charAt(0).toUpperCase() + exportName.slice(1)}`];
|
|
16
|
-
if (createProvider) {
|
|
17
|
-
const providerOptions = {};
|
|
18
|
-
if (options.baseURL) providerOptions.baseURL = options.baseURL;
|
|
19
|
-
if (options.apiKeyEnvVar) providerOptions.apiKey = process.env[options.apiKeyEnvVar];
|
|
20
|
-
providerCache[name] = createProvider(providerOptions);
|
|
21
|
-
return providerCache[name];
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
providerCache[name] = module[exportName];
|
|
25
|
-
return providerCache[name];
|
|
26
|
-
} catch {
|
|
27
|
-
providerCache[name] = null;
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Parse model identifier and return the appropriate provider model
|
|
33
|
-
*
|
|
34
|
-
* Supports three formats:
|
|
35
|
-
*
|
|
36
|
-
* 1. Provider-only format: provider
|
|
37
|
-
* Uses first model from FRONTIER_MODELS via gateway
|
|
38
|
-
* Examples: anthropic → anthropic/claude-sonnet-4-5, openai → openai/gpt-5.2
|
|
39
|
-
*
|
|
40
|
-
* 2. Gateway format: provider/model-name
|
|
41
|
-
* Uses Vercel AI Gateway (requires AI_GATEWAY_API_KEY)
|
|
42
|
-
* Examples: anthropic/claude-sonnet-4-5, openai/gpt-5.2, deepseek/deepseek-chat
|
|
43
|
-
*
|
|
44
|
-
* 3. Direct provider format: provider:model-name
|
|
45
|
-
* Requires installing the specific @ai-sdk/provider package
|
|
46
|
-
* Examples: anthropic:claude-sonnet-4-5, openai:gpt-5.2, deepseek:deepseek-chat
|
|
47
|
-
*/
|
|
48
|
-
function createModel(modelId) {
|
|
49
|
-
if (modelId.includes("/")) return gateway(modelId);
|
|
50
|
-
if (!modelId.includes(":")) {
|
|
51
|
-
const provider = modelId;
|
|
52
|
-
if (provider in FRONTIER_MODELS) {
|
|
53
|
-
const defaultModel = FRONTIER_MODELS[provider][0];
|
|
54
|
-
return gateway(`${provider}/${defaultModel}`);
|
|
55
|
-
}
|
|
56
|
-
throw new Error(`Unknown provider: ${modelId}. Supported: ${Object.keys(FRONTIER_MODELS).join(", ")}`);
|
|
57
|
-
}
|
|
58
|
-
const colonIndex = modelId.indexOf(":");
|
|
59
|
-
const provider = modelId.slice(0, colonIndex);
|
|
60
|
-
const modelName = modelId.slice(colonIndex + 1);
|
|
61
|
-
if (!modelName) throw new Error(`Invalid model identifier: ${modelId}. Model name is required.`);
|
|
62
|
-
if (provider in providerCache && providerCache[provider]) return providerCache[provider](modelName);
|
|
63
|
-
throw new Error(`Provider '${provider}' not loaded. Use gateway format (${provider}/${modelName}) or call createModelAsync() for direct provider access.`);
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Async version of createModel - supports lazy loading of direct providers
|
|
67
|
-
* Use this when you need direct provider access (provider:model format)
|
|
68
|
-
*/
|
|
69
|
-
async function createModelAsync(modelId) {
|
|
70
|
-
if (modelId.includes("/")) return gateway(modelId);
|
|
71
|
-
if (!modelId.includes(":")) {
|
|
72
|
-
const provider = modelId;
|
|
73
|
-
if (provider in FRONTIER_MODELS) {
|
|
74
|
-
const defaultModel = FRONTIER_MODELS[provider][0];
|
|
75
|
-
return gateway(`${provider}/${defaultModel}`);
|
|
76
|
-
}
|
|
77
|
-
throw new Error(`Unknown provider: ${modelId}. Supported: ${Object.keys(FRONTIER_MODELS).join(", ")}`);
|
|
78
|
-
}
|
|
79
|
-
const colonIndex = modelId.indexOf(":");
|
|
80
|
-
const provider = modelId.slice(0, colonIndex);
|
|
81
|
-
const modelName = modelId.slice(colonIndex + 1);
|
|
82
|
-
if (!modelName) throw new Error(`Invalid model identifier: ${modelId}. Model name is required.`);
|
|
83
|
-
const providerConfigs = {
|
|
84
|
-
anthropic: {
|
|
85
|
-
package: "@ai-sdk/anthropic",
|
|
86
|
-
export: "anthropic"
|
|
87
|
-
},
|
|
88
|
-
openai: {
|
|
89
|
-
package: "@ai-sdk/openai",
|
|
90
|
-
export: "openai"
|
|
91
|
-
},
|
|
92
|
-
deepseek: {
|
|
93
|
-
package: "@ai-sdk/deepseek",
|
|
94
|
-
export: "deepseek"
|
|
95
|
-
},
|
|
96
|
-
google: {
|
|
97
|
-
package: "@ai-sdk/google",
|
|
98
|
-
export: "google"
|
|
99
|
-
},
|
|
100
|
-
groq: {
|
|
101
|
-
package: "@ai-sdk/groq",
|
|
102
|
-
export: "groq"
|
|
103
|
-
},
|
|
104
|
-
mistral: {
|
|
105
|
-
package: "@ai-sdk/mistral",
|
|
106
|
-
export: "mistral"
|
|
107
|
-
},
|
|
108
|
-
xai: {
|
|
109
|
-
package: "@ai-sdk/xai",
|
|
110
|
-
export: "xai"
|
|
111
|
-
},
|
|
112
|
-
minimax: {
|
|
113
|
-
package: "@ai-sdk/anthropic",
|
|
114
|
-
export: "anthropic",
|
|
115
|
-
options: {
|
|
116
|
-
baseURL: "https://api.minimax.chat/v1",
|
|
117
|
-
apiKeyEnvVar: "MINIMAX_API_KEY"
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
const config = providerConfigs[provider];
|
|
122
|
-
if (!config) throw new Error(`Unknown provider: ${provider}. Supported: ${Object.keys(providerConfigs).join(", ")}. Or use gateway format: provider/model (e.g., openai/gpt-5.2)`);
|
|
123
|
-
const providerFn = await loadProvider(provider, config.package, config.export, config.options);
|
|
124
|
-
if (!providerFn) throw new Error(`Install ${config.package} to use ${provider} models directly`);
|
|
125
|
-
return providerFn(modelName);
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* List of supported providers for direct access
|
|
129
|
-
* Note: minimax uses Claude-compatible API via @ai-sdk/anthropic with custom baseURL
|
|
130
|
-
*/
|
|
131
|
-
const SUPPORTED_PROVIDERS = [
|
|
132
|
-
"anthropic",
|
|
133
|
-
"openai",
|
|
134
|
-
"deepseek",
|
|
135
|
-
"google",
|
|
136
|
-
"groq",
|
|
137
|
-
"mistral",
|
|
138
|
-
"xai",
|
|
139
|
-
"minimax"
|
|
140
|
-
];
|
|
141
|
-
/**
|
|
142
|
-
* Default provider when none specified
|
|
143
|
-
*/
|
|
144
|
-
const DEFAULT_PROVIDER = "anthropic";
|
|
145
|
-
/**
|
|
146
|
-
* Get the default model identifier (provider/model format)
|
|
147
|
-
* Uses the first model from the default provider
|
|
148
|
-
*/
|
|
149
|
-
function getDefaultModel() {
|
|
150
|
-
return `${DEFAULT_PROVIDER}/${FRONTIER_MODELS[DEFAULT_PROVIDER][0]}`;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Frontier models for each provider (as of 2026-02)
|
|
154
|
-
* Only includes the latest/best models, no legacy versions
|
|
155
|
-
*
|
|
156
|
-
* Note: Some models may be placeholders for testing or future releases.
|
|
157
|
-
* Always verify model availability with the provider before production use.
|
|
158
|
-
*/
|
|
159
|
-
const FRONTIER_MODELS = {
|
|
160
|
-
anthropic: [
|
|
161
|
-
"claude-sonnet-4-5",
|
|
162
|
-
"claude-haiku-4-5",
|
|
163
|
-
"claude-opus-4-5"
|
|
164
|
-
],
|
|
165
|
-
openai: ["gpt-5.2", "gpt-5.2-codex"],
|
|
166
|
-
google: [
|
|
167
|
-
"gemini-3-pro-preview",
|
|
168
|
-
"gemini-2.5-flash",
|
|
169
|
-
"gemini-2.5-pro"
|
|
170
|
-
],
|
|
171
|
-
deepseek: ["deepseek-chat", "deepseek-reasoner"],
|
|
172
|
-
groq: ["meta-llama/llama-4-scout-17b-16e-instruct", "deepseek-r1-distill-llama-70b"],
|
|
173
|
-
mistral: [
|
|
174
|
-
"mistral-large-latest",
|
|
175
|
-
"pixtral-large-latest",
|
|
176
|
-
"magistral-medium-2506"
|
|
177
|
-
],
|
|
178
|
-
xai: ["grok-4", "grok-4-fast-reasoning"],
|
|
179
|
-
minimax: ["MiniMax-M2"]
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
//#endregion
|
|
183
|
-
//#region src/backends/claude-cli.ts
|
|
184
|
-
/**
|
|
185
|
-
* Claude Code CLI backend
|
|
186
|
-
* Uses `claude -p` for non-interactive mode
|
|
187
|
-
*
|
|
188
|
-
* @see https://code.claude.com/docs/en/headless
|
|
189
|
-
*/
|
|
190
|
-
var ClaudeCliBackend = class {
|
|
191
|
-
type = "claude";
|
|
192
|
-
options;
|
|
193
|
-
constructor(options = {}) {
|
|
194
|
-
this.options = options;
|
|
195
|
-
}
|
|
196
|
-
async send(message, options) {
|
|
197
|
-
const args = this.buildArgs(message, options);
|
|
198
|
-
return new Promise((resolve, reject) => {
|
|
199
|
-
const proc = spawn("claude", args, {
|
|
200
|
-
cwd: this.options.cwd,
|
|
201
|
-
env: process.env,
|
|
202
|
-
stdio: [
|
|
203
|
-
"ignore",
|
|
204
|
-
"pipe",
|
|
205
|
-
"pipe"
|
|
206
|
-
]
|
|
207
|
-
});
|
|
208
|
-
let stdout = "";
|
|
209
|
-
let stderr = "";
|
|
210
|
-
proc.stdout.on("data", (data) => {
|
|
211
|
-
stdout += data.toString();
|
|
212
|
-
});
|
|
213
|
-
proc.stderr.on("data", (data) => {
|
|
214
|
-
stderr += data.toString();
|
|
215
|
-
});
|
|
216
|
-
proc.on("close", (code) => {
|
|
217
|
-
if (code !== 0) {
|
|
218
|
-
reject(/* @__PURE__ */ new Error(`claude exited with code ${code}: ${stderr}`));
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
if (this.options.outputFormat === "json") try {
|
|
222
|
-
const parsed = JSON.parse(stdout);
|
|
223
|
-
resolve({
|
|
224
|
-
content: parsed.content || parsed.result || stdout,
|
|
225
|
-
toolCalls: parsed.toolCalls,
|
|
226
|
-
usage: parsed.usage
|
|
227
|
-
});
|
|
228
|
-
} catch {
|
|
229
|
-
resolve({ content: stdout.trim() });
|
|
230
|
-
}
|
|
231
|
-
else resolve({ content: stdout.trim() });
|
|
232
|
-
});
|
|
233
|
-
proc.on("error", (err) => {
|
|
234
|
-
reject(/* @__PURE__ */ new Error(`Failed to spawn claude: ${err.message}`));
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
async isAvailable() {
|
|
239
|
-
return new Promise((resolve) => {
|
|
240
|
-
const proc = spawn("claude", ["--version"], { stdio: "pipe" });
|
|
241
|
-
proc.on("close", (code) => resolve(code === 0));
|
|
242
|
-
proc.on("error", () => resolve(false));
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
getInfo() {
|
|
246
|
-
return {
|
|
247
|
-
name: "Claude Code CLI",
|
|
248
|
-
model: this.options.model
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
buildArgs(message, options) {
|
|
252
|
-
const args = ["-p", message];
|
|
253
|
-
if (this.options.model) args.push("--model", this.options.model);
|
|
254
|
-
if (options?.system || this.options.appendSystemPrompt) {
|
|
255
|
-
const system = options?.system || this.options.appendSystemPrompt;
|
|
256
|
-
args.push("--append-system-prompt", system);
|
|
257
|
-
}
|
|
258
|
-
if (this.options.allowedTools?.length) args.push("--allowed-tools", this.options.allowedTools.join(","));
|
|
259
|
-
if (this.options.outputFormat) args.push("--output-format", this.options.outputFormat);
|
|
260
|
-
if (this.options.continue) args.push("--continue");
|
|
261
|
-
if (this.options.resume) args.push("--resume", this.options.resume);
|
|
262
|
-
return args;
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
//#endregion
|
|
267
|
-
//#region src/backends/codex-cli.ts
|
|
268
|
-
/**
|
|
269
|
-
* OpenAI Codex CLI backend
|
|
270
|
-
* Uses `codex exec` for non-interactive mode
|
|
271
|
-
*
|
|
272
|
-
* @see https://developers.openai.com/codex/noninteractive/
|
|
273
|
-
*/
|
|
274
|
-
var CodexCliBackend = class {
|
|
275
|
-
type = "codex";
|
|
276
|
-
options;
|
|
277
|
-
constructor(options = {}) {
|
|
278
|
-
this.options = options;
|
|
279
|
-
}
|
|
280
|
-
async send(message, _options) {
|
|
281
|
-
const args = this.buildArgs(message);
|
|
282
|
-
return new Promise((resolve, reject) => {
|
|
283
|
-
const proc = spawn("codex", args, {
|
|
284
|
-
cwd: this.options.cwd,
|
|
285
|
-
env: process.env
|
|
286
|
-
});
|
|
287
|
-
let stdout = "";
|
|
288
|
-
let stderr = "";
|
|
289
|
-
proc.stdout.on("data", (data) => {
|
|
290
|
-
stdout += data.toString();
|
|
291
|
-
});
|
|
292
|
-
proc.stderr.on("data", (data) => {
|
|
293
|
-
stderr += data.toString();
|
|
294
|
-
});
|
|
295
|
-
proc.on("close", (code) => {
|
|
296
|
-
if (code !== 0) {
|
|
297
|
-
reject(/* @__PURE__ */ new Error(`codex exited with code ${code}: ${stderr}`));
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
if (this.options.json) try {
|
|
301
|
-
const lines = stdout.trim().split("\n");
|
|
302
|
-
const lastEvent = JSON.parse(lines[lines.length - 1]);
|
|
303
|
-
resolve({
|
|
304
|
-
content: lastEvent.message || lastEvent.content || stdout,
|
|
305
|
-
toolCalls: lastEvent.toolCalls,
|
|
306
|
-
usage: lastEvent.usage
|
|
307
|
-
});
|
|
308
|
-
} catch {
|
|
309
|
-
resolve({ content: stdout.trim() });
|
|
310
|
-
}
|
|
311
|
-
else resolve({ content: stdout.trim() });
|
|
312
|
-
});
|
|
313
|
-
proc.on("error", (err) => {
|
|
314
|
-
reject(/* @__PURE__ */ new Error(`Failed to spawn codex: ${err.message}`));
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
async isAvailable() {
|
|
319
|
-
return new Promise((resolve) => {
|
|
320
|
-
const proc = spawn("codex", ["--version"], { stdio: "pipe" });
|
|
321
|
-
proc.on("close", (code) => resolve(code === 0));
|
|
322
|
-
proc.on("error", () => resolve(false));
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
getInfo() {
|
|
326
|
-
return {
|
|
327
|
-
name: "OpenAI Codex CLI",
|
|
328
|
-
model: this.options.model
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
buildArgs(message) {
|
|
332
|
-
const args = ["exec", message];
|
|
333
|
-
if (this.options.model) args.push("--model", this.options.model);
|
|
334
|
-
if (this.options.json) args.push("--json");
|
|
335
|
-
if (this.options.skipGitRepoCheck) args.push("--skip-git-repo-check");
|
|
336
|
-
if (this.options.approvalMode) args.push("--approval-mode", this.options.approvalMode);
|
|
337
|
-
if (this.options.resume) args.push("--resume", this.options.resume);
|
|
338
|
-
return args;
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
//#endregion
|
|
343
|
-
//#region src/backends/cursor-cli.ts
|
|
344
|
-
/**
|
|
345
|
-
* Cursor CLI backend
|
|
346
|
-
* Uses `cursor-agent -p` or `agent chat` for non-interactive mode
|
|
347
|
-
*
|
|
348
|
-
* @see https://cursor.com/docs/cli/headless
|
|
349
|
-
*/
|
|
350
|
-
var CursorCliBackend = class {
|
|
351
|
-
type = "cursor";
|
|
352
|
-
options;
|
|
353
|
-
constructor(options = {}) {
|
|
354
|
-
this.options = {
|
|
355
|
-
timeout: 12e4,
|
|
356
|
-
...options
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
async send(message, _options) {
|
|
360
|
-
const { command, args } = this.buildCommand(message);
|
|
361
|
-
return new Promise((resolve, reject) => {
|
|
362
|
-
const proc = spawn(command, args, {
|
|
363
|
-
cwd: this.options.cwd,
|
|
364
|
-
env: process.env
|
|
365
|
-
});
|
|
366
|
-
let stdout = "";
|
|
367
|
-
let stderr = "";
|
|
368
|
-
let timedOut = false;
|
|
369
|
-
const timer = setTimeout(() => {
|
|
370
|
-
timedOut = true;
|
|
371
|
-
proc.kill("SIGTERM");
|
|
372
|
-
}, this.options.timeout);
|
|
373
|
-
proc.stdout.on("data", (data) => {
|
|
374
|
-
stdout += data.toString();
|
|
375
|
-
});
|
|
376
|
-
proc.stderr.on("data", (data) => {
|
|
377
|
-
stderr += data.toString();
|
|
378
|
-
});
|
|
379
|
-
proc.on("close", (code) => {
|
|
380
|
-
clearTimeout(timer);
|
|
381
|
-
if (timedOut) {
|
|
382
|
-
reject(/* @__PURE__ */ new Error(`cursor-agent timed out after ${this.options.timeout}ms`));
|
|
383
|
-
return;
|
|
384
|
-
}
|
|
385
|
-
if (code !== 0 && code !== null) {
|
|
386
|
-
reject(/* @__PURE__ */ new Error(`cursor-agent exited with code ${code}: ${stderr}`));
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
resolve({ content: stdout.trim() });
|
|
390
|
-
});
|
|
391
|
-
proc.on("error", (err) => {
|
|
392
|
-
clearTimeout(timer);
|
|
393
|
-
reject(/* @__PURE__ */ new Error(`Failed to spawn cursor-agent: ${err.message}`));
|
|
394
|
-
});
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
async isAvailable() {
|
|
398
|
-
for (const cmd of ["cursor-agent", "agent"]) if (await this.checkCommand(cmd)) return true;
|
|
399
|
-
return false;
|
|
400
|
-
}
|
|
401
|
-
async checkCommand(command) {
|
|
402
|
-
return new Promise((resolve) => {
|
|
403
|
-
const proc = spawn(command, ["--version"], { stdio: "pipe" });
|
|
404
|
-
const timer = setTimeout(() => {
|
|
405
|
-
proc.kill();
|
|
406
|
-
resolve(false);
|
|
407
|
-
}, 5e3);
|
|
408
|
-
proc.on("close", (code) => {
|
|
409
|
-
clearTimeout(timer);
|
|
410
|
-
resolve(code === 0);
|
|
411
|
-
});
|
|
412
|
-
proc.on("error", () => {
|
|
413
|
-
clearTimeout(timer);
|
|
414
|
-
resolve(false);
|
|
415
|
-
});
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
getInfo() {
|
|
419
|
-
return {
|
|
420
|
-
name: "Cursor Agent CLI",
|
|
421
|
-
model: this.options.model
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
buildCommand(message) {
|
|
425
|
-
if (this.options.useAgentCommand) return {
|
|
426
|
-
command: "agent",
|
|
427
|
-
args: ["chat", message]
|
|
428
|
-
};
|
|
429
|
-
const args = ["-p", message];
|
|
430
|
-
if (this.options.model) args.push("--model", this.options.model);
|
|
431
|
-
return {
|
|
432
|
-
command: "cursor-agent",
|
|
433
|
-
args
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
//#endregion
|
|
439
|
-
//#region src/backends/sdk.ts
|
|
440
|
-
/**
|
|
441
|
-
* Vercel AI SDK backend
|
|
442
|
-
* Uses the AI SDK for direct API access
|
|
443
|
-
*/
|
|
444
|
-
var SdkBackend = class {
|
|
445
|
-
type = "sdk";
|
|
446
|
-
modelId;
|
|
447
|
-
model = null;
|
|
448
|
-
maxTokens;
|
|
449
|
-
constructor(options) {
|
|
450
|
-
this.modelId = options.model;
|
|
451
|
-
this.maxTokens = options.maxTokens ?? 4096;
|
|
452
|
-
try {
|
|
453
|
-
this.model = createModel(this.modelId);
|
|
454
|
-
} catch {}
|
|
455
|
-
}
|
|
456
|
-
async send(message, options) {
|
|
457
|
-
if (!this.model) this.model = await createModelAsync(this.modelId);
|
|
458
|
-
const result = await generateText({
|
|
459
|
-
model: this.model,
|
|
460
|
-
system: options?.system,
|
|
461
|
-
prompt: message,
|
|
462
|
-
maxTokens: this.maxTokens
|
|
463
|
-
});
|
|
464
|
-
return {
|
|
465
|
-
content: result.text,
|
|
466
|
-
usage: {
|
|
467
|
-
input: result.usage.promptTokens,
|
|
468
|
-
output: result.usage.completionTokens,
|
|
469
|
-
total: result.usage.totalTokens
|
|
470
|
-
}
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
async isAvailable() {
|
|
474
|
-
try {
|
|
475
|
-
if (!this.model) this.model = await createModelAsync(this.modelId);
|
|
476
|
-
return true;
|
|
477
|
-
} catch {
|
|
478
|
-
return false;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
getInfo() {
|
|
482
|
-
return {
|
|
483
|
-
name: "Vercel AI SDK",
|
|
484
|
-
model: this.modelId
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
//#endregion
|
|
490
|
-
//#region src/backends/index.ts
|
|
491
|
-
/**
|
|
492
|
-
* Create a backend instance
|
|
493
|
-
*/
|
|
494
|
-
function createBackend(config) {
|
|
495
|
-
switch (config.type) {
|
|
496
|
-
case "sdk": return new SdkBackend({
|
|
497
|
-
model: config.model,
|
|
498
|
-
maxTokens: config.maxTokens
|
|
499
|
-
});
|
|
500
|
-
case "claude": return new ClaudeCliBackend({
|
|
501
|
-
...config.options,
|
|
502
|
-
model: config.model
|
|
503
|
-
});
|
|
504
|
-
case "codex": return new CodexCliBackend({
|
|
505
|
-
...config.options,
|
|
506
|
-
model: config.model
|
|
507
|
-
});
|
|
508
|
-
case "cursor": return new CursorCliBackend({
|
|
509
|
-
...config.options,
|
|
510
|
-
model: config.model
|
|
511
|
-
});
|
|
512
|
-
default: throw new Error(`Unknown backend type: ${config.type}`);
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* Check which backends are available
|
|
517
|
-
*/
|
|
518
|
-
async function checkBackends() {
|
|
519
|
-
const claude = new ClaudeCliBackend();
|
|
520
|
-
const codex = new CodexCliBackend();
|
|
521
|
-
const cursor = new CursorCliBackend();
|
|
522
|
-
const [claudeAvailable, codexAvailable, cursorAvailable] = await Promise.all([
|
|
523
|
-
claude.isAvailable(),
|
|
524
|
-
codex.isAvailable(),
|
|
525
|
-
cursor.isAvailable()
|
|
526
|
-
]);
|
|
527
|
-
return {
|
|
528
|
-
sdk: true,
|
|
529
|
-
claude: claudeAvailable,
|
|
530
|
-
codex: codexAvailable,
|
|
531
|
-
cursor: cursorAvailable
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* List available backends with info
|
|
536
|
-
*/
|
|
537
|
-
async function listBackends() {
|
|
538
|
-
const availability = await checkBackends();
|
|
539
|
-
return [
|
|
540
|
-
{
|
|
541
|
-
type: "sdk",
|
|
542
|
-
available: availability.sdk,
|
|
543
|
-
name: "Vercel AI SDK"
|
|
544
|
-
},
|
|
545
|
-
{
|
|
546
|
-
type: "claude",
|
|
547
|
-
available: availability.claude,
|
|
548
|
-
name: "Claude Code CLI"
|
|
549
|
-
},
|
|
550
|
-
{
|
|
551
|
-
type: "codex",
|
|
552
|
-
available: availability.codex,
|
|
553
|
-
name: "OpenAI Codex CLI"
|
|
554
|
-
},
|
|
555
|
-
{
|
|
556
|
-
type: "cursor",
|
|
557
|
-
available: availability.cursor,
|
|
558
|
-
name: "Cursor Agent CLI"
|
|
559
|
-
}
|
|
560
|
-
];
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
//#endregion
|
|
564
|
-
export { CursorCliBackend as a, FRONTIER_MODELS as c, createModelAsync as d, getDefaultModel as f, SdkBackend as i, SUPPORTED_PROVIDERS as l, createBackend as n, CodexCliBackend as o, listBackends as r, ClaudeCliBackend as s, checkBackends as t, createModel as u };
|