@botconnector/bccli 0.4.1 → 0.4.2
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/{acp-3PHBAI64.js → acp-UYC6APR5.js} +30 -6
- package/dist/acp.d.ts +1 -0
- package/dist/agent.d.ts +5 -1
- package/dist/args-NRTZWWEV.js +13 -0
- package/dist/args.d.ts +2 -0
- package/dist/checkpoints.d.ts +1 -0
- package/dist/{chunk-BKGFA2PT.js → chunk-266SY3MC.js} +1 -1
- package/dist/{chunk-MFHCQQEN.js → chunk-3I5BW3ZT.js} +3 -2
- package/dist/{chunk-UZWJQF67.js → chunk-3WHI4LN3.js} +2 -1
- package/dist/{chunk-WNACAUDK.js → chunk-5YJ3ZQVR.js} +66 -9
- package/dist/{chunk-24JN75FZ.js → chunk-6M55UPES.js} +2 -2
- package/dist/{chunk-XV7ZVL4J.js → chunk-6UO5GX55.js} +26 -12
- package/dist/{chunk-R5RE46CW.js → chunk-C64KM37J.js} +36 -6
- package/dist/{chunk-GN4W3T6E.js → chunk-H7XJDKJY.js} +4 -4
- package/dist/{chunk-JHPGOAXU.js → chunk-HQW4BROS.js} +4 -5
- package/dist/{chunk-75BECX4F.js → chunk-IYR5PYA3.js} +4 -4
- package/dist/{chunk-45SDLMTV.js → chunk-JXM6REER.js} +1 -1
- package/dist/{chunk-BLOYFIAD.js → chunk-KPTML72Q.js} +1 -1
- package/dist/{chunk-WI22M2ID.js → chunk-NQOGVP3I.js} +2 -2
- package/dist/{chunk-QZKLZELZ.js → chunk-OK2USAXX.js} +28 -4
- package/dist/{chunk-PZRKU4UM.js → chunk-R72OV7RF.js} +421 -108
- package/dist/{chunk-FLQPE4S5.js → chunk-RX4UQX43.js} +4 -1
- package/dist/{chunk-BC7UXFE4.js → chunk-SVD4LHJC.js} +64 -3
- package/dist/{chunk-BXQQCUAC.js → chunk-TIMSYZIR.js} +7 -7
- package/dist/{chunk-MHIYLXJC.js → chunk-WFZKJY3R.js} +8 -4
- package/dist/{chunk-BGXNR74O.js → chunk-ZEPTUKNW.js} +119 -31
- package/dist/cli.js +60 -43
- package/dist/{completion-HPPFDAPB.js → completion-D2BSBTQO.js} +1 -1
- package/dist/{config-DIDLDONU.js → config-ENDRMOTP.js} +3 -3
- package/dist/{config-IU76CPK2.js → config-LAINORU5.js} +2 -2
- package/dist/config.d.ts +2 -0
- package/dist/{ghBotCli-E3VPHNZY.js → ghBotCli-TSLRORJJ.js} +21 -20
- package/dist/{integrationCli-Q2YPDTPG.js → integrationCli-HXCSEWH2.js} +2 -2
- package/dist/{login-FP3BB44A.js → login-RYESFZG6.js} +4 -4
- package/dist/lsp.d.ts +3 -0
- package/dist/mcp/manager.d.ts +18 -0
- package/dist/{mcpCli-SNBDUWJN.js → mcpCli-SETTCL3K.js} +6 -6
- package/dist/{modelsCli-CZ2HNGKR.js → modelsCli-OP7CDZC7.js} +6 -6
- package/dist/{oauthLogin-6FWQABJ7.js → oauthLogin-XWY7OHCG.js} +1 -1
- package/dist/{pluginsCli-LPIUUDWB.js → pluginsCli-ZQNKWZHJ.js} +2 -2
- package/dist/{prCli-5IMV3VNQ.js → prCli-6PUWTMTP.js} +20 -4
- package/dist/prCli.d.ts +13 -0
- package/dist/print.d.ts +2 -0
- package/dist/provider.d.ts +5 -0
- package/dist/providerCli-5OZI2GQQ.js +15 -0
- package/dist/sdk.d.ts +5 -1
- package/dist/sdk.js +733 -176
- package/dist/{serve-X2ZV4S5U.js → serve-4J7HA4JO.js} +17 -17
- package/dist/{serve-KWOECK5W.js → serve-K5AH4MGO.js} +3 -3
- package/dist/session-YQXCCKXI.js +12 -0
- package/dist/session.d.ts +3 -0
- package/dist/setup-S4AJT6XE.js +24 -0
- package/dist/slash/info.d.ts +1 -0
- package/dist/{statsCli-CF3R7ATL.js → statsCli-XR6BEZQQ.js} +2 -2
- package/dist/tokenBudget.d.ts +1 -1
- package/dist/tools/edit.d.ts +7 -2
- package/dist/tools/grep.d.ts +14 -2
- package/dist/tools/ignore.d.ts +2 -2
- package/dist/tools/paths.d.ts +2 -0
- package/dist/{transferCli-YUFPI6AH.js → transferCli-R2KEIWQR.js} +8 -6
- package/dist/ui/complete.d.ts +5 -0
- package/dist/ui/vim.d.ts +1 -1
- package/dist/{ui-IVIFNUCC.js → ui-36ZEK65V.js} +177 -54
- package/dist/{update-TZ2G6KQ3.js → update-FSS7X5WV.js} +2 -2
- package/package.json +1 -1
- package/dist/args-W6BNKY7K.js +0 -13
- package/dist/providerCli-NMUFXAAS.js +0 -15
- package/dist/session-GKEXDJKZ.js +0 -12
- package/dist/setup-OV3NWQN5.js +0 -24
|
@@ -36,6 +36,9 @@ function runAcp(input, output, opts) {
|
|
|
36
36
|
const replyError = (id, code, message) => write({ jsonrpc: "2.0", id, error: { code, message } });
|
|
37
37
|
const update = (sessionId, body) => write({ jsonrpc: "2.0", method: "session/update", params: { sessionId, update: body } });
|
|
38
38
|
const ioFor = (sid, session) => ({
|
|
39
|
+
onThinking(delta) {
|
|
40
|
+
update(sid, { sessionUpdate: "agent_thought_chunk", content: { type: "text", text: delta } });
|
|
41
|
+
},
|
|
39
42
|
toolStart(id, tool, target) {
|
|
40
43
|
session.open.push({ id, tool, target });
|
|
41
44
|
update(sid, { sessionUpdate: "tool_call", toolCallId: id, title: titleOf(tool, target), kind: kindOf(tool), status: "in_progress", rawInput: { target } });
|
|
@@ -89,7 +92,7 @@ function runAcp(input, output, opts) {
|
|
|
89
92
|
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
90
93
|
agentCapabilities: {
|
|
91
94
|
loadSession: false,
|
|
92
|
-
promptCapabilities: { image: false, audio: false, embeddedContext:
|
|
95
|
+
promptCapabilities: { image: false, audio: false, embeddedContext: true }
|
|
93
96
|
}
|
|
94
97
|
});
|
|
95
98
|
}
|
|
@@ -108,7 +111,17 @@ function runAcp(input, output, opts) {
|
|
|
108
111
|
const sid = params?.sessionId ?? "";
|
|
109
112
|
const session = sessions.get(sid);
|
|
110
113
|
if (!session) return replyError(id, -32602, "Unknown session");
|
|
111
|
-
|
|
114
|
+
if (session.controller) return replyError(id, -32e3, "Session is busy");
|
|
115
|
+
const text = (params?.prompt ?? []).map((p) => {
|
|
116
|
+
if (p?.type === "text") return String(p.text ?? "");
|
|
117
|
+
if ((p?.type === "resource" || p?.type === "embeddedContext") && p.resource?.text) {
|
|
118
|
+
const label = p.resource.uri ? `
|
|
119
|
+
[${p.resource.uri}]
|
|
120
|
+
` : "\n";
|
|
121
|
+
return `${label}${p.resource.text}`;
|
|
122
|
+
}
|
|
123
|
+
return "";
|
|
124
|
+
}).filter(Boolean).join("\n");
|
|
112
125
|
const controller = new AbortController();
|
|
113
126
|
session.controller = controller;
|
|
114
127
|
let cancelled = false;
|
|
@@ -122,8 +135,10 @@ function runAcp(input, output, opts) {
|
|
|
122
135
|
if (cancelled) return reply(id, { stopReason: "cancelled" });
|
|
123
136
|
return replyError(id, -32603, e.message);
|
|
124
137
|
} finally {
|
|
125
|
-
session.controller
|
|
126
|
-
|
|
138
|
+
if (session.controller === controller) {
|
|
139
|
+
session.controller = null;
|
|
140
|
+
session.open = [];
|
|
141
|
+
}
|
|
127
142
|
}
|
|
128
143
|
return reply(id, { stopReason: cancelled ? "cancelled" : "end_turn" });
|
|
129
144
|
}
|
|
@@ -150,6 +165,10 @@ function runAcp(input, output, opts) {
|
|
|
150
165
|
};
|
|
151
166
|
const onEnd = () => {
|
|
152
167
|
input.removeListener("data", onData);
|
|
168
|
+
for (const session of sessions.values()) {
|
|
169
|
+
session.controller?.abort();
|
|
170
|
+
for (const settle of [...session.pending]) settle("no");
|
|
171
|
+
}
|
|
153
172
|
resolve();
|
|
154
173
|
};
|
|
155
174
|
input.on("data", onData);
|
|
@@ -161,17 +180,22 @@ function runtimeAgent(cwd, allowAll = false) {
|
|
|
161
180
|
return {
|
|
162
181
|
async run(text, onChunk, signal, io) {
|
|
163
182
|
if (!rt) {
|
|
164
|
-
const { parseCliArgs } = await import("./args-
|
|
165
|
-
const { createRuntime } = await import("./setup-
|
|
183
|
+
const { parseCliArgs } = await import("./args-NRTZWWEV.js");
|
|
184
|
+
const { createRuntime } = await import("./setup-S4AJT6XE.js");
|
|
166
185
|
rt = createRuntime({ cwd, args: { ...parseCliArgs([]), allowAll } });
|
|
167
186
|
}
|
|
168
187
|
if (io && !allowAll) rt.agent.askPermission = (req) => io.askPermission(req);
|
|
188
|
+
let turnError;
|
|
169
189
|
rt.agent.onEvent = (event) => {
|
|
170
190
|
if (event.type === "text") onChunk(event.delta);
|
|
191
|
+
else if (event.type === "thinking") io?.onThinking?.(event.delta);
|
|
171
192
|
else if (event.type === "toolStart") io?.toolStart(event.id, event.tool, event.target);
|
|
172
193
|
else if (event.type === "toolEnd") io?.toolEnd(event.id, event.output, event.isError);
|
|
194
|
+
else if (event.type === "error") turnError = event.message;
|
|
195
|
+
else if (event.type === "budgetExceeded") turnError = `Budget exceeded (${event.kind})`;
|
|
173
196
|
};
|
|
174
197
|
await rt.agent.run(text, signal);
|
|
198
|
+
if (turnError) throw new Error(turnError);
|
|
175
199
|
}
|
|
176
200
|
};
|
|
177
201
|
}
|
package/dist/acp.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface AcpIo {
|
|
|
5
5
|
toolStart(id: string, tool: string, target: string): void;
|
|
6
6
|
toolEnd(id: string, output: string, isError: boolean): void;
|
|
7
7
|
askPermission(req: PermissionAsk): Promise<PermissionAnswer>;
|
|
8
|
+
onThinking?(delta: string): void;
|
|
8
9
|
}
|
|
9
10
|
/** The minimum an ACP client needs: run one prompt, stream text chunks, allow cancellation. */
|
|
10
11
|
export interface AcpAgent {
|
package/dist/agent.d.ts
CHANGED
|
@@ -109,14 +109,18 @@ export declare class Agent {
|
|
|
109
109
|
private definitions;
|
|
110
110
|
private turnTools;
|
|
111
111
|
private turnDefinitions;
|
|
112
|
-
|
|
112
|
+
readonly readFiles: Set<string>;
|
|
113
113
|
private readonly webBudget;
|
|
114
114
|
private readonly maxSteps?;
|
|
115
115
|
private contextWindow;
|
|
116
|
+
private budgetModel;
|
|
116
117
|
private systemPrompt;
|
|
117
118
|
constructor(opts: AgentOptions);
|
|
118
119
|
setSystemPrompt(text: string): void;
|
|
119
120
|
setContextWindow(window: number): void;
|
|
121
|
+
getContextWindow(): number;
|
|
122
|
+
setBudgetModel(model: string): void;
|
|
123
|
+
getBudgetModel(): string;
|
|
120
124
|
setTools(tools: Tool[]): void;
|
|
121
125
|
private isParallelSafe;
|
|
122
126
|
private push;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
helpText,
|
|
4
|
+
parseCliArgs
|
|
5
|
+
} from "./chunk-6UO5GX55.js";
|
|
6
|
+
import "./chunk-WFZKJY3R.js";
|
|
7
|
+
import "./chunk-KPTML72Q.js";
|
|
8
|
+
import "./chunk-RX4UQX43.js";
|
|
9
|
+
import "./chunk-3WHI4LN3.js";
|
|
10
|
+
export {
|
|
11
|
+
helpText,
|
|
12
|
+
parseCliArgs
|
|
13
|
+
};
|
package/dist/args.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export interface CliArgs {
|
|
|
45
45
|
project?: string;
|
|
46
46
|
/** `bccli pr` — explicit owner/name repo when cwd is not a git checkout of the PR. */
|
|
47
47
|
repo?: string;
|
|
48
|
+
/** Automatic fallback model ref when the primary model fails with 429 or 5xx. */
|
|
49
|
+
fallbackModel?: string;
|
|
48
50
|
}
|
|
49
51
|
/** Help text in the current language (call it after the language is set). */
|
|
50
52
|
export declare const helpText: () => string;
|
package/dist/checkpoints.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class CheckpointStore {
|
|
|
8
8
|
private readonly history;
|
|
9
9
|
private current;
|
|
10
10
|
private pendingRedo;
|
|
11
|
+
private offset;
|
|
11
12
|
beginTurn(): void;
|
|
12
13
|
/** Call before writing a file; only the first snapshot per file per turn is kept. */
|
|
13
14
|
snapshot(path: string): Promise<void>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
quarantineCorruptFile,
|
|
4
4
|
writeFileAtomic
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RX4UQX43.js";
|
|
6
6
|
|
|
7
7
|
// src/mcp/oauth.ts
|
|
8
8
|
import { spawn } from "child_process";
|
|
@@ -156,8 +156,9 @@ async function authorizeMcpServer(spec, deps) {
|
|
|
156
156
|
res.end("<html><body><p>BCCLI is connected. You can close this tab.</p></body></html>");
|
|
157
157
|
settle.resolve(code);
|
|
158
158
|
} catch (error) {
|
|
159
|
+
const escaped = error.message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
159
160
|
res.writeHead(400, { "content-type": "text/html; charset=utf-8" });
|
|
160
|
-
res.end(`<html><body><p>${
|
|
161
|
+
res.end(`<html><body><p>${escaped}</p></body></html>`);
|
|
161
162
|
settle.reject(error);
|
|
162
163
|
}
|
|
163
164
|
});
|
|
@@ -458,7 +458,8 @@ Opsi:
|
|
|
458
458
|
"gh is not available ({error}); install GitHub CLI first": "gh tidak tersedia ({error}); pasang GitHub CLI dulu",
|
|
459
459
|
"gh pr checkout {n} failed (exit {code})": "gh pr checkout {n} gagal (exit {code})",
|
|
460
460
|
"checked out PR #{n}": "checkout PR #{n} selesai",
|
|
461
|
-
"--allow-all: the PR task runs every tool without asking": "--allow-all: tugas PR menjalankan semua alat tanpa bertanya"
|
|
461
|
+
"--allow-all: the PR task runs every tool without asking": "--allow-all: tugas PR menjalankan semua alat tanpa bertanya",
|
|
462
|
+
"view or change configuration settings": "lihat atau ubah pengaturan konfigurasi"
|
|
462
463
|
};
|
|
463
464
|
|
|
464
465
|
// src/i18n.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
reasoningPayload
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KPTML72Q.js";
|
|
5
5
|
import {
|
|
6
6
|
t
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3WHI4LN3.js";
|
|
8
8
|
|
|
9
9
|
// src/provider.ts
|
|
10
10
|
import OpenAI from "openai";
|
|
@@ -171,7 +171,7 @@ async function readStream(res, onText, onThinking) {
|
|
|
171
171
|
}
|
|
172
172
|
current = target;
|
|
173
173
|
if (tc.id) target.id = tc.id;
|
|
174
|
-
if (tc.function?.name &&
|
|
174
|
+
if (tc.function?.name && target.name !== tc.function.name) target.name += tc.function.name;
|
|
175
175
|
if (tc.function?.arguments) target.arguments += tc.function.arguments;
|
|
176
176
|
}
|
|
177
177
|
};
|
|
@@ -378,7 +378,16 @@ function responsesFinishReason(items, toolCallCount, incompleteReason) {
|
|
|
378
378
|
function hasPendingProgrammaticReplay(messages) {
|
|
379
379
|
let pending = false;
|
|
380
380
|
for (const message of messages) {
|
|
381
|
+
if (message.role === "user" && typeof message.content === "string") {
|
|
382
|
+
pending = false;
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (message.role === "tool" && message.content === "Cancelled by the user.") {
|
|
386
|
+
pending = false;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
381
389
|
if (message.role !== "assistant") continue;
|
|
390
|
+
if (message.content) pending = false;
|
|
382
391
|
for (const item of message.responses_output_items ?? []) {
|
|
383
392
|
if (item.type === "program") pending = true;
|
|
384
393
|
else if (item.type === "message" && pending) pending = false;
|
|
@@ -452,7 +461,7 @@ async function readResponsesStream(res, onText, onThinking) {
|
|
|
452
461
|
calls.set(index, {
|
|
453
462
|
id: String(event.item.call_id || current?.id || event.item.id || `call_${index}`),
|
|
454
463
|
name: String(event.item.name || current?.name || ""),
|
|
455
|
-
arguments: String(event.item.arguments
|
|
464
|
+
arguments: String(event.item.arguments || current?.arguments || ""),
|
|
456
465
|
...programCaller(event.item) ?? current?.caller ? { caller: programCaller(event.item) ?? current?.caller } : {}
|
|
457
466
|
});
|
|
458
467
|
}
|
|
@@ -688,7 +697,7 @@ async function readResponsesWebSocketTurn(events, ws, onText, onThinking, signal
|
|
|
688
697
|
calls.set(index, {
|
|
689
698
|
id: String(event.item.call_id || current?.id || event.item.id || `call_${index}`),
|
|
690
699
|
name: String(event.item.name || current?.name || ""),
|
|
691
|
-
arguments: String(event.item.arguments
|
|
700
|
+
arguments: String(event.item.arguments || current?.arguments || ""),
|
|
692
701
|
...programCaller(event.item) ?? current?.caller ? { caller: programCaller(event.item) ?? current?.caller } : {}
|
|
693
702
|
});
|
|
694
703
|
}
|
|
@@ -749,7 +758,7 @@ function createProvider(options) {
|
|
|
749
758
|
const isBotConnectorCloud = /^https:\/\/api\.botconnector\.id\/v1\/?$/.test(baseURL) && apiKey?.startsWith("bc_live_");
|
|
750
759
|
if (isBotConnectorCloud) {
|
|
751
760
|
headers["x-botconnector-client"] = "bccli";
|
|
752
|
-
headers["x-botconnector-client-version"] = "0.4.
|
|
761
|
+
headers["x-botconnector-client-version"] = "0.4.2";
|
|
753
762
|
}
|
|
754
763
|
const useNativeResponses = isBotConnectorCloud && providerId === "bc-cloud" && model === "gpt-6-luna";
|
|
755
764
|
const useResponsesWebSocket = useNativeResponses && Boolean(apiKey) && (fetchOverride === void 0 || responsesWebSocketFactory !== void 0);
|
|
@@ -780,7 +789,7 @@ function createProvider(options) {
|
|
|
780
789
|
baseURL: baseURL.replace(/\/+$/, ""),
|
|
781
790
|
defaultHeaders: {
|
|
782
791
|
"x-botconnector-client": "bccli",
|
|
783
|
-
"x-botconnector-client-version": "0.4.
|
|
792
|
+
"x-botconnector-client-version": "0.4.2"
|
|
784
793
|
}
|
|
785
794
|
});
|
|
786
795
|
lunaWs = responsesWebSocketFactory ? responsesWebSocketFactory(client) : new ResponsesWS(client, { reconnect: null });
|
|
@@ -863,8 +872,13 @@ function createProvider(options) {
|
|
|
863
872
|
}
|
|
864
873
|
async function post(path, body, signal) {
|
|
865
874
|
let lastError;
|
|
875
|
+
let retryAfterWaitMs;
|
|
866
876
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
867
|
-
if (attempt > 0)
|
|
877
|
+
if (attempt > 0) {
|
|
878
|
+
const delay = retryAfterWaitMs ?? retryDelayMs * 2 ** (attempt - 1);
|
|
879
|
+
retryAfterWaitMs = void 0;
|
|
880
|
+
await sleep(delay, signal);
|
|
881
|
+
}
|
|
868
882
|
let res;
|
|
869
883
|
try {
|
|
870
884
|
res = await doFetch(`${baseURL}${path}`, { method: "POST", headers, body: JSON.stringify(body), signal });
|
|
@@ -874,6 +888,11 @@ function createProvider(options) {
|
|
|
874
888
|
continue;
|
|
875
889
|
}
|
|
876
890
|
if (res.ok) return res;
|
|
891
|
+
const retryHeader = res.headers.get("retry-after");
|
|
892
|
+
if (retryHeader) {
|
|
893
|
+
const secs = Number(retryHeader);
|
|
894
|
+
if (Number.isFinite(secs) && secs > 0 && secs <= 30) retryAfterWaitMs = Math.ceil(secs * 1e3);
|
|
895
|
+
}
|
|
877
896
|
const text = await res.text().catch(() => "");
|
|
878
897
|
lastError = new ProviderError(t("{status} from {url}: {message}", { status: res.status, url: baseURL, message: errorMessage(text) }), res.status);
|
|
879
898
|
const deterministicQuota429 = res.status === 429 && /"code"\s*:\s*"(?:luna_monthly_quota_exhausted|plan_allowance_exhausted)"/i.test(text);
|
|
@@ -936,11 +955,49 @@ function createProvider(options) {
|
|
|
936
955
|
}
|
|
937
956
|
};
|
|
938
957
|
}
|
|
958
|
+
function withFallbackProvider(primary, fallbacks) {
|
|
959
|
+
return {
|
|
960
|
+
async chat(req) {
|
|
961
|
+
let emitted = false;
|
|
962
|
+
const wrappedReq = {
|
|
963
|
+
...req,
|
|
964
|
+
onText: req.onText ? (delta) => {
|
|
965
|
+
emitted = true;
|
|
966
|
+
req.onText?.(delta);
|
|
967
|
+
} : () => {
|
|
968
|
+
emitted = true;
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
try {
|
|
972
|
+
return await primary.chat(wrappedReq);
|
|
973
|
+
} catch (primaryError) {
|
|
974
|
+
if (emitted || req.signal?.aborted) throw primaryError;
|
|
975
|
+
const status = primaryError instanceof ProviderError ? primaryError.status : void 0;
|
|
976
|
+
const canFallback = status === void 0 || status === 429 || status === 408 || status >= 500;
|
|
977
|
+
if (!canFallback) throw primaryError;
|
|
978
|
+
const chain = fallbacks();
|
|
979
|
+
if (!chain.length) throw primaryError;
|
|
980
|
+
let lastError = primaryError;
|
|
981
|
+
for (const fb of chain) {
|
|
982
|
+
if (req.signal?.aborted) throw lastError;
|
|
983
|
+
try {
|
|
984
|
+
return await fb.chat(req);
|
|
985
|
+
} catch (fbError) {
|
|
986
|
+
lastError = fbError;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
throw lastError;
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
listModels: () => primary.listModels()
|
|
993
|
+
};
|
|
994
|
+
}
|
|
939
995
|
|
|
940
996
|
export {
|
|
941
997
|
contentText,
|
|
942
998
|
imageUserMessage,
|
|
943
999
|
hasPendingProgrammaticReplay,
|
|
944
1000
|
completionAssistantMessage,
|
|
945
|
-
createProvider
|
|
1001
|
+
createProvider,
|
|
1002
|
+
withFallbackProvider
|
|
946
1003
|
};
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
MODE_ORDER
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WFZKJY3R.js";
|
|
5
5
|
import {
|
|
6
6
|
REASONING_LEVELS,
|
|
7
7
|
isReasoningLevel
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KPTML72Q.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigError
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-RX4UQX43.js";
|
|
12
12
|
import {
|
|
13
13
|
parseLang,
|
|
14
14
|
t
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-3WHI4LN3.js";
|
|
16
16
|
|
|
17
17
|
// src/args.ts
|
|
18
18
|
import { parseArgs } from "util";
|
|
@@ -41,9 +41,18 @@ var LOOPBACK_BIND = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1"]);
|
|
|
41
41
|
function trustFence(headers, port) {
|
|
42
42
|
const host = headers.host;
|
|
43
43
|
if (!host) return "missing Host header";
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
let hostname;
|
|
45
|
+
let hostPort;
|
|
46
|
+
if (host.startsWith("[")) {
|
|
47
|
+
const close = host.indexOf("]");
|
|
48
|
+
if (close === -1) return `non-loopback Host: ${host}`;
|
|
49
|
+
hostname = host.slice(0, close + 1);
|
|
50
|
+
hostPort = host[close + 1] === ":" ? Number(host.slice(close + 2)) : 80;
|
|
51
|
+
} else {
|
|
52
|
+
const sep = host.lastIndexOf(":");
|
|
53
|
+
hostname = sep > -1 ? host.slice(0, sep) : host;
|
|
54
|
+
hostPort = sep > -1 ? Number(host.slice(sep + 1)) : 80;
|
|
55
|
+
}
|
|
47
56
|
if (!LOOPBACK_HOSTS.has(hostname)) return `non-loopback Host: ${hostname}`;
|
|
48
57
|
if (hostPort !== port) return `Host port ${hostPort} does not match listener ${port}`;
|
|
49
58
|
if (headers.origin) {
|
|
@@ -111,9 +120,12 @@ Options:
|
|
|
111
120
|
-h, --help this help`;
|
|
112
121
|
var helpText = () => t(HELP);
|
|
113
122
|
function parseCliArgs(argv) {
|
|
114
|
-
const expanded = argv.map(
|
|
115
|
-
|
|
116
|
-
|
|
123
|
+
const expanded = argv.map((a, i) => {
|
|
124
|
+
const nextIsFlagOrEnd = i + 1 >= argv.length || argv[i + 1].startsWith("-");
|
|
125
|
+
if (a === "--models" && nextIsFlagOrEnd) return "--models=all";
|
|
126
|
+
if (a === "--project" && nextIsFlagOrEnd) return "--project=";
|
|
127
|
+
return a;
|
|
128
|
+
});
|
|
117
129
|
const { values, positionals } = parseArgs({
|
|
118
130
|
args: expanded,
|
|
119
131
|
allowPositionals: true,
|
|
@@ -145,7 +157,8 @@ function parseCliArgs(argv) {
|
|
|
145
157
|
tools: { type: "string" },
|
|
146
158
|
models: { type: "string" },
|
|
147
159
|
project: { type: "string" },
|
|
148
|
-
repo: { type: "string" }
|
|
160
|
+
repo: { type: "string" },
|
|
161
|
+
"fallback-model": { type: "string" }
|
|
149
162
|
}
|
|
150
163
|
});
|
|
151
164
|
const reasoning = values.reasoning;
|
|
@@ -219,7 +232,8 @@ function parseCliArgs(argv) {
|
|
|
219
232
|
tools,
|
|
220
233
|
models,
|
|
221
234
|
project: values.project,
|
|
222
|
-
repo: values.repo
|
|
235
|
+
repo: values.repo,
|
|
236
|
+
fallbackModel: values["fallback-model"]
|
|
223
237
|
};
|
|
224
238
|
}
|
|
225
239
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runCommand,
|
|
4
4
|
runHooks
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZEPTUKNW.js";
|
|
6
6
|
import {
|
|
7
7
|
ConfigError
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RX4UQX43.js";
|
|
9
9
|
import {
|
|
10
10
|
t
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-3WHI4LN3.js";
|
|
12
12
|
|
|
13
13
|
// src/verify.ts
|
|
14
14
|
var MAX_VERIFY_ROUNDS = 2;
|
|
@@ -40,10 +40,19 @@ function toolLabel(tool) {
|
|
|
40
40
|
if (tool === "web_search") return "Search";
|
|
41
41
|
return tool.charAt(0).toUpperCase() + tool.slice(1);
|
|
42
42
|
}
|
|
43
|
+
function resolvePrintPrompt(prompt, stdinText) {
|
|
44
|
+
const cleanStdin = stdinText?.trim();
|
|
45
|
+
const cleanPrompt = prompt?.trim();
|
|
46
|
+
if (cleanStdin && cleanPrompt) return `${cleanStdin}
|
|
47
|
+
|
|
48
|
+
${cleanPrompt}`;
|
|
49
|
+
return cleanPrompt || cleanStdin || void 0;
|
|
50
|
+
}
|
|
43
51
|
async function runPrint(rt, prompt, io = { out: process.stdout, err: process.stderr }, opts = {}) {
|
|
44
52
|
const format = opts.outputFormat ?? "text";
|
|
45
53
|
const emit = (line) => io.out.write(`${JSON.stringify(line)}
|
|
46
54
|
`);
|
|
55
|
+
const startedMs = Date.now();
|
|
47
56
|
let result = "";
|
|
48
57
|
const toolNames = /* @__PURE__ */ new Map();
|
|
49
58
|
rt.interaction.approvePlan = async () => {
|
|
@@ -65,6 +74,9 @@ async function runPrint(rt, prompt, io = { out: process.stdout, err: process.std
|
|
|
65
74
|
result += event.delta;
|
|
66
75
|
}
|
|
67
76
|
break;
|
|
77
|
+
case "textReplace":
|
|
78
|
+
result = event.text;
|
|
79
|
+
break;
|
|
68
80
|
case "toolStart":
|
|
69
81
|
toolNames.set(event.id, event.tool);
|
|
70
82
|
io.err.write(`\u23BF ${toolLabel(event.tool)} ${event.target}
|
|
@@ -142,12 +154,29 @@ async function runPrint(rt, prompt, io = { out: process.stdout, err: process.std
|
|
|
142
154
|
for (const warning of stop.warnings) io.err.write(`${warning}
|
|
143
155
|
`);
|
|
144
156
|
await rt.emitPlugins("Stop");
|
|
157
|
+
const durationMs = Math.max(0, Date.now() - startedMs);
|
|
145
158
|
if (format === "json") {
|
|
146
|
-
io.out.write(
|
|
147
|
-
|
|
159
|
+
io.out.write(
|
|
160
|
+
`${JSON.stringify({
|
|
161
|
+
status: failed ? "failed" : "ok",
|
|
162
|
+
model: rt.modelRef,
|
|
163
|
+
session_id: rt.session.id,
|
|
164
|
+
usage: rt.agent.totalUsage,
|
|
165
|
+
duration_ms: durationMs,
|
|
166
|
+
result
|
|
167
|
+
})}
|
|
168
|
+
`
|
|
169
|
+
);
|
|
148
170
|
} else if (format === "stream-json") {
|
|
149
171
|
if (result) emit({ type: "message", text: result });
|
|
150
|
-
emit({
|
|
172
|
+
emit({
|
|
173
|
+
type: "result",
|
|
174
|
+
status: failed ? "failed" : "ok",
|
|
175
|
+
model: rt.modelRef,
|
|
176
|
+
session_id: rt.session.id,
|
|
177
|
+
usage: rt.agent.totalUsage,
|
|
178
|
+
duration_ms: durationMs
|
|
179
|
+
});
|
|
151
180
|
} else if (wroteText) {
|
|
152
181
|
io.out.write("\n");
|
|
153
182
|
}
|
|
@@ -225,6 +254,7 @@ export {
|
|
|
225
254
|
runVerify,
|
|
226
255
|
verifyFollowup,
|
|
227
256
|
toolLabel,
|
|
257
|
+
resolvePrintPrompt,
|
|
228
258
|
runPrint,
|
|
229
259
|
resolveWorktree,
|
|
230
260
|
worktreeListText
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
listAllModels
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IYR5PYA3.js";
|
|
5
5
|
import {
|
|
6
6
|
hasKey,
|
|
7
7
|
providerName,
|
|
8
8
|
removeGlobalProvider,
|
|
9
9
|
writeGlobalConfig
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-HQW4BROS.js";
|
|
11
11
|
import {
|
|
12
12
|
PRESETS,
|
|
13
13
|
loadConfig,
|
|
14
14
|
saveCredential
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-RX4UQX43.js";
|
|
16
16
|
import {
|
|
17
17
|
t
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-3WHI4LN3.js";
|
|
19
19
|
|
|
20
20
|
// src/providerCli.ts
|
|
21
21
|
async function addProviderKey(providerId, key, deps) {
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
bccliHome,
|
|
5
5
|
readCredentials,
|
|
6
6
|
readJsonConfig,
|
|
7
|
-
removeCredential
|
|
8
|
-
|
|
7
|
+
removeCredential,
|
|
8
|
+
writeFileAtomic
|
|
9
|
+
} from "./chunk-RX4UQX43.js";
|
|
9
10
|
|
|
10
11
|
// src/providers.ts
|
|
11
|
-
import { mkdirSync, writeFileSync } from "fs";
|
|
12
12
|
import { join } from "path";
|
|
13
13
|
function providerName(config, id) {
|
|
14
14
|
return PRESETS.find((p) => p.id === id)?.name ?? config.providers[id]?.name ?? id;
|
|
@@ -24,8 +24,7 @@ function readGlobalConfigFile(env = process.env) {
|
|
|
24
24
|
return readJsonConfig(globalPath(env));
|
|
25
25
|
}
|
|
26
26
|
function save(data, env) {
|
|
27
|
-
|
|
28
|
-
writeFileSync(globalPath(env), `${JSON.stringify(data, null, 2)}
|
|
27
|
+
writeFileAtomic(globalPath(env), `${JSON.stringify(data, null, 2)}
|
|
29
28
|
`);
|
|
30
29
|
}
|
|
31
30
|
function writeGlobalConfig(patch, env = process.env) {
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
import {
|
|
3
3
|
hasKey,
|
|
4
4
|
providerName
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-HQW4BROS.js";
|
|
6
6
|
import {
|
|
7
7
|
createProvider
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-5YJ3ZQVR.js";
|
|
9
9
|
import {
|
|
10
10
|
PRESETS,
|
|
11
11
|
readCredentials
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-RX4UQX43.js";
|
|
13
13
|
import {
|
|
14
14
|
t
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-3WHI4LN3.js";
|
|
16
16
|
|
|
17
17
|
// src/models.ts
|
|
18
18
|
function order(ids) {
|