jinzd-ai-cli 0.4.143 → 0.4.144
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/{batch-FTCB7YHA.js → batch-64YESATH.js} +2 -2
- package/dist/{chunk-IMYOBDJG.js → chunk-2JPLV25X.js} +1 -1
- package/dist/{chunk-YCIJZ2XS.js → chunk-EHLHWFZP.js} +1 -1
- package/dist/{chunk-CSWA553M.js → chunk-HUILGJNB.js} +1 -1
- package/dist/{chunk-GDCLDXEC.js → chunk-IGZVCNGE.js} +2 -2
- package/dist/{chunk-YPFCJ5KC.js → chunk-PWCPOHZ4.js} +3 -3
- package/dist/{chunk-2JLVHUMU.js → chunk-QSGDXXE6.js} +1 -1
- package/dist/{chunk-DX5JYNVN.js → chunk-WPYKTLP2.js} +22 -2
- package/dist/{chunk-VXFBUMWG.js → chunk-XW4EP5IE.js} +1 -1
- package/dist/{chunk-2YEBAHAB.js → chunk-YGGW2D2V.js} +1 -1
- package/dist/{constants-YVTEGGKB.js → constants-7Q5DB2X6.js} +1 -1
- package/dist/{doctor-cli-EGD6OLJO.js → doctor-cli-RHGMQVCU.js} +5 -5
- package/dist/electron-server.js +23 -3
- package/dist/{hub-YNT2PVCA.js → hub-SXNKYCN7.js} +1 -1
- package/dist/index.js +219 -20
- package/dist/{run-tests-VK2S7V3X.js → run-tests-SUYREW3B.js} +1 -1
- package/dist/{run-tests-3KUDRXXZ.js → run-tests-X4YQXIGP.js} +2 -2
- package/dist/{server-7UH5SJSC.js → server-MGKTVVAR.js} +4 -4
- package/dist/{server-KZOHU7OE.js → server-X24SIKZE.js} +8 -8
- package/dist/{task-orchestrator-E46H7NUK.js → task-orchestrator-R6VOCA4V.js} +4 -4
- package/package.json +1 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ConfigManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WPYKTLP2.js";
|
|
5
5
|
import "./chunk-2ZD3YTVM.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-XW4EP5IE.js";
|
|
7
7
|
import "./chunk-PDX44BCA.js";
|
|
8
8
|
|
|
9
9
|
// src/cli/batch.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
truncateForPersist
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PWCPOHZ4.js";
|
|
5
5
|
import {
|
|
6
6
|
APP_NAME,
|
|
7
7
|
CONFIG_DIR_NAME,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
MCP_PROTOCOL_VERSION,
|
|
12
12
|
MCP_TOOL_PREFIX,
|
|
13
13
|
VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XW4EP5IE.js";
|
|
15
15
|
import {
|
|
16
16
|
redactJson
|
|
17
17
|
} from "./chunk-7ZJN4KLV.js";
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
} from "./chunk-UQQJWHRV.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-2JPLV25X.js";
|
|
9
9
|
import {
|
|
10
10
|
getDangerLevel,
|
|
11
11
|
isFileWriteTool,
|
|
12
12
|
runTool
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QSGDXXE6.js";
|
|
14
14
|
import {
|
|
15
15
|
EnvLoader,
|
|
16
16
|
NetworkError,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
SUBAGENT_ALLOWED_TOOLS,
|
|
24
24
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
25
25
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-XW4EP5IE.js";
|
|
27
27
|
import {
|
|
28
28
|
fileCheckpoints
|
|
29
29
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
CONFIG_FILE_NAME,
|
|
9
9
|
HISTORY_DIR_NAME,
|
|
10
10
|
PLUGINS_DIR_NAME
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XW4EP5IE.js";
|
|
12
12
|
|
|
13
13
|
// src/config/config-manager.ts
|
|
14
14
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -235,7 +235,27 @@ var ConfigSchema = z.object({
|
|
|
235
235
|
name: z.string().optional()
|
|
236
236
|
})).default([]),
|
|
237
237
|
fallback: z.string().optional()
|
|
238
|
-
}).default({ enabled: false, rules: [] })
|
|
238
|
+
}).default({ enabled: false, rules: [] }),
|
|
239
|
+
// Provider 容错(v0.4.144+):网络抖动 / 5xx / 429 时,先在当前 provider 上做指数退避重试,
|
|
240
|
+
// 仍失败则按顺序尝试 chain 里的 fallback provider。auth / 400 / 422 等"硬失败"直接跳过同
|
|
241
|
+
// provider 重试,但仍会尝试 chain(不同 key/schema 可能能成功)。
|
|
242
|
+
// 关键约束:流式 API 一旦已经向终端 yield 过 chunk,错误立刻向上抛 —— 不能"已经吐了一半"再
|
|
243
|
+
// 重新发起请求,会撕裂用户看到的输出。
|
|
244
|
+
// enabled 默认 false:保持向前兼容,未配置 chain 的用户行为不变。
|
|
245
|
+
fallback: z.object({
|
|
246
|
+
enabled: z.boolean().default(false),
|
|
247
|
+
/** 同 provider 重试次数(不含首次调用)。0 = 不重试,直接走 chain。 */
|
|
248
|
+
retries: z.number().int().min(0).max(10).default(2),
|
|
249
|
+
/** 首次退避等待(ms),后续按 2 的幂指数增长。 */
|
|
250
|
+
initialBackoffMs: z.number().int().positive().default(500),
|
|
251
|
+
/** 单次退避的硬上限(ms)。 */
|
|
252
|
+
maxBackoffMs: z.number().int().positive().default(8e3),
|
|
253
|
+
/** 兜底 provider 链,每个 entry 仅尝试 1 次。model 省略则使用 provider 的 defaultModel。 */
|
|
254
|
+
chain: z.array(z.object({
|
|
255
|
+
provider: z.string(),
|
|
256
|
+
model: z.string().optional()
|
|
257
|
+
})).default([])
|
|
258
|
+
}).default({ enabled: false, retries: 2, initialBackoffMs: 500, maxBackoffMs: 8e3, chain: [] })
|
|
239
259
|
});
|
|
240
260
|
|
|
241
261
|
// src/config/config-manager.ts
|
|
@@ -2,25 +2,25 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getConfigDirUsage,
|
|
4
4
|
listRecentCrashes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HUILGJNB.js";
|
|
6
6
|
import {
|
|
7
7
|
ProviderRegistry
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EHLHWFZP.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigManager
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-WPYKTLP2.js";
|
|
12
12
|
import {
|
|
13
13
|
getStatsSnapshot,
|
|
14
14
|
getTopFailingTools,
|
|
15
15
|
getTopUsedTools,
|
|
16
16
|
resetStats
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QSGDXXE6.js";
|
|
18
18
|
import "./chunk-2ZD3YTVM.js";
|
|
19
19
|
import {
|
|
20
20
|
DEV_STATE_FILE_NAME,
|
|
21
21
|
MEMORY_FILE_NAME,
|
|
22
22
|
VERSION
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-XW4EP5IE.js";
|
|
24
24
|
import "./chunk-PDX44BCA.js";
|
|
25
25
|
|
|
26
26
|
// src/diagnostics/doctor-cli.ts
|
package/dist/electron-server.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
VERSION,
|
|
37
37
|
buildUserIdentityPrompt,
|
|
38
38
|
runTestsTool
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-YGGW2D2V.js";
|
|
40
40
|
import {
|
|
41
41
|
hasSemanticIndex,
|
|
42
42
|
semanticSearch
|
|
@@ -286,7 +286,27 @@ var ConfigSchema = z.object({
|
|
|
286
286
|
name: z.string().optional()
|
|
287
287
|
})).default([]),
|
|
288
288
|
fallback: z.string().optional()
|
|
289
|
-
}).default({ enabled: false, rules: [] })
|
|
289
|
+
}).default({ enabled: false, rules: [] }),
|
|
290
|
+
// Provider 容错(v0.4.144+):网络抖动 / 5xx / 429 时,先在当前 provider 上做指数退避重试,
|
|
291
|
+
// 仍失败则按顺序尝试 chain 里的 fallback provider。auth / 400 / 422 等"硬失败"直接跳过同
|
|
292
|
+
// provider 重试,但仍会尝试 chain(不同 key/schema 可能能成功)。
|
|
293
|
+
// 关键约束:流式 API 一旦已经向终端 yield 过 chunk,错误立刻向上抛 —— 不能"已经吐了一半"再
|
|
294
|
+
// 重新发起请求,会撕裂用户看到的输出。
|
|
295
|
+
// enabled 默认 false:保持向前兼容,未配置 chain 的用户行为不变。
|
|
296
|
+
fallback: z.object({
|
|
297
|
+
enabled: z.boolean().default(false),
|
|
298
|
+
/** 同 provider 重试次数(不含首次调用)。0 = 不重试,直接走 chain。 */
|
|
299
|
+
retries: z.number().int().min(0).max(10).default(2),
|
|
300
|
+
/** 首次退避等待(ms),后续按 2 的幂指数增长。 */
|
|
301
|
+
initialBackoffMs: z.number().int().positive().default(500),
|
|
302
|
+
/** 单次退避的硬上限(ms)。 */
|
|
303
|
+
maxBackoffMs: z.number().int().positive().default(8e3),
|
|
304
|
+
/** 兜底 provider 链,每个 entry 仅尝试 1 次。model 省略则使用 provider 的 defaultModel。 */
|
|
305
|
+
chain: z.array(z.object({
|
|
306
|
+
provider: z.string(),
|
|
307
|
+
model: z.string().optional()
|
|
308
|
+
})).default([])
|
|
309
|
+
}).default({ enabled: false, retries: 2, initialBackoffMs: 500, maxBackoffMs: 8e3, chain: [] })
|
|
290
310
|
});
|
|
291
311
|
|
|
292
312
|
// src/config/env-loader.ts
|
|
@@ -12548,7 +12568,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
12548
12568
|
case "test": {
|
|
12549
12569
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
12550
12570
|
try {
|
|
12551
|
-
const { executeTests } = await import("./run-tests-
|
|
12571
|
+
const { executeTests } = await import("./run-tests-SUYREW3B.js");
|
|
12552
12572
|
const argStr = args.join(" ").trim();
|
|
12553
12573
|
let testArgs = {};
|
|
12554
12574
|
if (argStr) {
|
|
@@ -386,7 +386,7 @@ ${content}`);
|
|
|
386
386
|
}
|
|
387
387
|
}
|
|
388
388
|
async function runTaskMode(config, providers, configManager, topic) {
|
|
389
|
-
const { TaskOrchestrator } = await import("./task-orchestrator-
|
|
389
|
+
const { TaskOrchestrator } = await import("./task-orchestrator-R6VOCA4V.js");
|
|
390
390
|
const orchestrator = new TaskOrchestrator(config, providers, configManager);
|
|
391
391
|
let interrupted = false;
|
|
392
392
|
const onSigint = () => {
|
package/dist/index.js
CHANGED
|
@@ -16,12 +16,12 @@ import {
|
|
|
16
16
|
saveDevState,
|
|
17
17
|
sessionHasMeaningfulContent,
|
|
18
18
|
setupProxy
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-IGZVCNGE.js";
|
|
20
20
|
import {
|
|
21
21
|
getConfigDirUsage,
|
|
22
22
|
listRecentCrashes,
|
|
23
23
|
writeCrashLog
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-HUILGJNB.js";
|
|
25
25
|
import {
|
|
26
26
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
27
27
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
@@ -39,10 +39,10 @@ import {
|
|
|
39
39
|
looksLikeDocumentBody,
|
|
40
40
|
stripPseudoToolCalls,
|
|
41
41
|
stripToolCallReminder
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-EHLHWFZP.js";
|
|
43
43
|
import {
|
|
44
44
|
ConfigManager
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-WPYKTLP2.js";
|
|
46
46
|
import {
|
|
47
47
|
ToolExecutor,
|
|
48
48
|
ToolRegistry,
|
|
@@ -61,17 +61,21 @@ import {
|
|
|
61
61
|
spawnAgentContext,
|
|
62
62
|
theme,
|
|
63
63
|
undoStack
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-PWCPOHZ4.js";
|
|
65
65
|
import "./chunk-UQQJWHRV.js";
|
|
66
66
|
import "./chunk-2DXY7UGF.js";
|
|
67
|
-
import "./chunk-
|
|
67
|
+
import "./chunk-2JPLV25X.js";
|
|
68
68
|
import {
|
|
69
69
|
getStatsSnapshot,
|
|
70
70
|
getTopFailingTools,
|
|
71
71
|
getTopUsedTools,
|
|
72
72
|
installFlushOnExit
|
|
73
|
-
} from "./chunk-
|
|
74
|
-
import
|
|
73
|
+
} from "./chunk-QSGDXXE6.js";
|
|
74
|
+
import {
|
|
75
|
+
AuthError,
|
|
76
|
+
ProviderError,
|
|
77
|
+
RateLimitError
|
|
78
|
+
} from "./chunk-2ZD3YTVM.js";
|
|
75
79
|
import {
|
|
76
80
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
77
81
|
AUTHOR,
|
|
@@ -93,7 +97,7 @@ import {
|
|
|
93
97
|
SKILLS_DIR_NAME,
|
|
94
98
|
VERSION,
|
|
95
99
|
buildUserIdentityPrompt
|
|
96
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-XW4EP5IE.js";
|
|
97
101
|
import {
|
|
98
102
|
formatGitContextForPrompt,
|
|
99
103
|
getGitContext,
|
|
@@ -444,6 +448,7 @@ var Renderer = class {
|
|
|
444
448
|
console.log(feat("Tool history ordering (v0.4.100+): preserve original tool-call order across multi-turn rounds \u2014 fixes reasoning drift on long agentic loops"));
|
|
445
449
|
console.log(feat("save_last_response Web mode (v0.4.101\u20130.4.102+): hidden from CLI-only contexts and tee-streams chunks to disk in Web UI as the response arrives"));
|
|
446
450
|
console.log(feat("write_file long-content guidance (v0.4.103+): tool description no longer encourages AI to chunk long files \u2014 single-shot writes prevented from being split into truncated parts"));
|
|
451
|
+
console.log(feat("Provider retry + fallback chain (v0.4.144+): transient network / 5xx / 429 errors retry on the same provider with exponential backoff; persistent failures walk config.fallback.chain (per-entry provider+model). Opt-in via config.fallback.enabled. Stream-safe: never retries after first chunk yielded"));
|
|
447
452
|
console.log();
|
|
448
453
|
}
|
|
449
454
|
printPrompt(provider, _model) {
|
|
@@ -1814,7 +1819,7 @@ No tools match "${filter}".
|
|
|
1814
1819
|
const { join: join6 } = await import("path");
|
|
1815
1820
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1816
1821
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
|
|
1817
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1822
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-7Q5DB2X6.js");
|
|
1818
1823
|
const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
|
|
1819
1824
|
const cwd = process.cwd();
|
|
1820
1825
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2875,7 +2880,7 @@ ${hint}` : "")
|
|
|
2875
2880
|
usage: "/test [command|filter]",
|
|
2876
2881
|
async execute(args, ctx) {
|
|
2877
2882
|
try {
|
|
2878
|
-
const { executeTests } = await import("./run-tests-
|
|
2883
|
+
const { executeTests } = await import("./run-tests-X4YQXIGP.js");
|
|
2879
2884
|
const argStr = args.join(" ").trim();
|
|
2880
2885
|
let testArgs = {};
|
|
2881
2886
|
if (argStr) {
|
|
@@ -4464,6 +4469,154 @@ function stripRoutingTags(message) {
|
|
|
4464
4469
|
return message.replace(/(?:^|\s)#(fast|deep|default)\b/gi, " ").replace(/\s{2,}/g, " ").trim();
|
|
4465
4470
|
}
|
|
4466
4471
|
|
|
4472
|
+
// src/providers/fallback.ts
|
|
4473
|
+
var TRANSIENT_CODES = /* @__PURE__ */ new Set([
|
|
4474
|
+
"ECONNRESET",
|
|
4475
|
+
"ETIMEDOUT",
|
|
4476
|
+
"EAI_AGAIN",
|
|
4477
|
+
"EHOSTUNREACH",
|
|
4478
|
+
"ENOTFOUND",
|
|
4479
|
+
"EPIPE",
|
|
4480
|
+
"ECONNREFUSED",
|
|
4481
|
+
"EHOSTDOWN",
|
|
4482
|
+
"ENETUNREACH",
|
|
4483
|
+
"UND_ERR_SOCKET",
|
|
4484
|
+
// undici socket errors
|
|
4485
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
4486
|
+
]);
|
|
4487
|
+
function classifyError(err) {
|
|
4488
|
+
if (err == null) return "unknown";
|
|
4489
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4490
|
+
let cur = err;
|
|
4491
|
+
for (let i = 0; i < 5 && cur && !seen.has(cur); i++) {
|
|
4492
|
+
seen.add(cur);
|
|
4493
|
+
const e = cur;
|
|
4494
|
+
if (e.name === "AbortError" || e.code === "ABORT_ERR") return "aborted";
|
|
4495
|
+
if (err instanceof AuthError) return "auth";
|
|
4496
|
+
if (err instanceof RateLimitError) return "rate_limit";
|
|
4497
|
+
const status = e.status ?? e.statusCode;
|
|
4498
|
+
if (typeof status === "number") {
|
|
4499
|
+
if (status === 429) return "rate_limit";
|
|
4500
|
+
if (status === 401 || status === 403) return "auth";
|
|
4501
|
+
if (status === 400 || status === 422) return "bad_request";
|
|
4502
|
+
if (status >= 500 && status < 600) return "transient";
|
|
4503
|
+
}
|
|
4504
|
+
if (e.code && TRANSIENT_CODES.has(e.code)) return "transient";
|
|
4505
|
+
cur = e.cause;
|
|
4506
|
+
}
|
|
4507
|
+
return "unknown";
|
|
4508
|
+
}
|
|
4509
|
+
function planAttempts(initialProvider, initialModel, registry, opts) {
|
|
4510
|
+
const out = [];
|
|
4511
|
+
for (let i = 0; i <= opts.retries; i++) {
|
|
4512
|
+
out.push({ providerId: initialProvider, model: initialModel, retryNumber: i });
|
|
4513
|
+
}
|
|
4514
|
+
for (const entry of opts.chain) {
|
|
4515
|
+
if (entry.provider === initialProvider) continue;
|
|
4516
|
+
if (!registry.has(entry.provider)) continue;
|
|
4517
|
+
const p = registry.get(entry.provider);
|
|
4518
|
+
const model = entry.model ?? p.info.defaultModel;
|
|
4519
|
+
out.push({ providerId: entry.provider, model, retryNumber: 0 });
|
|
4520
|
+
}
|
|
4521
|
+
return out;
|
|
4522
|
+
}
|
|
4523
|
+
function backoffDelay(retryNumber, opts, klass) {
|
|
4524
|
+
const base = klass === "rate_limit" ? Math.max(opts.initialBackoffMs, 2e3) : opts.initialBackoffMs;
|
|
4525
|
+
const expo = base * Math.pow(2, retryNumber);
|
|
4526
|
+
const jitter = Math.random() * (base / 2);
|
|
4527
|
+
return Math.min(opts.maxBackoffMs, expo + jitter);
|
|
4528
|
+
}
|
|
4529
|
+
function sleep(ms) {
|
|
4530
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
4531
|
+
}
|
|
4532
|
+
async function withFallback(initialProvider, initialModel, registry, opts, call) {
|
|
4533
|
+
if (!opts.enabled) {
|
|
4534
|
+
return call(registry.get(initialProvider), initialModel);
|
|
4535
|
+
}
|
|
4536
|
+
const attempts = planAttempts(initialProvider, initialModel, registry, opts);
|
|
4537
|
+
let lastErr;
|
|
4538
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
4539
|
+
const a = attempts[i];
|
|
4540
|
+
const prev = i > 0 ? attempts[i - 1] : void 0;
|
|
4541
|
+
if (prev && prev.providerId !== a.providerId) {
|
|
4542
|
+
opts.onFallback?.(prev.providerId, a.providerId, a.model, lastErr);
|
|
4543
|
+
} else if (a.retryNumber > 0) {
|
|
4544
|
+
opts.onRetry?.(a.retryNumber, opts.retries, a.providerId, lastErr);
|
|
4545
|
+
await sleep(backoffDelay(a.retryNumber - 1, opts, classifyError(lastErr)));
|
|
4546
|
+
}
|
|
4547
|
+
try {
|
|
4548
|
+
return await call(registry.get(a.providerId), a.model);
|
|
4549
|
+
} catch (err) {
|
|
4550
|
+
lastErr = err;
|
|
4551
|
+
const klass = classifyError(err);
|
|
4552
|
+
if (klass === "aborted") throw err;
|
|
4553
|
+
if (klass === "auth" || klass === "bad_request") {
|
|
4554
|
+
let j = i + 1;
|
|
4555
|
+
while (j < attempts.length && attempts[j].providerId === a.providerId) j++;
|
|
4556
|
+
if (j >= attempts.length) throw err;
|
|
4557
|
+
i = j - 1;
|
|
4558
|
+
continue;
|
|
4559
|
+
}
|
|
4560
|
+
if (i === attempts.length - 1) throw err;
|
|
4561
|
+
}
|
|
4562
|
+
}
|
|
4563
|
+
throw lastErr;
|
|
4564
|
+
}
|
|
4565
|
+
async function* withFallbackStream(initialProvider, initialModel, registry, opts, createStream) {
|
|
4566
|
+
if (!opts.enabled) {
|
|
4567
|
+
yield* createStream(registry.get(initialProvider), initialModel);
|
|
4568
|
+
return;
|
|
4569
|
+
}
|
|
4570
|
+
const attempts = planAttempts(initialProvider, initialModel, registry, opts);
|
|
4571
|
+
let lastErr;
|
|
4572
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
4573
|
+
const a = attempts[i];
|
|
4574
|
+
const prev = i > 0 ? attempts[i - 1] : void 0;
|
|
4575
|
+
if (prev && prev.providerId !== a.providerId) {
|
|
4576
|
+
opts.onFallback?.(prev.providerId, a.providerId, a.model, lastErr);
|
|
4577
|
+
} else if (a.retryNumber > 0) {
|
|
4578
|
+
opts.onRetry?.(a.retryNumber, opts.retries, a.providerId, lastErr);
|
|
4579
|
+
await sleep(backoffDelay(a.retryNumber - 1, opts, classifyError(lastErr)));
|
|
4580
|
+
}
|
|
4581
|
+
let yielded = false;
|
|
4582
|
+
try {
|
|
4583
|
+
const gen = createStream(registry.get(a.providerId), a.model);
|
|
4584
|
+
for await (const chunk of gen) {
|
|
4585
|
+
yielded = true;
|
|
4586
|
+
yield chunk;
|
|
4587
|
+
}
|
|
4588
|
+
return;
|
|
4589
|
+
} catch (err) {
|
|
4590
|
+
lastErr = err;
|
|
4591
|
+
if (yielded) throw err;
|
|
4592
|
+
const klass = classifyError(err);
|
|
4593
|
+
if (klass === "aborted") throw err;
|
|
4594
|
+
if (klass === "auth" || klass === "bad_request") {
|
|
4595
|
+
let j = i + 1;
|
|
4596
|
+
while (j < attempts.length && attempts[j].providerId === a.providerId) j++;
|
|
4597
|
+
if (j >= attempts.length) throw err;
|
|
4598
|
+
i = j - 1;
|
|
4599
|
+
continue;
|
|
4600
|
+
}
|
|
4601
|
+
if (i === attempts.length - 1) throw err;
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
throw lastErr;
|
|
4605
|
+
}
|
|
4606
|
+
function shortErrorTag(err) {
|
|
4607
|
+
if (err == null) return "unknown";
|
|
4608
|
+
const e = err;
|
|
4609
|
+
if (e.code) return e.code;
|
|
4610
|
+
const status = e.status ?? e.statusCode;
|
|
4611
|
+
if (typeof status === "number") return `HTTP ${status}`;
|
|
4612
|
+
if (e instanceof ProviderError && e.message) {
|
|
4613
|
+
const m = e.message.match(/\[[^\]]+\]\s*(.{0,60})/);
|
|
4614
|
+
if (m) return m[1].trim();
|
|
4615
|
+
}
|
|
4616
|
+
if (e instanceof Error && e.message) return e.message.slice(0, 60);
|
|
4617
|
+
return "error";
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4467
4620
|
// src/repl/notify.ts
|
|
4468
4621
|
import { spawn } from "child_process";
|
|
4469
4622
|
import { platform as platform2 } from "os";
|
|
@@ -5820,6 +5973,35 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5820
5973
|
thinkingBudget: params.thinkingBudget
|
|
5821
5974
|
};
|
|
5822
5975
|
}
|
|
5976
|
+
/**
|
|
5977
|
+
* Build FallbackOptions from config + wire one-line notice callbacks to stderr.
|
|
5978
|
+
* v0.4.144+: when config.fallback.enabled is true, network/5xx/429 failures retry
|
|
5979
|
+
* on the same provider with exponential backoff; persistent failures walk the
|
|
5980
|
+
* config.fallback.chain. Returns disabled-opts if user hasn't opted in.
|
|
5981
|
+
*/
|
|
5982
|
+
getFallbackOptions(spinner) {
|
|
5983
|
+
const cfg = this.config.get("fallback");
|
|
5984
|
+
const enabled = !!cfg?.enabled;
|
|
5985
|
+
return {
|
|
5986
|
+
enabled,
|
|
5987
|
+
retries: cfg?.retries ?? 2,
|
|
5988
|
+
initialBackoffMs: cfg?.initialBackoffMs ?? 500,
|
|
5989
|
+
maxBackoffMs: cfg?.maxBackoffMs ?? 8e3,
|
|
5990
|
+
chain: cfg?.chain ?? [],
|
|
5991
|
+
onRetry: (attempt, total, providerId, err) => {
|
|
5992
|
+
spinner.stop();
|
|
5993
|
+
process.stderr.write(theme.warning(` [${providerId}] retry ${attempt}/${total}: ${shortErrorTag(err)}
|
|
5994
|
+
`));
|
|
5995
|
+
spinner.start("Retrying...");
|
|
5996
|
+
},
|
|
5997
|
+
onFallback: (from, to, toModel, err) => {
|
|
5998
|
+
spinner.stop();
|
|
5999
|
+
process.stderr.write(theme.warning(` [${from} \u2192 ${to}] falling over to ${toModel}: ${shortErrorTag(err)}
|
|
6000
|
+
`));
|
|
6001
|
+
spinner.start("Retrying...");
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
}
|
|
5823
6005
|
/**
|
|
5824
6006
|
* Compute smart-routing decision for this user turn.
|
|
5825
6007
|
* Only considers models available for the current provider (rule skipped otherwise).
|
|
@@ -6515,9 +6697,19 @@ ${mcpBudgetNote}` : "");
|
|
|
6515
6697
|
if (supportsStreamingTools) {
|
|
6516
6698
|
const streamAc = this.setupStreamInterrupt();
|
|
6517
6699
|
try {
|
|
6518
|
-
const
|
|
6519
|
-
|
|
6520
|
-
|
|
6700
|
+
const fallbackOpts = this.getFallbackOptions(spinner);
|
|
6701
|
+
const streamGen = withFallbackStream(
|
|
6702
|
+
this.currentProvider,
|
|
6703
|
+
effectiveModel,
|
|
6704
|
+
this.providers,
|
|
6705
|
+
fallbackOpts,
|
|
6706
|
+
(p, m) => {
|
|
6707
|
+
const tc = p;
|
|
6708
|
+
if (typeof tc.chatWithToolsStream !== "function") {
|
|
6709
|
+
throw new Error(`provider ${p.info.id} does not support streaming tool calls`);
|
|
6710
|
+
}
|
|
6711
|
+
return tc.chatWithToolsStream({ ...chatRequest, model: m, signal: streamAc.signal }, toolDefs);
|
|
6712
|
+
}
|
|
6521
6713
|
);
|
|
6522
6714
|
const streamResult = await this.consumeToolStream(streamGen, spinner);
|
|
6523
6715
|
if (streamResult.toolCalls.length > 0) {
|
|
@@ -6546,7 +6738,14 @@ ${mcpBudgetNote}` : "");
|
|
|
6546
6738
|
this.teardownStreamInterrupt();
|
|
6547
6739
|
}
|
|
6548
6740
|
} else {
|
|
6549
|
-
|
|
6741
|
+
const fallbackOpts = this.getFallbackOptions(spinner);
|
|
6742
|
+
result = await withFallback(
|
|
6743
|
+
this.currentProvider,
|
|
6744
|
+
effectiveModel,
|
|
6745
|
+
this.providers,
|
|
6746
|
+
fallbackOpts,
|
|
6747
|
+
(p, m) => p.chatWithTools({ ...chatRequest, model: m }, toolDefs)
|
|
6748
|
+
);
|
|
6550
6749
|
}
|
|
6551
6750
|
if (result.usage) {
|
|
6552
6751
|
roundUsage.inputTokens += result.usage.inputTokens;
|
|
@@ -7381,7 +7580,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7381
7580
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7382
7581
|
process.exit(1);
|
|
7383
7582
|
}
|
|
7384
|
-
const { startWebServer } = await import("./server-
|
|
7583
|
+
const { startWebServer } = await import("./server-X24SIKZE.js");
|
|
7385
7584
|
await startWebServer({ port, host: options.host });
|
|
7386
7585
|
});
|
|
7387
7586
|
program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
|
|
@@ -7548,12 +7747,12 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7548
7747
|
console.log(footer + "\n");
|
|
7549
7748
|
});
|
|
7550
7749
|
program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
|
|
7551
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7750
|
+
const { runDoctorCli } = await import("./doctor-cli-RHGMQVCU.js");
|
|
7552
7751
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7553
7752
|
});
|
|
7554
7753
|
program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
|
|
7555
7754
|
try {
|
|
7556
|
-
const batch = await import("./batch-
|
|
7755
|
+
const batch = await import("./batch-64YESATH.js");
|
|
7557
7756
|
switch (action) {
|
|
7558
7757
|
case "submit":
|
|
7559
7758
|
if (!arg) {
|
|
@@ -7596,7 +7795,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7596
7795
|
}
|
|
7597
7796
|
});
|
|
7598
7797
|
program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
|
|
7599
|
-
const { startMcpServer } = await import("./server-
|
|
7798
|
+
const { startMcpServer } = await import("./server-MGKTVVAR.js");
|
|
7600
7799
|
await startMcpServer({
|
|
7601
7800
|
allowDestructive: !!options.allowDestructive,
|
|
7602
7801
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7723,7 +7922,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7723
7922
|
}),
|
|
7724
7923
|
config.get("customProviders")
|
|
7725
7924
|
);
|
|
7726
|
-
const { startHub } = await import("./hub-
|
|
7925
|
+
const { startHub } = await import("./hub-SXNKYCN7.js");
|
|
7727
7926
|
await startHub(
|
|
7728
7927
|
{
|
|
7729
7928
|
topic: topic ?? "",
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ToolRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PWCPOHZ4.js";
|
|
5
5
|
import "./chunk-UQQJWHRV.js";
|
|
6
6
|
import "./chunk-2DXY7UGF.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-2JPLV25X.js";
|
|
8
8
|
import {
|
|
9
9
|
getDangerLevel,
|
|
10
10
|
runTool,
|
|
11
11
|
schemaToJsonSchema
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QSGDXXE6.js";
|
|
13
13
|
import "./chunk-2ZD3YTVM.js";
|
|
14
14
|
import {
|
|
15
15
|
VERSION
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-XW4EP5IE.js";
|
|
17
17
|
import "./chunk-4BKXL7SM.js";
|
|
18
18
|
import "./chunk-7ZJN4KLV.js";
|
|
19
19
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
loadDevState,
|
|
15
15
|
persistToolRound,
|
|
16
16
|
setupProxy
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-IGZVCNGE.js";
|
|
18
18
|
import {
|
|
19
19
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
20
20
|
HALLUCINATION_CORRECTION_MESSAGE,
|
|
@@ -28,10 +28,10 @@ import {
|
|
|
28
28
|
looksLikeDocumentBody,
|
|
29
29
|
stripPseudoToolCalls,
|
|
30
30
|
stripToolCallReminder
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-EHLHWFZP.js";
|
|
32
32
|
import {
|
|
33
33
|
ConfigManager
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-WPYKTLP2.js";
|
|
35
35
|
import {
|
|
36
36
|
ToolExecutor,
|
|
37
37
|
ToolRegistry,
|
|
@@ -49,14 +49,14 @@ import {
|
|
|
49
49
|
spawnAgentContext,
|
|
50
50
|
truncateOutput,
|
|
51
51
|
undoStack
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-PWCPOHZ4.js";
|
|
53
53
|
import "./chunk-UQQJWHRV.js";
|
|
54
54
|
import "./chunk-2DXY7UGF.js";
|
|
55
|
-
import "./chunk-
|
|
55
|
+
import "./chunk-2JPLV25X.js";
|
|
56
56
|
import {
|
|
57
57
|
getDangerLevel,
|
|
58
58
|
runTool
|
|
59
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-QSGDXXE6.js";
|
|
60
60
|
import "./chunk-2ZD3YTVM.js";
|
|
61
61
|
import {
|
|
62
62
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
SKILLS_DIR_NAME,
|
|
77
77
|
VERSION,
|
|
78
78
|
buildUserIdentityPrompt
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-XW4EP5IE.js";
|
|
80
80
|
import {
|
|
81
81
|
formatGitContextForPrompt,
|
|
82
82
|
getGitContext,
|
|
@@ -2460,7 +2460,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2460
2460
|
case "test": {
|
|
2461
2461
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2462
2462
|
try {
|
|
2463
|
-
const { executeTests } = await import("./run-tests-
|
|
2463
|
+
const { executeTests } = await import("./run-tests-X4YQXIGP.js");
|
|
2464
2464
|
const argStr = args.join(" ").trim();
|
|
2465
2465
|
let testArgs = {};
|
|
2466
2466
|
if (argStr) {
|
|
@@ -3,18 +3,18 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
googleSearchContext,
|
|
5
5
|
truncateOutput
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-PWCPOHZ4.js";
|
|
7
7
|
import "./chunk-UQQJWHRV.js";
|
|
8
8
|
import "./chunk-2DXY7UGF.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-2JPLV25X.js";
|
|
10
10
|
import {
|
|
11
11
|
getDangerLevel,
|
|
12
12
|
runTool
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-QSGDXXE6.js";
|
|
14
14
|
import "./chunk-2ZD3YTVM.js";
|
|
15
15
|
import {
|
|
16
16
|
SUBAGENT_ALLOWED_TOOLS
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-XW4EP5IE.js";
|
|
18
18
|
import "./chunk-4BKXL7SM.js";
|
|
19
19
|
import "./chunk-7ZJN4KLV.js";
|
|
20
20
|
import "./chunk-KHYD3WXE.js";
|