@gullabs/claude-cli 0.6.1 → 0.16.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/NOTICE +6 -0
- package/README.md +97 -13
- package/dist/index.cjs +311 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -18
- package/dist/index.d.ts +48 -18
- package/dist/index.js +309 -47
- package/dist/index.js.map +1 -1
- package/package.json +18 -8
package/dist/index.cjs
CHANGED
|
@@ -5,9 +5,107 @@ var os = require('os');
|
|
|
5
5
|
var path = require('path');
|
|
6
6
|
var core = require('@gullabs/core');
|
|
7
7
|
var child_process = require('child_process');
|
|
8
|
+
var string_decoder = require('string_decoder');
|
|
8
9
|
var zod = require('zod');
|
|
9
10
|
|
|
10
11
|
// src/adapter.ts
|
|
12
|
+
var INHERITED_NAMES = /* @__PURE__ */ new Set([
|
|
13
|
+
// Process basics.
|
|
14
|
+
"PATH",
|
|
15
|
+
"HOME",
|
|
16
|
+
"USER",
|
|
17
|
+
"LOGNAME",
|
|
18
|
+
"LANG",
|
|
19
|
+
"LANGUAGE",
|
|
20
|
+
"TERM",
|
|
21
|
+
"TMPDIR",
|
|
22
|
+
"TEMP",
|
|
23
|
+
"TMP",
|
|
24
|
+
"SHELL",
|
|
25
|
+
"TZ",
|
|
26
|
+
// Windows equivalents of the above.
|
|
27
|
+
"SYSTEMROOT",
|
|
28
|
+
"SYSTEMDRIVE",
|
|
29
|
+
"WINDIR",
|
|
30
|
+
"COMSPEC",
|
|
31
|
+
"PATHEXT",
|
|
32
|
+
"USERPROFILE",
|
|
33
|
+
"APPDATA",
|
|
34
|
+
"LOCALAPPDATA",
|
|
35
|
+
"PROGRAMDATA",
|
|
36
|
+
"HOMEDRIVE",
|
|
37
|
+
"HOMEPATH",
|
|
38
|
+
// Network: proxies and trust roots.
|
|
39
|
+
"HTTPS_PROXY",
|
|
40
|
+
"HTTP_PROXY",
|
|
41
|
+
"ALL_PROXY",
|
|
42
|
+
"NO_PROXY",
|
|
43
|
+
"https_proxy",
|
|
44
|
+
"http_proxy",
|
|
45
|
+
"all_proxy",
|
|
46
|
+
"no_proxy",
|
|
47
|
+
"NODE_EXTRA_CA_CERTS",
|
|
48
|
+
"SSL_CERT_FILE",
|
|
49
|
+
"SSL_CERT_DIR",
|
|
50
|
+
// The CLI's own documented settings that keep the subscription login usable:
|
|
51
|
+
// where its login lives, the long-lived subscription token from
|
|
52
|
+
// `claude setup-token`, and client certificates for an mTLS proxy.
|
|
53
|
+
"CLAUDE_CONFIG_DIR",
|
|
54
|
+
"CLAUDE_CODE_OAUTH_TOKEN",
|
|
55
|
+
"CLAUDE_CODE_CLIENT_CERT",
|
|
56
|
+
"CLAUDE_CODE_CLIENT_KEY",
|
|
57
|
+
"CLAUDE_CODE_CLIENT_KEY_PASSPHRASE",
|
|
58
|
+
"CLAUDE_CODE_PROXY_RESOLVES_HOSTS"
|
|
59
|
+
]);
|
|
60
|
+
var INHERITED_PREFIXES = ["LC_", "XDG_"];
|
|
61
|
+
function isInherited(name, windows) {
|
|
62
|
+
const key = windows ? name.toUpperCase() : name;
|
|
63
|
+
if (INHERITED_NAMES.has(key)) return true;
|
|
64
|
+
return INHERITED_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
65
|
+
}
|
|
66
|
+
function buildChildEnv(parent, extra, windows) {
|
|
67
|
+
const env = {};
|
|
68
|
+
for (const [name, value] of Object.entries(parent)) {
|
|
69
|
+
if (value !== void 0 && isInherited(name, windows)) env[name] = value;
|
|
70
|
+
}
|
|
71
|
+
if (extra !== void 0) {
|
|
72
|
+
if (windows) {
|
|
73
|
+
const overridden = new Set(Object.keys(extra).map((name) => name.toUpperCase()));
|
|
74
|
+
for (const name of Object.keys(env)) {
|
|
75
|
+
if (overridden.has(name.toUpperCase())) delete env[name];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
Object.assign(env, extra);
|
|
79
|
+
}
|
|
80
|
+
return env;
|
|
81
|
+
}
|
|
82
|
+
function badEnv(message) {
|
|
83
|
+
return new core.LlmError(message, {
|
|
84
|
+
kind: "bad_request",
|
|
85
|
+
retryable: false,
|
|
86
|
+
provider: "claude-cli"
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function parseExtraEnv(env) {
|
|
90
|
+
if (env === void 0) return void 0;
|
|
91
|
+
if (env === null || typeof env !== "object" || Array.isArray(env)) {
|
|
92
|
+
throw badEnv("claudeCliAdapter: `env` must be an object of string values");
|
|
93
|
+
}
|
|
94
|
+
const copy = {};
|
|
95
|
+
for (const [name, value] of Object.entries(env)) {
|
|
96
|
+
if (name === "" || name.includes("=") || name.includes("\0")) {
|
|
97
|
+
throw badEnv(`claudeCliAdapter: \`env\` has an invalid name "${name}"`);
|
|
98
|
+
}
|
|
99
|
+
if (typeof value !== "string" || value.includes("\0")) {
|
|
100
|
+
throw badEnv(
|
|
101
|
+
`claudeCliAdapter: \`env.${name}\` must be a string without NUL characters`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
copy[name] = value;
|
|
105
|
+
}
|
|
106
|
+
return Object.freeze(copy);
|
|
107
|
+
}
|
|
108
|
+
var MAX_STDOUT_BYTES = 32 * 1024 * 1024;
|
|
11
109
|
function buildClaudeCliRunner(claudePath = "claude") {
|
|
12
110
|
return {
|
|
13
111
|
run(args, input, opts) {
|
|
@@ -20,9 +118,14 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
20
118
|
}
|
|
21
119
|
const child = child_process.spawn(claudePath, args, {
|
|
22
120
|
cwd: opts.cwd,
|
|
23
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
121
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
122
|
+
detached: process.platform !== "win32",
|
|
123
|
+
env: buildChildEnv(process.env, opts.env, process.platform === "win32")
|
|
24
124
|
});
|
|
125
|
+
const stdoutDecoder = new string_decoder.StringDecoder("utf8");
|
|
126
|
+
const stderrDecoder = new string_decoder.StringDecoder("utf8");
|
|
25
127
|
let stdout = "";
|
|
128
|
+
let stdoutBytes = 0;
|
|
26
129
|
let stderr = "";
|
|
27
130
|
let settled = false;
|
|
28
131
|
let pendingError;
|
|
@@ -38,12 +141,31 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
38
141
|
opts.signal.removeEventListener("abort", onAbort);
|
|
39
142
|
}
|
|
40
143
|
};
|
|
144
|
+
const signalTree = (signal) => {
|
|
145
|
+
if (process.platform !== "win32" && child.pid !== void 0) {
|
|
146
|
+
try {
|
|
147
|
+
process.kill(-child.pid, signal);
|
|
148
|
+
return;
|
|
149
|
+
} catch {
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
child.kill(signal);
|
|
153
|
+
};
|
|
41
154
|
const killChild = () => {
|
|
42
|
-
|
|
155
|
+
signalTree("SIGTERM");
|
|
43
156
|
killTimeoutHandle = setTimeout(() => {
|
|
44
|
-
|
|
157
|
+
signalTree("SIGKILL");
|
|
158
|
+
child.stdout.destroy();
|
|
159
|
+
child.stderr.destroy();
|
|
45
160
|
}, 5e3);
|
|
46
161
|
};
|
|
162
|
+
const sweepGroup = () => {
|
|
163
|
+
if (process.platform === "win32" || child.pid === void 0) return;
|
|
164
|
+
try {
|
|
165
|
+
process.kill(-child.pid, "SIGKILL");
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
};
|
|
47
169
|
const beginReject = (err) => {
|
|
48
170
|
if (settled || pendingError !== void 0) return;
|
|
49
171
|
pendingError = err;
|
|
@@ -66,10 +188,22 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
66
188
|
}, opts.timeoutMs);
|
|
67
189
|
}
|
|
68
190
|
child.stdout.on("data", (chunk) => {
|
|
69
|
-
|
|
191
|
+
if (pendingError !== void 0) return;
|
|
192
|
+
stdoutBytes += chunk.length;
|
|
193
|
+
if (stdoutBytes > MAX_STDOUT_BYTES) {
|
|
194
|
+
const err = new Error(
|
|
195
|
+
`claude-cli stdout exceeded ${MAX_STDOUT_BYTES} bytes; the process was killed`
|
|
196
|
+
);
|
|
197
|
+
err.name = "OutputLimitError";
|
|
198
|
+
beginReject(err);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
stdout += stdoutDecoder.write(chunk);
|
|
70
202
|
});
|
|
71
203
|
child.stderr.on("data", (chunk) => {
|
|
72
|
-
stderr
|
|
204
|
+
stderr = (stderr + stderrDecoder.write(chunk)).slice(-1048576);
|
|
205
|
+
});
|
|
206
|
+
child.stdin.on("error", () => {
|
|
73
207
|
});
|
|
74
208
|
child.once("error", (err) => {
|
|
75
209
|
if (settled) return;
|
|
@@ -82,8 +216,11 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
82
216
|
settled = true;
|
|
83
217
|
cleanup();
|
|
84
218
|
if (pendingError !== void 0) {
|
|
219
|
+
sweepGroup();
|
|
85
220
|
reject(pendingError);
|
|
86
221
|
} else {
|
|
222
|
+
stdout += stdoutDecoder.end();
|
|
223
|
+
stderr = (stderr + stderrDecoder.end()).slice(-1048576);
|
|
87
224
|
resolve({ stdout, stderr, exitCode });
|
|
88
225
|
}
|
|
89
226
|
});
|
|
@@ -94,31 +231,52 @@ function buildClaudeCliRunner(claudePath = "claude") {
|
|
|
94
231
|
}
|
|
95
232
|
|
|
96
233
|
// src/adapter.ts
|
|
234
|
+
function abortError() {
|
|
235
|
+
const err = new Error("claude-cli call aborted");
|
|
236
|
+
err.name = "AbortError";
|
|
237
|
+
return err;
|
|
238
|
+
}
|
|
97
239
|
var Semaphore = class {
|
|
98
240
|
available;
|
|
99
|
-
|
|
241
|
+
waiters = [];
|
|
100
242
|
constructor(max) {
|
|
101
243
|
this.available = max;
|
|
102
244
|
}
|
|
103
|
-
|
|
245
|
+
/**
|
|
246
|
+
* Take a slot. A caller that has to wait leaves the queue, and rejects with an
|
|
247
|
+
* `AbortError`, as soon as `signal` fires: a call the engine already gave up
|
|
248
|
+
* on must not hold a place in line.
|
|
249
|
+
*/
|
|
250
|
+
acquire(signal) {
|
|
251
|
+
if (signal?.aborted === true) return Promise.reject(abortError());
|
|
104
252
|
if (this.available > 0) {
|
|
105
253
|
this.available -= 1;
|
|
106
|
-
return () => {
|
|
254
|
+
return Promise.resolve(() => {
|
|
107
255
|
this.release();
|
|
108
|
-
};
|
|
256
|
+
});
|
|
109
257
|
}
|
|
110
|
-
|
|
111
|
-
|
|
258
|
+
return new Promise((resolve, reject) => {
|
|
259
|
+
const grant = () => {
|
|
260
|
+
signal?.removeEventListener("abort", onAbort);
|
|
261
|
+
resolve(() => {
|
|
262
|
+
this.release();
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
const onAbort = () => {
|
|
266
|
+
const at = this.waiters.indexOf(grant);
|
|
267
|
+
if (at >= 0) this.waiters.splice(at, 1);
|
|
268
|
+
reject(abortError());
|
|
269
|
+
};
|
|
270
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
271
|
+
this.waiters.push(grant);
|
|
112
272
|
});
|
|
113
|
-
this.available -= 1;
|
|
114
|
-
return () => {
|
|
115
|
-
this.release();
|
|
116
|
-
};
|
|
117
273
|
}
|
|
274
|
+
// A freed slot goes straight to the next waiter, so a new caller cannot
|
|
275
|
+
// overtake it between the release and the waiter's wake-up.
|
|
118
276
|
release() {
|
|
119
|
-
this.
|
|
120
|
-
const next = this.queue.shift();
|
|
277
|
+
const next = this.waiters.shift();
|
|
121
278
|
if (next !== void 0) next();
|
|
279
|
+
else this.available += 1;
|
|
122
280
|
}
|
|
123
281
|
};
|
|
124
282
|
function mapFinishReason(stopReason) {
|
|
@@ -126,6 +284,8 @@ function mapFinishReason(stopReason) {
|
|
|
126
284
|
switch (stopReason) {
|
|
127
285
|
case "end_turn":
|
|
128
286
|
return "stop";
|
|
287
|
+
case "refusal":
|
|
288
|
+
return "content_filter";
|
|
129
289
|
case "tool_use":
|
|
130
290
|
return "stop";
|
|
131
291
|
default:
|
|
@@ -133,14 +293,19 @@ function mapFinishReason(stopReason) {
|
|
|
133
293
|
}
|
|
134
294
|
}
|
|
135
295
|
function mapUsage(usage) {
|
|
136
|
-
const
|
|
296
|
+
const cacheRead = usage?.cache_read_input_tokens;
|
|
297
|
+
const cacheWrite = usage?.cache_creation_input_tokens;
|
|
298
|
+
const inputTokens = (usage?.input_tokens ?? 0) + (cacheRead ?? 0) + (cacheWrite ?? 0);
|
|
137
299
|
const outputTokens = usage?.output_tokens ?? 0;
|
|
138
|
-
const cachedInputTokens =
|
|
300
|
+
const cachedInputTokens = cacheRead;
|
|
301
|
+
const thinkingTokens = usage?.output_tokens_details?.thinking_tokens;
|
|
139
302
|
const totalTokens = usage !== void 0 ? inputTokens + outputTokens : void 0;
|
|
140
303
|
const details = {
|
|
141
304
|
input: inputTokens,
|
|
142
305
|
output: outputTokens,
|
|
143
306
|
...cachedInputTokens !== void 0 ? { cached: cachedInputTokens } : {},
|
|
307
|
+
...cacheWrite !== void 0 ? { cacheWrite } : {},
|
|
308
|
+
...thinkingTokens !== void 0 ? { thinking: thinkingTokens } : {},
|
|
144
309
|
...totalTokens !== void 0 ? { total: totalTokens } : {}
|
|
145
310
|
};
|
|
146
311
|
const raw = usage !== void 0 ? usage : null;
|
|
@@ -150,6 +315,7 @@ function mapUsage(usage) {
|
|
|
150
315
|
details,
|
|
151
316
|
raw,
|
|
152
317
|
...cachedInputTokens !== void 0 ? { cachedInputTokens } : {},
|
|
318
|
+
...thinkingTokens !== void 0 ? { thinkingTokens } : {},
|
|
153
319
|
...totalTokens !== void 0 ? { totalTokens } : {}
|
|
154
320
|
};
|
|
155
321
|
}
|
|
@@ -179,20 +345,47 @@ function buildPrompt(messages) {
|
|
|
179
345
|
${messageText(msg)}`;
|
|
180
346
|
}).join("\n\n");
|
|
181
347
|
}
|
|
348
|
+
var AUTH_FAILURE = /\b(?:log ?in|auth|oauth|authentication|unauthori[sz]ed|401)\b/i;
|
|
349
|
+
var RATE_LIMITED = /\brate[ -]?limit(?:ed|s|ing)?\b|\btoo many requests\b|(?<![\w.:/-])429(?![\w-]|\.\d)/i;
|
|
182
350
|
function looksAuthy(text) {
|
|
183
|
-
return
|
|
351
|
+
return AUTH_FAILURE.test(text);
|
|
184
352
|
}
|
|
185
353
|
function looksRateLimited(text) {
|
|
186
|
-
return
|
|
354
|
+
return RATE_LIMITED.test(text);
|
|
187
355
|
}
|
|
188
|
-
function
|
|
189
|
-
const
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
356
|
+
function assertServedModel(envelope, requestedModel) {
|
|
357
|
+
const modelUsage = envelope.modelUsage;
|
|
358
|
+
if (modelUsage === null || typeof modelUsage !== "object" || Array.isArray(modelUsage)) {
|
|
359
|
+
throw new core.LlmError("claude CLI did not report a valid modelUsage object.", {
|
|
360
|
+
kind: "server",
|
|
361
|
+
retryable: false,
|
|
362
|
+
provider: "claude-cli"
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
for (const served of Object.keys(modelUsage)) {
|
|
366
|
+
if (served !== requestedModel) {
|
|
367
|
+
throw new core.LlmError(
|
|
368
|
+
`claude CLI served model "${served}" but the request asked for "${requestedModel}".`,
|
|
369
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (!Object.hasOwn(modelUsage, requestedModel)) {
|
|
374
|
+
throw new core.LlmError(
|
|
375
|
+
`claude CLI did not report the requested model "${requestedModel}" in modelUsage.`,
|
|
376
|
+
{ kind: "server", retryable: false, provider: "claude-cli" }
|
|
194
377
|
);
|
|
195
378
|
}
|
|
379
|
+
}
|
|
380
|
+
function classifyRunFailure(envelope, result) {
|
|
381
|
+
if (envelope?.stop_reason === "refusal") {
|
|
382
|
+
return new core.LlmError("claude CLI refused the prompt (stop_reason: refusal).", {
|
|
383
|
+
kind: "content_filter",
|
|
384
|
+
retryable: false,
|
|
385
|
+
provider: "claude-cli"
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
const combinedText = `${envelope?.subtype ?? ""} ${result.stderr}`;
|
|
196
389
|
if (looksRateLimited(combinedText)) {
|
|
197
390
|
return new core.LlmError(
|
|
198
391
|
`claude CLI reported rate limiting: ${result.stderr.slice(-500)}`,
|
|
@@ -203,6 +396,12 @@ function classifyRunFailure(envelope, result) {
|
|
|
203
396
|
}
|
|
204
397
|
);
|
|
205
398
|
}
|
|
399
|
+
if (looksAuthy(combinedText)) {
|
|
400
|
+
return new core.LlmError(
|
|
401
|
+
`claude CLI reported an authentication failure: ${result.stderr.slice(-500)}`,
|
|
402
|
+
{ kind: "invalid_auth", retryable: false, provider: "claude-cli" }
|
|
403
|
+
);
|
|
404
|
+
}
|
|
206
405
|
if (envelope?.is_error === true) {
|
|
207
406
|
return new core.LlmError(
|
|
208
407
|
`claude CLI reported an error (subtype: ${envelope.subtype ?? "unknown"}): ${result.stderr.slice(-500)}`,
|
|
@@ -218,6 +417,7 @@ function classifyRunFailure(envelope, result) {
|
|
|
218
417
|
function claudeCliAdapter(opts) {
|
|
219
418
|
const runner = opts?.runner ?? buildClaudeCliRunner(opts?.claudePath);
|
|
220
419
|
const semaphore = new Semaphore(opts?.maxConcurrency ?? 2);
|
|
420
|
+
const env = parseExtraEnv(opts?.env);
|
|
221
421
|
return {
|
|
222
422
|
id: "claude-cli",
|
|
223
423
|
async run(req, ctx) {
|
|
@@ -243,6 +443,27 @@ function claudeCliAdapter(opts) {
|
|
|
243
443
|
const warnings = [];
|
|
244
444
|
const model = req.model;
|
|
245
445
|
const config = req.config;
|
|
446
|
+
if (req.modelDescriptor?.model !== model || req.modelDescriptor.provider !== "claude-cli") {
|
|
447
|
+
throw new core.LlmError(`No matching Claude model descriptor for "${model}".`, {
|
|
448
|
+
kind: "bad_request",
|
|
449
|
+
retryable: false,
|
|
450
|
+
provider: "claude-cli"
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
if (req.transientProviderState !== void 0) {
|
|
454
|
+
throw new core.LlmError(`Model "${model}" does not admit transientProviderState.`, {
|
|
455
|
+
kind: "bad_request",
|
|
456
|
+
retryable: false,
|
|
457
|
+
provider: "claude-cli"
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
if (config.reasoning !== void 0 && req.modelDescriptor.capabilities?.reasoningApi === void 0) {
|
|
461
|
+
throw new core.LlmError(`Model "${model}" does not admit reasoning.`, {
|
|
462
|
+
kind: "bad_request",
|
|
463
|
+
retryable: false,
|
|
464
|
+
provider: "claude-cli"
|
|
465
|
+
});
|
|
466
|
+
}
|
|
246
467
|
const prompt = buildPrompt(req.messages);
|
|
247
468
|
const args = [
|
|
248
469
|
"-p",
|
|
@@ -252,7 +473,9 @@ function claudeCliAdapter(opts) {
|
|
|
252
473
|
"--tools",
|
|
253
474
|
"",
|
|
254
475
|
"--disable-slash-commands",
|
|
255
|
-
"--no-session-persistence"
|
|
476
|
+
"--no-session-persistence",
|
|
477
|
+
"--settings",
|
|
478
|
+
'{"switchModelsOnFlag":false}'
|
|
256
479
|
];
|
|
257
480
|
args.push("--model", model);
|
|
258
481
|
const effort = config.reasoning?.effort;
|
|
@@ -266,14 +489,29 @@ function claudeCliAdapter(opts) {
|
|
|
266
489
|
args.push("--json-schema", JSON.stringify(req.outputJsonSchema));
|
|
267
490
|
}
|
|
268
491
|
const timeoutMs = req.attemptTimeoutMs ?? config.timeoutMs;
|
|
269
|
-
|
|
270
|
-
|
|
492
|
+
let release;
|
|
493
|
+
try {
|
|
494
|
+
release = await semaphore.acquire(ctx.signal);
|
|
495
|
+
} catch (waitErr) {
|
|
496
|
+
throw new core.LlmError(
|
|
497
|
+
waitErr instanceof Error ? waitErr.message : "claude-cli call aborted",
|
|
498
|
+
{ kind: "aborted", retryable: false, provider: "claude-cli" }
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
let cwd;
|
|
502
|
+
try {
|
|
503
|
+
cwd = await promises.mkdtemp(path.join(os.tmpdir(), "claude-cli-"));
|
|
504
|
+
} catch (mkdirErr) {
|
|
505
|
+
release();
|
|
506
|
+
throw mkdirErr;
|
|
507
|
+
}
|
|
271
508
|
let result;
|
|
272
509
|
try {
|
|
273
510
|
result = await runner.run(args, prompt, {
|
|
274
511
|
cwd,
|
|
275
512
|
...timeoutMs !== void 0 ? { timeoutMs } : {},
|
|
276
|
-
...ctx.signal !== void 0 ? { signal: ctx.signal } : {}
|
|
513
|
+
...ctx.signal !== void 0 ? { signal: ctx.signal } : {},
|
|
514
|
+
...env !== void 0 ? { env } : {}
|
|
277
515
|
});
|
|
278
516
|
} catch (rawErr) {
|
|
279
517
|
release();
|
|
@@ -315,6 +553,7 @@ function claudeCliAdapter(opts) {
|
|
|
315
553
|
if (result.exitCode !== 0 || envelope?.is_error === true || envelope === void 0) {
|
|
316
554
|
throw classifyRunFailure(envelope, result);
|
|
317
555
|
}
|
|
556
|
+
assertServedModel(envelope, model);
|
|
318
557
|
const text = envelope.result ?? "";
|
|
319
558
|
let rawStructured;
|
|
320
559
|
if (req.outputJsonSchema !== void 0) {
|
|
@@ -337,6 +576,10 @@ function claudeCliAdapter(opts) {
|
|
|
337
576
|
};
|
|
338
577
|
const adapterResult = {
|
|
339
578
|
model,
|
|
579
|
+
message: {
|
|
580
|
+
role: "assistant",
|
|
581
|
+
parts: text.length > 0 ? [{ kind: "text", text }] : []
|
|
582
|
+
},
|
|
340
583
|
usage,
|
|
341
584
|
warnings,
|
|
342
585
|
...text.length > 0 ? { text } : {},
|
|
@@ -349,13 +592,13 @@ function claudeCliAdapter(opts) {
|
|
|
349
592
|
};
|
|
350
593
|
}
|
|
351
594
|
var CLAUDE_CLI_MODEL_IDS = [
|
|
352
|
-
"claude-fable-5",
|
|
353
|
-
"claude-opus-
|
|
595
|
+
"claude-fable-5-1",
|
|
596
|
+
"claude-opus-5-5",
|
|
354
597
|
"claude-sonnet-5",
|
|
355
598
|
"claude-haiku-4-5-20251001"
|
|
356
599
|
];
|
|
357
600
|
var CLAUDE_CLI_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
358
|
-
function
|
|
601
|
+
function buildEffortConfigSchema(modelName) {
|
|
359
602
|
return zod.z.strictObject({
|
|
360
603
|
reasoning: zod.z.strictObject({
|
|
361
604
|
effort: zod.z.enum(CLAUDE_CLI_EFFORTS).meta({
|
|
@@ -375,32 +618,51 @@ function buildClaudeCliConfigSchema(modelName) {
|
|
|
375
618
|
description: `Strict claude-cli config for model ${modelName}. Text-only, no sampling knobs, effort-based reasoning.`
|
|
376
619
|
});
|
|
377
620
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
)
|
|
621
|
+
function buildHaikuConfigSchema() {
|
|
622
|
+
return zod.z.strictObject({
|
|
623
|
+
timeoutMs: zod.z.number().int().positive().max(18e5).optional().meta({
|
|
624
|
+
title: "Timeout",
|
|
625
|
+
description: "Logical request timeout in milliseconds; forwarded to the CLI runner."
|
|
626
|
+
})
|
|
627
|
+
}).meta({
|
|
628
|
+
title: "claude-haiku-4-5-20251001Config",
|
|
629
|
+
description: "Strict claude-cli config for claude-haiku-4-5-20251001. No reasoning key: the CLI drops --effort."
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
var ClaudeFable51ConfigSchema = buildEffortConfigSchema("claude-fable-5-1");
|
|
633
|
+
var ClaudeOpus55ConfigSchema = buildEffortConfigSchema("claude-opus-5-5");
|
|
634
|
+
var ClaudeSonnet5ConfigSchema = buildEffortConfigSchema("claude-sonnet-5");
|
|
635
|
+
var ClaudeHaiku45ConfigSchema = buildHaikuConfigSchema();
|
|
384
636
|
var CONFIG_SCHEMAS = {
|
|
385
|
-
"claude-fable-5":
|
|
386
|
-
"claude-opus-
|
|
637
|
+
"claude-fable-5-1": ClaudeFable51ConfigSchema,
|
|
638
|
+
"claude-opus-5-5": ClaudeOpus55ConfigSchema,
|
|
387
639
|
"claude-sonnet-5": ClaudeSonnet5ConfigSchema,
|
|
388
640
|
"claude-haiku-4-5-20251001": ClaudeHaiku45ConfigSchema
|
|
389
641
|
};
|
|
642
|
+
var CLAUDE_CLI_LIMITS = {
|
|
643
|
+
"claude-fable-5-1": { contextWindow: 1e6, maxOutputTokens: 64e3 },
|
|
644
|
+
"claude-opus-5-5": { contextWindow: 1e6, maxOutputTokens: 128e3 },
|
|
645
|
+
"claude-sonnet-5": { contextWindow: 1e6, maxOutputTokens: 128e3 },
|
|
646
|
+
"claude-haiku-4-5-20251001": { contextWindow: 2e5, maxOutputTokens: 32e3 }
|
|
647
|
+
};
|
|
390
648
|
var claudeCliModelDescriptors = CLAUDE_CLI_MODEL_IDS.map(
|
|
391
649
|
(id) => {
|
|
392
650
|
const configSchema = CONFIG_SCHEMAS[id];
|
|
393
651
|
return {
|
|
394
652
|
model: id,
|
|
395
653
|
provider: "claude-cli",
|
|
654
|
+
limits: CLAUDE_CLI_LIMITS[id],
|
|
396
655
|
capabilities: {
|
|
656
|
+
// The CLI runs text-only: the adapter rejects every non-text part.
|
|
657
|
+
inputMimeTypes: [],
|
|
397
658
|
structuredOutput: true,
|
|
398
659
|
nativeStructuredOutput: true,
|
|
399
|
-
reasoningApi: "level",
|
|
400
|
-
|
|
401
|
-
|
|
660
|
+
...id !== "claude-haiku-4-5-20251001" ? { reasoningApi: "level" } : {},
|
|
661
|
+
admittedReasoningEfforts: id === "claude-haiku-4-5-20251001" ? [] : CLAUDE_CLI_EFFORTS,
|
|
662
|
+
sampling: "fixed"
|
|
402
663
|
},
|
|
403
664
|
configSchema,
|
|
665
|
+
configKeys: core.toConfigKeys(configSchema),
|
|
404
666
|
configJsonSchema: core.toConfigJsonSchema(configSchema),
|
|
405
667
|
validateConfig: core.zodToStandardSchema(configSchema)
|
|
406
668
|
};
|
|
@@ -418,9 +680,11 @@ function claudeCliProvider(opts) {
|
|
|
418
680
|
};
|
|
419
681
|
}
|
|
420
682
|
|
|
421
|
-
exports.
|
|
683
|
+
exports.CLAUDE_CLI_EFFORTS = CLAUDE_CLI_EFFORTS;
|
|
684
|
+
exports.CLAUDE_CLI_MODEL_IDS = CLAUDE_CLI_MODEL_IDS;
|
|
685
|
+
exports.ClaudeFable51ConfigSchema = ClaudeFable51ConfigSchema;
|
|
422
686
|
exports.ClaudeHaiku45ConfigSchema = ClaudeHaiku45ConfigSchema;
|
|
423
|
-
exports.
|
|
687
|
+
exports.ClaudeOpus55ConfigSchema = ClaudeOpus55ConfigSchema;
|
|
424
688
|
exports.ClaudeSonnet5ConfigSchema = ClaudeSonnet5ConfigSchema;
|
|
425
689
|
exports.buildClaudeCliRunner = buildClaudeCliRunner;
|
|
426
690
|
exports.claudeCliAdapter = claudeCliAdapter;
|