agent-worker 0.12.0 → 0.13.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/dist/backends-BWzhErjT.mjs +3 -0
- package/dist/{backends-DLaP0rMW.mjs → backends-CziIqKRg.mjs} +287 -100
- package/dist/cli/index.mjs +24 -15
- package/dist/index.d.mts +51 -7
- package/dist/index.mjs +2 -2
- package/dist/{runner-CQJYnM7D.mjs → runner-CnxROIev.mjs} +8 -1
- package/dist/{worker-CJ5_b2_q.mjs → worker-DBJ8136Q.mjs} +4 -2
- package/dist/{workflow-CNlUyGit.mjs → workflow-CIE3WPNx.mjs} +27 -2
- package/package.json +4 -2
- package/dist/backends-DG5igQii.mjs +0 -3
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { C as CLAUDE_MODEL_MAP, D as SDK_MODEL_ALIASES, E as OPENCODE_MODEL_MAP, O as getModelForBackend, S as BACKEND_DEFAULT_MODELS, T as CURSOR_MODEL_MAP, _ as extractCodexResult, a as createMockBackend, b as execWithIdleTimeout, c as extractOpenCodeResult, d as CodexBackend, f as ClaudeCodeBackend, g as extractClaudeResult, h as createStreamParser, i as MockAIBackend, k as normalizeBackendType, l as opencodeAdapter, m as codexAdapter, n as createBackend, o as SdkBackend, p as claudeAdapter, r as listBackends, s as OpenCodeBackend, t as checkBackends, u as CursorBackend, v as formatEvent, w as CODEX_MODEL_MAP, x as DEFAULT_IDLE_TIMEOUT, y as IdleTimeoutError } from "./backends-CziIqKRg.mjs";
|
|
2
|
+
|
|
3
|
+
export { listBackends };
|
|
@@ -6,30 +6,45 @@ import { stringify } from "yaml";
|
|
|
6
6
|
|
|
7
7
|
//#region src/agent/models.ts
|
|
8
8
|
const providerCache = {};
|
|
9
|
+
/** Provider SDK package mapping */
|
|
10
|
+
const PROVIDER_PACKAGES = {
|
|
11
|
+
anthropic: {
|
|
12
|
+
package: "@ai-sdk/anthropic",
|
|
13
|
+
export: "anthropic"
|
|
14
|
+
},
|
|
15
|
+
openai: {
|
|
16
|
+
package: "@ai-sdk/openai",
|
|
17
|
+
export: "openai"
|
|
18
|
+
},
|
|
19
|
+
deepseek: {
|
|
20
|
+
package: "@ai-sdk/deepseek",
|
|
21
|
+
export: "deepseek"
|
|
22
|
+
},
|
|
23
|
+
google: {
|
|
24
|
+
package: "@ai-sdk/google",
|
|
25
|
+
export: "google"
|
|
26
|
+
},
|
|
27
|
+
groq: {
|
|
28
|
+
package: "@ai-sdk/groq",
|
|
29
|
+
export: "groq"
|
|
30
|
+
},
|
|
31
|
+
mistral: {
|
|
32
|
+
package: "@ai-sdk/mistral",
|
|
33
|
+
export: "mistral"
|
|
34
|
+
},
|
|
35
|
+
xai: {
|
|
36
|
+
package: "@ai-sdk/xai",
|
|
37
|
+
export: "xai"
|
|
38
|
+
}
|
|
39
|
+
};
|
|
9
40
|
/**
|
|
10
|
-
* Lazy load a provider, caching the result
|
|
11
|
-
*
|
|
41
|
+
* Lazy load a provider SDK, caching the result.
|
|
42
|
+
* Only caches standard providers (no custom baseURL/apiKey).
|
|
12
43
|
*/
|
|
13
|
-
async function loadProvider(name, packageName, exportName
|
|
44
|
+
async function loadProvider(name, packageName, exportName) {
|
|
14
45
|
if (name in providerCache) return providerCache[name] ?? null;
|
|
15
46
|
try {
|
|
16
|
-
const
|
|
17
|
-
if (options?.baseURL || options?.apiKeyEnvVar) {
|
|
18
|
-
const createProvider = module[`create${exportName.charAt(0).toUpperCase() + exportName.slice(1)}`];
|
|
19
|
-
if (createProvider) {
|
|
20
|
-
const providerOptions = {};
|
|
21
|
-
if (options.baseURL) providerOptions.baseURL = options.baseURL;
|
|
22
|
-
if (options.apiKeyEnvVar) {
|
|
23
|
-
const apiKey = process.env[options.apiKeyEnvVar];
|
|
24
|
-
if (!apiKey) throw new Error(`Environment variable ${options.apiKeyEnvVar} is not set (required for ${name} provider)`);
|
|
25
|
-
providerOptions.apiKey = apiKey;
|
|
26
|
-
}
|
|
27
|
-
const provider = createProvider(providerOptions);
|
|
28
|
-
providerCache[name] = provider;
|
|
29
|
-
return provider;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
const exportedProvider = module[exportName];
|
|
47
|
+
const exportedProvider = (await import(packageName))[exportName];
|
|
33
48
|
providerCache[name] = exportedProvider;
|
|
34
49
|
return exportedProvider;
|
|
35
50
|
} catch {
|
|
@@ -38,6 +53,55 @@ async function loadProvider(name, packageName, exportName, options) {
|
|
|
38
53
|
}
|
|
39
54
|
}
|
|
40
55
|
/**
|
|
56
|
+
* Create a provider instance with custom baseURL and/or apiKey.
|
|
57
|
+
* Not cached — each call creates a fresh instance.
|
|
58
|
+
*/
|
|
59
|
+
async function createCustomProvider(packageName, exportName, options) {
|
|
60
|
+
const createFn = (await import(packageName))[`create${exportName.charAt(0).toUpperCase() + exportName.slice(1)}`];
|
|
61
|
+
if (!createFn) throw new Error(`Package ${packageName} does not export create${exportName.charAt(0).toUpperCase() + exportName.slice(1)}`);
|
|
62
|
+
return createFn(options);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Resolve api_key field: '$ENV_VAR' → process.env.ENV_VAR, literal → as-is
|
|
66
|
+
*/
|
|
67
|
+
function resolveApiKey(apiKey) {
|
|
68
|
+
if (apiKey.startsWith("$")) {
|
|
69
|
+
const envVar = apiKey.slice(1);
|
|
70
|
+
const value = process.env[envVar];
|
|
71
|
+
if (!value) throw new Error(`Environment variable ${envVar} is not set`);
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
return apiKey;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a model using explicit provider configuration.
|
|
78
|
+
* Use this when provider details (base_url, api_key) are specified separately from the model name.
|
|
79
|
+
*
|
|
80
|
+
* Example:
|
|
81
|
+
* createModelWithProvider("MiniMax-M2.5", { name: "anthropic", base_url: "https://api.minimax.io/anthropic/v1", api_key: "$MINIMAX_API_KEY" })
|
|
82
|
+
*/
|
|
83
|
+
async function createModelWithProvider(modelName, provider) {
|
|
84
|
+
if (typeof provider === "string") {
|
|
85
|
+
const pkg = PROVIDER_PACKAGES[provider];
|
|
86
|
+
if (!pkg) throw new Error(`Unknown provider: ${provider}. Supported: ${Object.keys(PROVIDER_PACKAGES).join(", ")}`);
|
|
87
|
+
const providerFn = await loadProvider(provider, pkg.package, pkg.export);
|
|
88
|
+
if (!providerFn) throw new Error(`Install ${pkg.package} to use ${provider} models directly`);
|
|
89
|
+
return providerFn(modelName);
|
|
90
|
+
}
|
|
91
|
+
const { name, base_url, api_key } = provider;
|
|
92
|
+
const pkg = PROVIDER_PACKAGES[name];
|
|
93
|
+
if (!pkg) throw new Error(`Unknown provider: ${name}. Supported: ${Object.keys(PROVIDER_PACKAGES).join(", ")}`);
|
|
94
|
+
if (!base_url && !api_key) {
|
|
95
|
+
const providerFn = await loadProvider(name, pkg.package, pkg.export);
|
|
96
|
+
if (!providerFn) throw new Error(`Install ${pkg.package} to use ${name} models directly`);
|
|
97
|
+
return providerFn(modelName);
|
|
98
|
+
}
|
|
99
|
+
const opts = {};
|
|
100
|
+
if (base_url) opts.baseURL = base_url;
|
|
101
|
+
if (api_key) opts.apiKey = resolveApiKey(api_key);
|
|
102
|
+
return (await createCustomProvider(pkg.package, pkg.export, opts))(modelName);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
41
105
|
* Parse model identifier and return the appropriate provider model
|
|
42
106
|
*
|
|
43
107
|
* Supports three formats:
|
|
@@ -89,61 +153,14 @@ async function createModelAsync(modelId) {
|
|
|
89
153
|
const provider = modelId.slice(0, colonIndex);
|
|
90
154
|
const modelName = modelId.slice(colonIndex + 1);
|
|
91
155
|
if (!modelName) throw new Error(`Invalid model identifier: ${modelId}. Model name is required.`);
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
export: "anthropic"
|
|
96
|
-
},
|
|
97
|
-
openai: {
|
|
98
|
-
package: "@ai-sdk/openai",
|
|
99
|
-
export: "openai"
|
|
100
|
-
},
|
|
101
|
-
deepseek: {
|
|
102
|
-
package: "@ai-sdk/deepseek",
|
|
103
|
-
export: "deepseek"
|
|
104
|
-
},
|
|
105
|
-
google: {
|
|
106
|
-
package: "@ai-sdk/google",
|
|
107
|
-
export: "google"
|
|
108
|
-
},
|
|
109
|
-
groq: {
|
|
110
|
-
package: "@ai-sdk/groq",
|
|
111
|
-
export: "groq"
|
|
112
|
-
},
|
|
113
|
-
mistral: {
|
|
114
|
-
package: "@ai-sdk/mistral",
|
|
115
|
-
export: "mistral"
|
|
116
|
-
},
|
|
117
|
-
xai: {
|
|
118
|
-
package: "@ai-sdk/xai",
|
|
119
|
-
export: "xai"
|
|
120
|
-
},
|
|
121
|
-
minimax: {
|
|
122
|
-
package: "@ai-sdk/anthropic",
|
|
123
|
-
export: "anthropic",
|
|
124
|
-
options: {
|
|
125
|
-
baseURL: "https://api.minimax.io/anthropic/v1",
|
|
126
|
-
apiKeyEnvVar: "MINIMAX_API_KEY"
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
minimax_cn: {
|
|
130
|
-
package: "@ai-sdk/anthropic",
|
|
131
|
-
export: "anthropic",
|
|
132
|
-
options: {
|
|
133
|
-
baseURL: "https://api.minimaxi.com/anthropic/v1",
|
|
134
|
-
apiKeyEnvVar: "MINIMAX_CN_API_KEY"
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
const config = providerConfigs[provider];
|
|
139
|
-
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)`);
|
|
140
|
-
const providerFn = await loadProvider(provider, config.package, config.export, config.options);
|
|
156
|
+
const config = PROVIDER_PACKAGES[provider];
|
|
157
|
+
if (!config) throw new Error(`Unknown provider: ${provider}. Supported: ${Object.keys(PROVIDER_PACKAGES).join(", ")}. Or use gateway format: provider/model (e.g., openai/gpt-5.2)`);
|
|
158
|
+
const providerFn = await loadProvider(provider, config.package, config.export);
|
|
141
159
|
if (!providerFn) throw new Error(`Install ${config.package} to use ${provider} models directly`);
|
|
142
160
|
return providerFn(modelName);
|
|
143
161
|
}
|
|
144
162
|
/**
|
|
145
163
|
* List of supported providers for direct access
|
|
146
|
-
* Note: minimax uses Claude-compatible API via @ai-sdk/anthropic with custom baseURL
|
|
147
164
|
*/
|
|
148
165
|
const SUPPORTED_PROVIDERS = [
|
|
149
166
|
"anthropic",
|
|
@@ -152,8 +169,7 @@ const SUPPORTED_PROVIDERS = [
|
|
|
152
169
|
"google",
|
|
153
170
|
"groq",
|
|
154
171
|
"mistral",
|
|
155
|
-
"xai"
|
|
156
|
-
"minimax"
|
|
172
|
+
"xai"
|
|
157
173
|
];
|
|
158
174
|
/**
|
|
159
175
|
* Default provider when none specified
|
|
@@ -192,8 +208,7 @@ const FRONTIER_MODELS = {
|
|
|
192
208
|
"pixtral-large-latest",
|
|
193
209
|
"magistral-medium-2506"
|
|
194
210
|
],
|
|
195
|
-
xai: ["grok-4", "grok-4-fast-reasoning"]
|
|
196
|
-
minimax: ["MiniMax-M2"]
|
|
211
|
+
xai: ["grok-4", "grok-4-fast-reasoning"]
|
|
197
212
|
};
|
|
198
213
|
|
|
199
214
|
//#endregion
|
|
@@ -209,7 +224,8 @@ const BACKEND_DEFAULT_MODELS = {
|
|
|
209
224
|
default: "claude-sonnet-4-5",
|
|
210
225
|
claude: "sonnet",
|
|
211
226
|
cursor: "sonnet-4.5",
|
|
212
|
-
codex: "gpt-5.2-codex"
|
|
227
|
+
codex: "gpt-5.2-codex",
|
|
228
|
+
opencode: "deepseek/deepseek-chat"
|
|
213
229
|
};
|
|
214
230
|
/**
|
|
215
231
|
* Model aliases for SDK (Anthropic format)
|
|
@@ -272,6 +288,22 @@ const CODEX_MODEL_MAP = {
|
|
|
272
288
|
"o3-mini": "o3-mini"
|
|
273
289
|
};
|
|
274
290
|
/**
|
|
291
|
+
* Model translation for OpenCode CLI backend
|
|
292
|
+
* OpenCode uses provider/model format natively
|
|
293
|
+
*/
|
|
294
|
+
const OPENCODE_MODEL_MAP = {
|
|
295
|
+
"deepseek-chat": "deepseek/deepseek-chat",
|
|
296
|
+
"deepseek-reasoner": "deepseek/deepseek-reasoner",
|
|
297
|
+
"deepseek/deepseek-chat": "deepseek/deepseek-chat",
|
|
298
|
+
"deepseek/deepseek-reasoner": "deepseek/deepseek-reasoner",
|
|
299
|
+
sonnet: "anthropic/claude-sonnet-4-5-20250514",
|
|
300
|
+
opus: "anthropic/claude-opus-4-20250514",
|
|
301
|
+
"claude-sonnet-4-5": "anthropic/claude-sonnet-4-5-20250514",
|
|
302
|
+
"claude-opus-4": "anthropic/claude-opus-4-20250514",
|
|
303
|
+
"gpt-5.2": "openai/gpt-5.2",
|
|
304
|
+
o3: "openai/o3"
|
|
305
|
+
};
|
|
306
|
+
/**
|
|
275
307
|
* Get the model name for a specific backend
|
|
276
308
|
* Translates generic model names to backend-specific format
|
|
277
309
|
*/
|
|
@@ -283,6 +315,7 @@ function getModelForBackend(model, backend) {
|
|
|
283
315
|
case "cursor": return CURSOR_MODEL_MAP[model] || CURSOR_MODEL_MAP[normalizedModel] || normalizedModel;
|
|
284
316
|
case "claude": return CLAUDE_MODEL_MAP[model] || CLAUDE_MODEL_MAP[normalizedModel] || normalizedModel;
|
|
285
317
|
case "codex": return CODEX_MODEL_MAP[model] || CODEX_MODEL_MAP[normalizedModel] || normalizedModel;
|
|
318
|
+
case "opencode": return OPENCODE_MODEL_MAP[model] || OPENCODE_MODEL_MAP[normalizedModel] || model;
|
|
286
319
|
default: return normalizedModel;
|
|
287
320
|
}
|
|
288
321
|
}
|
|
@@ -931,8 +964,7 @@ var CodexBackend = class {
|
|
|
931
964
|
//#region src/backends/cursor.ts
|
|
932
965
|
/**
|
|
933
966
|
* Cursor CLI backend
|
|
934
|
-
* Uses `cursor agent -p`
|
|
935
|
-
* for non-interactive mode with stream-json output
|
|
967
|
+
* Uses `cursor agent -p` for non-interactive mode with stream-json output
|
|
936
968
|
*
|
|
937
969
|
* MCP Configuration:
|
|
938
970
|
* Cursor uses project-level MCP config via .cursor/mcp.json in the workspace.
|
|
@@ -943,7 +975,7 @@ var CodexBackend = class {
|
|
|
943
975
|
var CursorBackend = class {
|
|
944
976
|
type = "cursor";
|
|
945
977
|
options;
|
|
946
|
-
/** Resolved command: "cursor" (subcommand style)
|
|
978
|
+
/** Resolved command: "cursor" (subcommand style) */
|
|
947
979
|
resolvedCommand = null;
|
|
948
980
|
constructor(options = {}) {
|
|
949
981
|
this.options = {
|
|
@@ -994,7 +1026,7 @@ var CursorBackend = class {
|
|
|
994
1026
|
}
|
|
995
1027
|
/**
|
|
996
1028
|
* Resolve which cursor command is available.
|
|
997
|
-
*
|
|
1029
|
+
* Checks `cursor agent --version` (subcommand style).
|
|
998
1030
|
* Result is cached after first resolution.
|
|
999
1031
|
*/
|
|
1000
1032
|
async resolveCommand() {
|
|
@@ -1007,14 +1039,6 @@ var CursorBackend = class {
|
|
|
1007
1039
|
this.resolvedCommand = "cursor";
|
|
1008
1040
|
return "cursor";
|
|
1009
1041
|
} catch {}
|
|
1010
|
-
try {
|
|
1011
|
-
await execa("cursor-agent", ["--version"], {
|
|
1012
|
-
stdin: "ignore",
|
|
1013
|
-
timeout: 2e3
|
|
1014
|
-
});
|
|
1015
|
-
this.resolvedCommand = "cursor-agent";
|
|
1016
|
-
return "cursor-agent";
|
|
1017
|
-
} catch {}
|
|
1018
1042
|
return null;
|
|
1019
1043
|
}
|
|
1020
1044
|
async buildCommand(message) {
|
|
@@ -1027,16 +1051,161 @@ var CursorBackend = class {
|
|
|
1027
1051
|
message
|
|
1028
1052
|
];
|
|
1029
1053
|
if (this.options.model) agentArgs.push("--model", this.options.model);
|
|
1030
|
-
if (cmd
|
|
1054
|
+
if (!cmd) throw new Error("cursor agent CLI not found");
|
|
1055
|
+
return {
|
|
1031
1056
|
command: "cursor",
|
|
1032
1057
|
args: ["agent", ...agentArgs]
|
|
1033
1058
|
};
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
//#endregion
|
|
1063
|
+
//#region src/backends/opencode.ts
|
|
1064
|
+
/**
|
|
1065
|
+
* OpenCode CLI backend
|
|
1066
|
+
* Uses `opencode run` for non-interactive mode with JSON event output
|
|
1067
|
+
*
|
|
1068
|
+
* MCP Configuration:
|
|
1069
|
+
* OpenCode uses project-level MCP config via opencode.json in the workspace.
|
|
1070
|
+
* Use setWorkspace() to set up a dedicated workspace with MCP config.
|
|
1071
|
+
*
|
|
1072
|
+
* @see https://opencode.ai/docs/
|
|
1073
|
+
*/
|
|
1074
|
+
var OpenCodeBackend = class {
|
|
1075
|
+
type = "opencode";
|
|
1076
|
+
options;
|
|
1077
|
+
constructor(options = {}) {
|
|
1078
|
+
this.options = {
|
|
1079
|
+
timeout: DEFAULT_IDLE_TIMEOUT,
|
|
1080
|
+
...options
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Set up workspace directory with MCP config
|
|
1085
|
+
* Creates opencode.json in the workspace with MCP server config
|
|
1086
|
+
*/
|
|
1087
|
+
setWorkspace(workspaceDir, mcpConfig) {
|
|
1088
|
+
this.options.workspace = workspaceDir;
|
|
1089
|
+
if (!existsSync(workspaceDir)) mkdirSync(workspaceDir, { recursive: true });
|
|
1090
|
+
const opencodeMcp = {};
|
|
1091
|
+
for (const [name, config] of Object.entries(mcpConfig.mcpServers)) {
|
|
1092
|
+
const serverConfig = config;
|
|
1093
|
+
opencodeMcp[name] = {
|
|
1094
|
+
type: "local",
|
|
1095
|
+
command: [serverConfig.command, ...serverConfig.args || []],
|
|
1096
|
+
enabled: true,
|
|
1097
|
+
...serverConfig.env ? { environment: serverConfig.env } : {}
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
const opencodeConfig = {
|
|
1101
|
+
$schema: "https://opencode.ai/config.json",
|
|
1102
|
+
mcp: opencodeMcp
|
|
1103
|
+
};
|
|
1104
|
+
writeFileSync(join(workspaceDir, "opencode.json"), JSON.stringify(opencodeConfig, null, 2));
|
|
1105
|
+
}
|
|
1106
|
+
async send(message, _options) {
|
|
1107
|
+
const args = this.buildArgs(message);
|
|
1108
|
+
const cwd = this.options.workspace || this.options.cwd;
|
|
1109
|
+
const timeout = this.options.timeout ?? DEFAULT_IDLE_TIMEOUT;
|
|
1110
|
+
try {
|
|
1111
|
+
const { stdout } = await execWithIdleTimeout({
|
|
1112
|
+
command: "opencode",
|
|
1113
|
+
args,
|
|
1114
|
+
cwd,
|
|
1115
|
+
timeout,
|
|
1116
|
+
onStdout: this.options.streamCallbacks ? createStreamParser(this.options.streamCallbacks, "OpenCode", opencodeAdapter) : void 0
|
|
1117
|
+
});
|
|
1118
|
+
return extractOpenCodeResult(stdout);
|
|
1119
|
+
} catch (error) {
|
|
1120
|
+
if (error instanceof IdleTimeoutError) throw new Error(`opencode timed out after ${timeout}ms of inactivity`);
|
|
1121
|
+
if (error && typeof error === "object" && "exitCode" in error) {
|
|
1122
|
+
const execError = error;
|
|
1123
|
+
throw new Error(`opencode failed (exit ${execError.exitCode}): ${execError.stderr || execError.shortMessage}`);
|
|
1124
|
+
}
|
|
1125
|
+
throw error;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
async isAvailable() {
|
|
1129
|
+
try {
|
|
1130
|
+
await execa("opencode", ["--version"], {
|
|
1131
|
+
stdin: "ignore",
|
|
1132
|
+
timeout: 5e3
|
|
1133
|
+
});
|
|
1134
|
+
return true;
|
|
1135
|
+
} catch {
|
|
1136
|
+
return false;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
getInfo() {
|
|
1140
|
+
return {
|
|
1141
|
+
name: "OpenCode CLI",
|
|
1142
|
+
model: this.options.model
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
buildArgs(message) {
|
|
1146
|
+
const args = [
|
|
1147
|
+
"run",
|
|
1148
|
+
"--format",
|
|
1149
|
+
"json",
|
|
1150
|
+
message
|
|
1151
|
+
];
|
|
1152
|
+
if (this.options.model) args.push("--model", this.options.model);
|
|
1153
|
+
return args;
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
/**
|
|
1157
|
+
* Adapter for OpenCode --format json output.
|
|
1158
|
+
*
|
|
1159
|
+
* Events:
|
|
1160
|
+
* { type: "step_start", sessionID: "..." }
|
|
1161
|
+
* { type: "tool_use", part: { tool: "bash", state: { input: {...} } } }
|
|
1162
|
+
* { type: "text", part: { text: "..." } } → skipped (result only)
|
|
1163
|
+
* { type: "step_finish", part: { cost, tokens } }
|
|
1164
|
+
*/
|
|
1165
|
+
const opencodeAdapter = (raw) => {
|
|
1166
|
+
const event = raw;
|
|
1167
|
+
if (event.type === "step_start") return {
|
|
1168
|
+
kind: "init",
|
|
1169
|
+
sessionId: event.sessionID
|
|
1170
|
+
};
|
|
1171
|
+
if (event.type === "tool_use") {
|
|
1172
|
+
const { tool, state } = event.part;
|
|
1173
|
+
const args = state.input ? JSON.stringify(state.input) : "";
|
|
1034
1174
|
return {
|
|
1035
|
-
|
|
1036
|
-
|
|
1175
|
+
kind: "tool_call",
|
|
1176
|
+
name: tool,
|
|
1177
|
+
args: args.length > 100 ? args.slice(0, 100) + "..." : args
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
if (event.type === "text") return { kind: "skip" };
|
|
1181
|
+
if (event.type === "step_finish") {
|
|
1182
|
+
const { cost, tokens } = event.part;
|
|
1183
|
+
return {
|
|
1184
|
+
kind: "completed",
|
|
1185
|
+
costUsd: cost,
|
|
1186
|
+
usage: tokens ? {
|
|
1187
|
+
input: tokens.input,
|
|
1188
|
+
output: tokens.output
|
|
1189
|
+
} : void 0
|
|
1037
1190
|
};
|
|
1038
1191
|
}
|
|
1192
|
+
return null;
|
|
1039
1193
|
};
|
|
1194
|
+
/**
|
|
1195
|
+
* Extract final result from OpenCode --format json output.
|
|
1196
|
+
*
|
|
1197
|
+
* Priority:
|
|
1198
|
+
* 1. Last text event
|
|
1199
|
+
* 2. Raw stdout fallback
|
|
1200
|
+
*/
|
|
1201
|
+
function extractOpenCodeResult(stdout) {
|
|
1202
|
+
const lines = stdout.trim().split("\n");
|
|
1203
|
+
for (let i = lines.length - 1; i >= 0; i--) try {
|
|
1204
|
+
const event = JSON.parse(lines[i]);
|
|
1205
|
+
if (event.type === "text" && event.part?.text) return { content: event.part.text };
|
|
1206
|
+
} catch {}
|
|
1207
|
+
return { content: stdout.trim() };
|
|
1208
|
+
}
|
|
1040
1209
|
|
|
1041
1210
|
//#endregion
|
|
1042
1211
|
//#region src/backends/sdk.ts
|
|
@@ -1049,15 +1218,17 @@ var SdkBackend = class {
|
|
|
1049
1218
|
modelId;
|
|
1050
1219
|
model = null;
|
|
1051
1220
|
maxTokens;
|
|
1221
|
+
provider;
|
|
1052
1222
|
constructor(options) {
|
|
1053
1223
|
this.modelId = options.model;
|
|
1054
1224
|
this.maxTokens = options.maxTokens ?? 4096;
|
|
1055
|
-
|
|
1225
|
+
this.provider = options.provider;
|
|
1226
|
+
if (!this.provider) try {
|
|
1056
1227
|
this.model = createModel(this.modelId);
|
|
1057
1228
|
} catch {}
|
|
1058
1229
|
}
|
|
1059
1230
|
async send(message, options) {
|
|
1060
|
-
if (!this.model) this.model = await createModelAsync(this.modelId);
|
|
1231
|
+
if (!this.model) this.model = this.provider ? await createModelWithProvider(this.modelId, this.provider) : await createModelAsync(this.modelId);
|
|
1061
1232
|
const result = await generateText({
|
|
1062
1233
|
model: this.model,
|
|
1063
1234
|
system: options?.system,
|
|
@@ -1075,7 +1246,7 @@ var SdkBackend = class {
|
|
|
1075
1246
|
}
|
|
1076
1247
|
async isAvailable() {
|
|
1077
1248
|
try {
|
|
1078
|
-
if (!this.model) this.model = await createModelAsync(this.modelId);
|
|
1249
|
+
if (!this.model) this.model = this.provider ? await createModelWithProvider(this.modelId, this.provider) : await createModelAsync(this.modelId);
|
|
1079
1250
|
return true;
|
|
1080
1251
|
} catch {
|
|
1081
1252
|
return false;
|
|
@@ -1133,10 +1304,14 @@ function createBackend(config) {
|
|
|
1133
1304
|
};
|
|
1134
1305
|
const model = getModelForBackend(normalized.model, normalized.type);
|
|
1135
1306
|
switch (normalized.type) {
|
|
1136
|
-
case "default":
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1307
|
+
case "default": {
|
|
1308
|
+
const provider = normalized.provider;
|
|
1309
|
+
return new SdkBackend({
|
|
1310
|
+
model,
|
|
1311
|
+
maxTokens: normalized.maxTokens,
|
|
1312
|
+
provider
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1140
1315
|
case "claude": return new ClaudeCodeBackend({
|
|
1141
1316
|
...normalized.options,
|
|
1142
1317
|
model
|
|
@@ -1149,6 +1324,10 @@ function createBackend(config) {
|
|
|
1149
1324
|
...normalized.options,
|
|
1150
1325
|
model
|
|
1151
1326
|
});
|
|
1327
|
+
case "opencode": return new OpenCodeBackend({
|
|
1328
|
+
...normalized.options,
|
|
1329
|
+
model
|
|
1330
|
+
});
|
|
1152
1331
|
default: throw new Error(`Unknown backend type: ${normalized.type}`);
|
|
1153
1332
|
}
|
|
1154
1333
|
}
|
|
@@ -1163,16 +1342,19 @@ async function checkBackends() {
|
|
|
1163
1342
|
const claude = new ClaudeCodeBackend();
|
|
1164
1343
|
const codex = new CodexBackend();
|
|
1165
1344
|
const cursor = new CursorBackend();
|
|
1166
|
-
const
|
|
1345
|
+
const opencode = new OpenCodeBackend();
|
|
1346
|
+
const [claudeAvailable, codexAvailable, cursorAvailable, opencodeAvailable] = await Promise.all([
|
|
1167
1347
|
withTimeout(claude.isAvailable(), 3e3),
|
|
1168
1348
|
withTimeout(codex.isAvailable(), 3e3),
|
|
1169
|
-
withTimeout(cursor.isAvailable(), 3e3)
|
|
1349
|
+
withTimeout(cursor.isAvailable(), 3e3),
|
|
1350
|
+
withTimeout(opencode.isAvailable(), 3e3)
|
|
1170
1351
|
]);
|
|
1171
1352
|
return {
|
|
1172
1353
|
default: true,
|
|
1173
1354
|
claude: claudeAvailable,
|
|
1174
1355
|
codex: codexAvailable,
|
|
1175
1356
|
cursor: cursorAvailable,
|
|
1357
|
+
opencode: opencodeAvailable,
|
|
1176
1358
|
mock: true
|
|
1177
1359
|
};
|
|
1178
1360
|
}
|
|
@@ -1201,9 +1383,14 @@ async function listBackends() {
|
|
|
1201
1383
|
type: "cursor",
|
|
1202
1384
|
available: availability.cursor,
|
|
1203
1385
|
name: "Cursor Agent CLI"
|
|
1386
|
+
},
|
|
1387
|
+
{
|
|
1388
|
+
type: "opencode",
|
|
1389
|
+
available: availability.opencode,
|
|
1390
|
+
name: "OpenCode CLI"
|
|
1204
1391
|
}
|
|
1205
1392
|
];
|
|
1206
1393
|
}
|
|
1207
1394
|
|
|
1208
1395
|
//#endregion
|
|
1209
|
-
export {
|
|
1396
|
+
export { parseModel as A, CLAUDE_MODEL_MAP as C, SDK_MODEL_ALIASES as D, OPENCODE_MODEL_MAP as E, createModelWithProvider as F, getDefaultModel as I, SUPPORTED_PROVIDERS as M, createModel as N, getModelForBackend as O, createModelAsync as P, BACKEND_DEFAULT_MODELS as S, CURSOR_MODEL_MAP as T, extractCodexResult as _, createMockBackend as a, execWithIdleTimeout as b, extractOpenCodeResult as c, CodexBackend as d, ClaudeCodeBackend as f, extractClaudeResult as g, createStreamParser as h, MockAIBackend as i, FRONTIER_MODELS as j, normalizeBackendType as k, opencodeAdapter as l, codexAdapter as m, createBackend as n, SdkBackend as o, claudeAdapter as p, listBackends as r, OpenCodeBackend as s, checkBackends as t, CursorBackend as u, formatEvent as v, CODEX_MODEL_MAP as w, DEFAULT_IDLE_TIMEOUT as x, IdleTimeoutError as y };
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { t as AgentWorker } from "../worker-
|
|
2
|
+
import { I as getDefaultModel, j as FRONTIER_MODELS, k as normalizeBackendType, n as createBackend } from "../backends-CziIqKRg.mjs";
|
|
3
|
+
import { t as AgentWorker } from "../worker-DBJ8136Q.mjs";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
6
6
|
import { appendFile, mkdir, open, readFile, readdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -97,7 +97,8 @@ var LocalWorker = class {
|
|
|
97
97
|
model: config.model,
|
|
98
98
|
system: config.system,
|
|
99
99
|
tools: {},
|
|
100
|
-
backend
|
|
100
|
+
backend,
|
|
101
|
+
provider: config.provider
|
|
101
102
|
}, restore);
|
|
102
103
|
}
|
|
103
104
|
send(input, options) {
|
|
@@ -1545,7 +1546,7 @@ function createDaemonApp(optionsOrGetState) {
|
|
|
1545
1546
|
if (!s) return c.json({ error: "Not ready" }, 503);
|
|
1546
1547
|
const body = await parseJsonBody(c);
|
|
1547
1548
|
if (!body || typeof body !== "object") return c.json({ error: "Invalid JSON body" }, 400);
|
|
1548
|
-
const { name, model, system, backend = "default", workflow = "global", tag = "main" } = body;
|
|
1549
|
+
const { name, model, system, backend = "default", provider, workflow = "global", tag = "main" } = body;
|
|
1549
1550
|
if (!name || !model || !system) return c.json({ error: "name, model, system required" }, 400);
|
|
1550
1551
|
if (s.configs.has(name)) return c.json({ error: `Agent already exists: ${name}` }, 409);
|
|
1551
1552
|
const agentConfig = {
|
|
@@ -1553,6 +1554,7 @@ function createDaemonApp(optionsOrGetState) {
|
|
|
1553
1554
|
model,
|
|
1554
1555
|
system,
|
|
1555
1556
|
backend,
|
|
1557
|
+
provider,
|
|
1556
1558
|
workflow,
|
|
1557
1559
|
tag,
|
|
1558
1560
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1718,7 +1720,7 @@ function createDaemonApp(optionsOrGetState) {
|
|
|
1718
1720
|
const key = `${workflowName}:${tag}`;
|
|
1719
1721
|
if (s.workflows.has(key)) return c.json({ error: `Workflow already running: ${key}` }, 409);
|
|
1720
1722
|
try {
|
|
1721
|
-
const { runWorkflowWithControllers } = await import("../runner-
|
|
1723
|
+
const { runWorkflowWithControllers } = await import("../runner-CnxROIev.mjs");
|
|
1722
1724
|
const result = await runWorkflowWithControllers({
|
|
1723
1725
|
workflow,
|
|
1724
1726
|
workflowName,
|
|
@@ -2069,23 +2071,33 @@ function registerAgentCommands(program) {
|
|
|
2069
2071
|
"claude",
|
|
2070
2072
|
"codex",
|
|
2071
2073
|
"cursor",
|
|
2074
|
+
"opencode",
|
|
2072
2075
|
"mock"
|
|
2073
|
-
]).default("default")).option("-s, --system <prompt>", "System prompt", "You are a helpful assistant.").option("-f, --system-file <file>", "Read system prompt from file").option("--workflow <name>", "Workflow name (default: global)").option("--tag <tag>", "Workflow instance tag (default: main)").option("--port <port>", `Daemon port if starting new daemon (default: ${DEFAULT_PORT})`).option("--host <host>", "Daemon host (default: 127.0.0.1)").option("--json", "Output as JSON").addHelpText("after", `
|
|
2076
|
+
]).default("default")).option("--provider <name>", "Provider SDK name (e.g., anthropic, openai)").option("--base-url <url>", "Override provider base URL").option("--api-key <ref>", "API key env var (e.g., $MINIMAX_API_KEY)").option("-s, --system <prompt>", "System prompt", "You are a helpful assistant.").option("-f, --system-file <file>", "Read system prompt from file").option("--workflow <name>", "Workflow name (default: global)").option("--tag <tag>", "Workflow instance tag (default: main)").option("--port <port>", `Daemon port if starting new daemon (default: ${DEFAULT_PORT})`).option("--host <host>", "Daemon host (default: 127.0.0.1)").option("--json", "Output as JSON").addHelpText("after", `
|
|
2074
2077
|
Examples:
|
|
2075
2078
|
$ agent-worker new alice -m anthropic/claude-sonnet-4-5
|
|
2076
2079
|
$ agent-worker new bot -b mock
|
|
2077
2080
|
$ agent-worker new reviewer --workflow review --tag pr-123
|
|
2081
|
+
$ agent-worker new coder -m MiniMax-M2.5 --provider anthropic --base-url https://api.minimax.io/anthropic/v1 --api-key '$MINIMAX_API_KEY'
|
|
2078
2082
|
`).action(async (name, options) => {
|
|
2079
2083
|
let system = options.system;
|
|
2080
2084
|
if (options.systemFile) system = readFileSync(options.systemFile, "utf-8");
|
|
2081
2085
|
const backend = normalizeBackendType(options.backend ?? "default");
|
|
2082
2086
|
const model = options.model || getDefaultModel();
|
|
2087
|
+
let provider;
|
|
2088
|
+
if (options.provider) if (options.baseUrl || options.apiKey) provider = {
|
|
2089
|
+
name: options.provider,
|
|
2090
|
+
base_url: options.baseUrl,
|
|
2091
|
+
api_key: options.apiKey
|
|
2092
|
+
};
|
|
2093
|
+
else provider = options.provider;
|
|
2083
2094
|
await ensureDaemon(options.port ? parseInt(options.port, 10) : void 0, options.host);
|
|
2084
2095
|
const res = await createAgent({
|
|
2085
2096
|
name,
|
|
2086
2097
|
model,
|
|
2087
2098
|
system,
|
|
2088
2099
|
backend,
|
|
2100
|
+
provider,
|
|
2089
2101
|
workflow: options.workflow,
|
|
2090
2102
|
tag: options.tag
|
|
2091
2103
|
});
|
|
@@ -2339,7 +2351,7 @@ Examples:
|
|
|
2339
2351
|
|
|
2340
2352
|
Note: Workflow name is inferred from YAML 'name' field or filename
|
|
2341
2353
|
`).action(async (file, options) => {
|
|
2342
|
-
const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-
|
|
2354
|
+
const { parseWorkflowFile, runWorkflowWithControllers } = await import("../workflow-CIE3WPNx.mjs");
|
|
2343
2355
|
const tag = options.tag || DEFAULT_TAG;
|
|
2344
2356
|
const parsedWorkflow = await parseWorkflowFile(file, { tag });
|
|
2345
2357
|
const workflowName = parsedWorkflow.name;
|
|
@@ -2350,7 +2362,7 @@ Note: Workflow name is inferred from YAML 'name' field or filename
|
|
|
2350
2362
|
isCleaningUp = true;
|
|
2351
2363
|
console.log("\nInterrupted, cleaning up...");
|
|
2352
2364
|
if (controllers) {
|
|
2353
|
-
const { shutdownControllers } = await import("../workflow-
|
|
2365
|
+
const { shutdownControllers } = await import("../workflow-CIE3WPNx.mjs");
|
|
2354
2366
|
const { createSilentLogger } = await import("../logger-Bfdo83xL.mjs");
|
|
2355
2367
|
await shutdownControllers(controllers, createSilentLogger());
|
|
2356
2368
|
}
|
|
@@ -2423,7 +2435,7 @@ Workflow runs inside the daemon. Use ls/stop to manage:
|
|
|
2423
2435
|
|
|
2424
2436
|
Note: Workflow name is inferred from YAML 'name' field or filename
|
|
2425
2437
|
`).action(async (file, options) => {
|
|
2426
|
-
const { parseWorkflowFile } = await import("../workflow-
|
|
2438
|
+
const { parseWorkflowFile } = await import("../workflow-CIE3WPNx.mjs");
|
|
2427
2439
|
const { ensureDaemon } = await Promise.resolve().then(() => agent_exports);
|
|
2428
2440
|
const tag = options.tag || DEFAULT_TAG;
|
|
2429
2441
|
const parsedWorkflow = await parseWorkflowFile(file, { tag });
|
|
@@ -2574,10 +2586,6 @@ const PROVIDER_API_KEYS = {
|
|
|
2574
2586
|
xai: {
|
|
2575
2587
|
envVar: "XAI_API_KEY",
|
|
2576
2588
|
description: "xAI Grok"
|
|
2577
|
-
},
|
|
2578
|
-
minimax: {
|
|
2579
|
-
envVar: "MINIMAX_API_KEY",
|
|
2580
|
-
description: "MiniMax"
|
|
2581
2589
|
}
|
|
2582
2590
|
};
|
|
2583
2591
|
function registerInfoCommands(program) {
|
|
@@ -2598,10 +2606,11 @@ function registerInfoCommands(program) {
|
|
|
2598
2606
|
console.log(` Provider only: provider (e.g., openai → ${gatewayExample})`);
|
|
2599
2607
|
console.log(` Gateway format: provider/model (e.g., ${gatewayExample})`);
|
|
2600
2608
|
console.log(` Direct format: provider:model (e.g., ${directExample})`);
|
|
2609
|
+
console.log(` Custom endpoint: --provider anthropic --base-url <url> --api-key '$KEY'`);
|
|
2601
2610
|
console.log(`\nDefault: ${defaultModel} (when no model specified)`);
|
|
2602
2611
|
});
|
|
2603
2612
|
program.command("backends").description("Check available backends (SDK, CLI tools)").action(async () => {
|
|
2604
|
-
const { listBackends } = await import("../backends-
|
|
2613
|
+
const { listBackends } = await import("../backends-BWzhErjT.mjs");
|
|
2605
2614
|
const backends = await listBackends();
|
|
2606
2615
|
console.log("Backend Status:\n");
|
|
2607
2616
|
for (const backend of backends) {
|
|
@@ -2681,7 +2690,7 @@ async function resolveDir(targetInput) {
|
|
|
2681
2690
|
|
|
2682
2691
|
//#endregion
|
|
2683
2692
|
//#region package.json
|
|
2684
|
-
var version = "0.
|
|
2693
|
+
var version = "0.13.0";
|
|
2685
2694
|
|
|
2686
2695
|
//#endregion
|
|
2687
2696
|
//#region src/cli/index.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,27 @@
|
|
|
1
1
|
import { LanguageModel } from "ai";
|
|
2
2
|
import { BashToolkit, CreateBashToolOptions, createBashTool } from "bash-tool";
|
|
3
3
|
|
|
4
|
+
//#region src/workflow/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Custom provider configuration for API endpoint overrides.
|
|
7
|
+
* Allows pointing any compatible SDK at a different base URL.
|
|
8
|
+
*
|
|
9
|
+
* Examples:
|
|
10
|
+
* provider: anthropic # string → built-in provider
|
|
11
|
+
* provider: # object → custom endpoint
|
|
12
|
+
* name: anthropic
|
|
13
|
+
* base_url: https://api.minimax.io/anthropic/v1
|
|
14
|
+
* api_key: $MINIMAX_API_KEY
|
|
15
|
+
*/
|
|
16
|
+
interface ProviderConfig {
|
|
17
|
+
/** Provider SDK name (e.g., 'anthropic', 'openai') */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Override base URL for the provider */
|
|
20
|
+
base_url?: string;
|
|
21
|
+
/** API key — env var reference with '$' prefix (e.g., '$MINIMAX_API_KEY') or literal value */
|
|
22
|
+
api_key?: string;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
4
25
|
//#region src/agent/types.d.ts
|
|
5
26
|
/**
|
|
6
27
|
* Message status for streaming/response tracking
|
|
@@ -132,7 +153,7 @@ interface Transcript {
|
|
|
132
153
|
* Both `backends/types.ts` and `workflow/controller/types.ts` re-export from this module.
|
|
133
154
|
*/
|
|
134
155
|
/** Backend type (union of all supported backends) */
|
|
135
|
-
type BackendType = "default" | "claude" | "cursor" | "codex" | "mock";
|
|
156
|
+
type BackendType = "default" | "claude" | "cursor" | "codex" | "opencode" | "mock";
|
|
136
157
|
//#endregion
|
|
137
158
|
//#region src/backends/types.d.ts
|
|
138
159
|
interface BackendConfig {
|
|
@@ -188,6 +209,8 @@ interface Backend {
|
|
|
188
209
|
interface AgentWorkerConfig extends SessionConfig {
|
|
189
210
|
/** CLI backend - when provided, send() delegates to this backend */
|
|
190
211
|
backend?: Backend;
|
|
212
|
+
/** Provider configuration — when set, model is resolved via createModelWithProvider */
|
|
213
|
+
provider?: string | ProviderConfig;
|
|
191
214
|
}
|
|
192
215
|
/**
|
|
193
216
|
* Step finish callback info
|
|
@@ -230,6 +253,7 @@ declare class AgentWorker {
|
|
|
230
253
|
private totalUsage;
|
|
231
254
|
private pendingApprovals;
|
|
232
255
|
private backend;
|
|
256
|
+
private provider;
|
|
233
257
|
private cachedAgent;
|
|
234
258
|
private toolsChanged;
|
|
235
259
|
/**
|
|
@@ -325,9 +349,8 @@ declare function createModel(modelId: string): LanguageModel;
|
|
|
325
349
|
declare function createModelAsync(modelId: string): Promise<LanguageModel>;
|
|
326
350
|
/**
|
|
327
351
|
* List of supported providers for direct access
|
|
328
|
-
* Note: minimax uses Claude-compatible API via @ai-sdk/anthropic with custom baseURL
|
|
329
352
|
*/
|
|
330
|
-
declare const SUPPORTED_PROVIDERS: readonly ["anthropic", "openai", "deepseek", "google", "groq", "mistral", "xai"
|
|
353
|
+
declare const SUPPORTED_PROVIDERS: readonly ["anthropic", "openai", "deepseek", "google", "groq", "mistral", "xai"];
|
|
331
354
|
type SupportedProvider = (typeof SUPPORTED_PROVIDERS)[number];
|
|
332
355
|
/**
|
|
333
356
|
* Frontier models for each provider (as of 2026-02)
|
|
@@ -344,7 +367,6 @@ declare const FRONTIER_MODELS: {
|
|
|
344
367
|
readonly groq: readonly ["meta-llama/llama-4-scout-17b-16e-instruct", "deepseek-r1-distill-llama-70b"];
|
|
345
368
|
readonly mistral: readonly ["mistral-large-latest", "pixtral-large-latest", "magistral-medium-2506"];
|
|
346
369
|
readonly xai: readonly ["grok-4", "grok-4-fast-reasoning"];
|
|
347
|
-
readonly minimax: readonly ["MiniMax-M2"];
|
|
348
370
|
};
|
|
349
371
|
//#endregion
|
|
350
372
|
//#region src/agent/tools/bash.d.ts
|
|
@@ -575,7 +597,7 @@ interface CursorOptions {
|
|
|
575
597
|
declare class CursorBackend implements Backend {
|
|
576
598
|
readonly type: "cursor";
|
|
577
599
|
private options;
|
|
578
|
-
/** Resolved command: "cursor" (subcommand style)
|
|
600
|
+
/** Resolved command: "cursor" (subcommand style) */
|
|
579
601
|
private resolvedCommand;
|
|
580
602
|
constructor(options?: CursorOptions);
|
|
581
603
|
/**
|
|
@@ -596,7 +618,7 @@ declare class CursorBackend implements Backend {
|
|
|
596
618
|
};
|
|
597
619
|
/**
|
|
598
620
|
* Resolve which cursor command is available.
|
|
599
|
-
*
|
|
621
|
+
* Checks `cursor agent --version` (subcommand style).
|
|
600
622
|
* Result is cached after first resolution.
|
|
601
623
|
*/
|
|
602
624
|
private resolveCommand;
|
|
@@ -606,18 +628,35 @@ declare class CursorBackend implements Backend {
|
|
|
606
628
|
}>;
|
|
607
629
|
}
|
|
608
630
|
//#endregion
|
|
631
|
+
//#region src/backends/opencode.d.ts
|
|
632
|
+
interface OpenCodeOptions {
|
|
633
|
+
/** Model to use in provider/model format (e.g., 'deepseek/deepseek-chat') */
|
|
634
|
+
model?: string;
|
|
635
|
+
/** Working directory (defaults to workspace if set) */
|
|
636
|
+
cwd?: string;
|
|
637
|
+
/** Workspace directory for agent isolation */
|
|
638
|
+
workspace?: string;
|
|
639
|
+
/** Idle timeout in milliseconds — kills process if no output for this duration */
|
|
640
|
+
timeout?: number;
|
|
641
|
+
/** Stream parser callbacks (structured event output) */
|
|
642
|
+
streamCallbacks?: StreamParserCallbacks;
|
|
643
|
+
}
|
|
644
|
+
//#endregion
|
|
609
645
|
//#region src/backends/sdk.d.ts
|
|
610
646
|
interface SdkBackendOptions {
|
|
611
|
-
/** Model identifier (e.g., 'openai/gpt-5.2' or 'anthropic:claude-sonnet-4-5') */
|
|
647
|
+
/** Model identifier (e.g., 'openai/gpt-5.2' or 'anthropic:claude-sonnet-4-5' or just 'MiniMax-M2.5' with provider) */
|
|
612
648
|
model: string;
|
|
613
649
|
/** Maximum tokens to generate */
|
|
614
650
|
maxTokens?: number;
|
|
651
|
+
/** Provider configuration — when set, model is a plain name resolved via the provider */
|
|
652
|
+
provider?: string | ProviderConfig;
|
|
615
653
|
}
|
|
616
654
|
declare class SdkBackend implements Backend {
|
|
617
655
|
readonly type: "default";
|
|
618
656
|
private modelId;
|
|
619
657
|
private model;
|
|
620
658
|
private maxTokens;
|
|
659
|
+
private provider;
|
|
621
660
|
constructor(options: SdkBackendOptions);
|
|
622
661
|
send(message: string, options?: {
|
|
623
662
|
system?: string;
|
|
@@ -656,6 +695,7 @@ type BackendOptions = {
|
|
|
656
695
|
type: "default";
|
|
657
696
|
model?: string;
|
|
658
697
|
maxTokens?: number;
|
|
698
|
+
provider?: string | ProviderConfig;
|
|
659
699
|
} | {
|
|
660
700
|
type: "claude";
|
|
661
701
|
model?: string;
|
|
@@ -668,6 +708,10 @@ type BackendOptions = {
|
|
|
668
708
|
type: "cursor";
|
|
669
709
|
model?: string;
|
|
670
710
|
options?: Omit<CursorOptions, "model">;
|
|
711
|
+
} | {
|
|
712
|
+
type: "opencode";
|
|
713
|
+
model?: string;
|
|
714
|
+
options?: Omit<OpenCodeOptions, "model">;
|
|
671
715
|
};
|
|
672
716
|
/**
|
|
673
717
|
* Create a backend instance
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as AgentWorker } from "./worker-
|
|
1
|
+
import { M as SUPPORTED_PROVIDERS, N as createModel, P as createModelAsync, a as createMockBackend, d as CodexBackend, f as ClaudeCodeBackend, i as MockAIBackend, j as FRONTIER_MODELS, n as createBackend, o as SdkBackend, r as listBackends, t as checkBackends, u as CursorBackend } from "./backends-CziIqKRg.mjs";
|
|
2
|
+
import { t as AgentWorker } from "./worker-DBJ8136Q.mjs";
|
|
3
3
|
import { jsonSchema, tool } from "ai";
|
|
4
4
|
import { createBashTool } from "bash-tool";
|
|
5
5
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as parseModel, P as createModelAsync, a as createMockBackend, n as createBackend } from "./backends-CziIqKRg.mjs";
|
|
2
2
|
import { T as EventLog, n as createFileContextProvider, t as FileContextProvider, v as createContextMCPServer } from "./cli/index.mjs";
|
|
3
3
|
import { n as createMemoryContextProvider } from "./memory-provider-BtLYtdQH.mjs";
|
|
4
4
|
import { createChannelLogger, createSilentLogger } from "./logger-Bfdo83xL.mjs";
|
|
@@ -825,6 +825,7 @@ function getBackendByType(backendType, options) {
|
|
|
825
825
|
return createBackend({
|
|
826
826
|
type: backendType,
|
|
827
827
|
model: options?.model,
|
|
828
|
+
...backendType === "default" && options?.provider ? { provider: options.provider } : {},
|
|
828
829
|
...Object.keys(backendOptions).length > 0 ? { options: backendOptions } : {}
|
|
829
830
|
});
|
|
830
831
|
}
|
|
@@ -835,6 +836,10 @@ function getBackendByType(backendType, options) {
|
|
|
835
836
|
* Prefer using getBackendByType with explicit backend field in workflow configs.
|
|
836
837
|
*/
|
|
837
838
|
function getBackendForModel(model, options) {
|
|
839
|
+
if (options?.provider) return getBackendByType("default", {
|
|
840
|
+
...options,
|
|
841
|
+
model
|
|
842
|
+
});
|
|
838
843
|
const { provider } = parseModel(model);
|
|
839
844
|
switch (provider) {
|
|
840
845
|
case "anthropic": return getBackendByType("default", {
|
|
@@ -1344,11 +1349,13 @@ async function runWorkflowWithControllers(config) {
|
|
|
1344
1349
|
if (createBackend) backend = createBackend(agentName, agentDef);
|
|
1345
1350
|
else if (agentDef.backend) backend = getBackendByType(agentDef.backend, {
|
|
1346
1351
|
model: agentDef.model,
|
|
1352
|
+
provider: agentDef.provider,
|
|
1347
1353
|
debugLog: (msg) => agentLogger.debug(msg),
|
|
1348
1354
|
streamCallbacks,
|
|
1349
1355
|
timeout: agentDef.timeout
|
|
1350
1356
|
});
|
|
1351
1357
|
else if (agentDef.model) backend = getBackendForModel(agentDef.model, {
|
|
1358
|
+
provider: agentDef.provider,
|
|
1352
1359
|
debugLog: (msg) => agentLogger.debug(msg),
|
|
1353
1360
|
streamCallbacks
|
|
1354
1361
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { F as createModelWithProvider, P as createModelAsync } from "./backends-CziIqKRg.mjs";
|
|
2
2
|
import { ToolLoopAgent, stepCountIs } from "ai";
|
|
3
3
|
|
|
4
4
|
//#region src/agent/worker.ts
|
|
@@ -30,6 +30,7 @@ var AgentWorker = class {
|
|
|
30
30
|
};
|
|
31
31
|
pendingApprovals = [];
|
|
32
32
|
backend;
|
|
33
|
+
provider;
|
|
33
34
|
cachedAgent = null;
|
|
34
35
|
toolsChanged = false;
|
|
35
36
|
/**
|
|
@@ -65,6 +66,7 @@ var AgentWorker = class {
|
|
|
65
66
|
this.maxTokens = config.maxTokens ?? 4096;
|
|
66
67
|
this.maxSteps = config.maxSteps ?? 200;
|
|
67
68
|
this.backend = config.backend ?? null;
|
|
69
|
+
this.provider = config.provider;
|
|
68
70
|
}
|
|
69
71
|
/**
|
|
70
72
|
* Check if a tool needs approval for given arguments
|
|
@@ -117,7 +119,7 @@ var AgentWorker = class {
|
|
|
117
119
|
async getAgent(autoApprove) {
|
|
118
120
|
if (!this.cachedAgent || this.toolsChanged || !autoApprove) {
|
|
119
121
|
this.cachedAgent = new ToolLoopAgent({
|
|
120
|
-
model: await createModelAsync(this.model),
|
|
122
|
+
model: this.provider ? await createModelWithProvider(this.model, this.provider) : await createModelAsync(this.model),
|
|
121
123
|
instructions: this.system,
|
|
122
124
|
tools: this.buildTools(autoApprove),
|
|
123
125
|
maxOutputTokens: this.maxTokens,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import "./backends-
|
|
1
|
+
import "./backends-CziIqKRg.mjs";
|
|
2
2
|
import { c as CONTEXT_DEFAULTS, i as resolveContextDir } from "./cli/index.mjs";
|
|
3
3
|
import "./memory-provider-BtLYtdQH.mjs";
|
|
4
4
|
import { createChannelLogger, createSilentLogger } from "./logger-Bfdo83xL.mjs";
|
|
5
|
-
import { a as runSdkAgent, c as buildAgentPrompt, createWorkflowProvider, d as createContext, f as interpolate, i as createAgentController, initWorkflow, l as formatInbox, n as getBackendForModel, o as runMockAgent, r as checkWorkflowIdle, runWorkflowWithControllers, s as generateWorkflowMCPConfig, shutdownControllers, t as getBackendByType, u as CONTROLLER_DEFAULTS } from "./runner-
|
|
5
|
+
import { a as runSdkAgent, c as buildAgentPrompt, createWorkflowProvider, d as createContext, f as interpolate, i as createAgentController, initWorkflow, l as formatInbox, n as getBackendForModel, o as runMockAgent, r as checkWorkflowIdle, runWorkflowWithControllers, s as generateWorkflowMCPConfig, shutdownControllers, t as getBackendByType, u as CONTROLLER_DEFAULTS } from "./runner-CnxROIev.mjs";
|
|
6
6
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
7
|
import { basename, dirname, join, resolve } from "node:path";
|
|
8
8
|
import { parse } from "yaml";
|
|
@@ -212,6 +212,7 @@ const CLI_BACKENDS = [
|
|
|
212
212
|
"claude",
|
|
213
213
|
"cursor",
|
|
214
214
|
"codex",
|
|
215
|
+
"opencode",
|
|
215
216
|
"mock"
|
|
216
217
|
];
|
|
217
218
|
function validateAgent(name, agent, errors) {
|
|
@@ -241,6 +242,30 @@ function validateAgent(name, agent, errors) {
|
|
|
241
242
|
path: `${path}.tools`,
|
|
242
243
|
message: "Optional field \"tools\" must be an array"
|
|
243
244
|
});
|
|
245
|
+
if (a.provider !== void 0) {
|
|
246
|
+
if (typeof a.provider === "string") {} else if (typeof a.provider === "object" && a.provider !== null && !Array.isArray(a.provider)) {
|
|
247
|
+
const p = a.provider;
|
|
248
|
+
if (!p.name || typeof p.name !== "string") errors.push({
|
|
249
|
+
path: `${path}.provider.name`,
|
|
250
|
+
message: "Field \"provider.name\" is required and must be a string"
|
|
251
|
+
});
|
|
252
|
+
if (p.base_url !== void 0 && typeof p.base_url !== "string") errors.push({
|
|
253
|
+
path: `${path}.provider.base_url`,
|
|
254
|
+
message: "Field \"provider.base_url\" must be a string"
|
|
255
|
+
});
|
|
256
|
+
if (p.api_key !== void 0 && typeof p.api_key !== "string") errors.push({
|
|
257
|
+
path: `${path}.provider.api_key`,
|
|
258
|
+
message: "Field \"provider.api_key\" must be a string"
|
|
259
|
+
});
|
|
260
|
+
} else errors.push({
|
|
261
|
+
path: `${path}.provider`,
|
|
262
|
+
message: "Field \"provider\" must be a string or object with { name, base_url?, api_key? }"
|
|
263
|
+
});
|
|
264
|
+
if (CLI_BACKENDS.includes(backend) && backend !== "mock") errors.push({
|
|
265
|
+
path: `${path}.provider`,
|
|
266
|
+
message: `Field "provider" is ignored for CLI backend "${backend}" (only works with default backend)`
|
|
267
|
+
});
|
|
268
|
+
}
|
|
244
269
|
}
|
|
245
270
|
|
|
246
271
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-worker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.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",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"scripts": {
|
|
22
22
|
"dev": "tsdown --watch",
|
|
23
23
|
"build": "tsdown",
|
|
24
|
-
"test": "bun test",
|
|
24
|
+
"test": "bun test test/*.test.ts test/unit/",
|
|
25
|
+
"test:e2e": "bun test test/e2e/",
|
|
26
|
+
"e2e:setup": "bash scripts/e2e-setup.sh",
|
|
25
27
|
"lint": "oxlint src",
|
|
26
28
|
"lint:fix": "oxlint src --fix",
|
|
27
29
|
"format": "oxfmt src",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { C as SDK_MODEL_ALIASES, S as CURSOR_MODEL_MAP, T as normalizeBackendType, _ as execWithIdleTimeout, a as createMockBackend, b as CLAUDE_MODEL_MAP, c as CodexBackend, d as codexAdapter, f as createStreamParser, g as IdleTimeoutError, h as formatEvent, i as MockAIBackend, l as ClaudeCodeBackend, m as extractCodexResult, n as createBackend, o as SdkBackend, p as extractClaudeResult, r as listBackends, s as CursorBackend, t as checkBackends, u as claudeAdapter, v as DEFAULT_IDLE_TIMEOUT, w as getModelForBackend, x as CODEX_MODEL_MAP, y as BACKEND_DEFAULT_MODELS } from "./backends-DLaP0rMW.mjs";
|
|
2
|
-
|
|
3
|
-
export { listBackends };
|