beecork 2.8.2 → 2.8.3
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/index.js +103 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -60,6 +60,13 @@ function normalizeEffort(raw) {
|
|
|
60
60
|
const v = (raw ?? "").trim().toLowerCase();
|
|
61
61
|
return EFFORTS.includes(v) ? v : void 0;
|
|
62
62
|
}
|
|
63
|
+
function normalizeProviderSort(raw) {
|
|
64
|
+
if (raw == null) return "latency";
|
|
65
|
+
const v = raw.trim().toLowerCase();
|
|
66
|
+
if (v === "latency" || v === "price" || v === "throughput") return v;
|
|
67
|
+
if (["", "off", "none", "default", "0", "false", "no"].includes(v)) return "";
|
|
68
|
+
return "latency";
|
|
69
|
+
}
|
|
63
70
|
function parseExtra(raw) {
|
|
64
71
|
if (!raw || !raw.trim()) return {};
|
|
65
72
|
try {
|
|
@@ -95,6 +102,10 @@ var config = {
|
|
|
95
102
|
// transient API failures
|
|
96
103
|
apiTimeoutMs: num("API_TIMEOUT_MS", 18e4),
|
|
97
104
|
// per-attempt model-call timeout (generous for reasoning models)
|
|
105
|
+
// Run a batch's independent, read-only tool calls (read_file/search/list_dir/web_fetch/…) CONCURRENTLY
|
|
106
|
+
// instead of one-at-a-time — the model is told to batch independent calls, so this cashes in the win
|
|
107
|
+
// (N web_fetches take ~1× instead of N×). Mutating/approval/interactive tools always stay serial.
|
|
108
|
+
parallelTools: !["0", "false", "off", "no"].includes((process.env.PARALLEL_TOOLS ?? "").trim().toLowerCase()),
|
|
98
109
|
// Tool operational limits
|
|
99
110
|
execTimeoutMs: num("EXEC_TIMEOUT_MS", 3e4),
|
|
100
111
|
// run_bash command timeout
|
|
@@ -115,6 +126,11 @@ var config = {
|
|
|
115
126
|
// startup default; changed live via /effort
|
|
116
127
|
openRouterExtra: parseExtra(process.env.OPENROUTER_EXTRA),
|
|
117
128
|
// advanced: extra request-body params (sampling, provider routing, …)
|
|
129
|
+
// Provider routing (overridable by a `provider` block in OPENROUTER_EXTRA). The same model is served
|
|
130
|
+
// by many OpenRouter backends with very different time-to-first-token; "latency" (the default) routes
|
|
131
|
+
// to the fastest-responding one so replies start streaming right away instead of stalling on a slow
|
|
132
|
+
// provider. Set OPENROUTER_PROVIDER_SORT=off to fall back to OpenRouter's default load-balanced routing.
|
|
133
|
+
providerSort: normalizeProviderSort(process.env.OPENROUTER_PROVIDER_SORT),
|
|
118
134
|
// Background tasks (run_bash background:true → check_task / stop_task)
|
|
119
135
|
maxBackgroundTasks: num("MAX_BG_TASKS", 5),
|
|
120
136
|
// per-session cap on concurrent background commands
|
|
@@ -1072,6 +1088,9 @@ function loadCatalog() {
|
|
|
1072
1088
|
}).catch(() => {
|
|
1073
1089
|
});
|
|
1074
1090
|
}
|
|
1091
|
+
function primeCatalog() {
|
|
1092
|
+
loadCatalog();
|
|
1093
|
+
}
|
|
1075
1094
|
var baseId = (slug) => slug.split(":")[0];
|
|
1076
1095
|
function shouldSendReasoning(model) {
|
|
1077
1096
|
loadCatalog();
|
|
@@ -2815,7 +2834,7 @@ function parseSSELine(line) {
|
|
|
2815
2834
|
return out3;
|
|
2816
2835
|
}
|
|
2817
2836
|
function buildRequestBody(opts) {
|
|
2818
|
-
const { model, messages, includeTools, effort, reasoningSupported, extra, tools } = opts;
|
|
2837
|
+
const { model, messages, includeTools, effort, reasoningSupported, extra, tools, providerSort } = opts;
|
|
2819
2838
|
const body = { ...extra };
|
|
2820
2839
|
body.model = model;
|
|
2821
2840
|
body.messages = messages;
|
|
@@ -2824,6 +2843,7 @@ function buildRequestBody(opts) {
|
|
|
2824
2843
|
if (reasoningSupported && !("reasoning" in extra)) {
|
|
2825
2844
|
body.reasoning = effort === "off" ? { enabled: false } : { effort };
|
|
2826
2845
|
}
|
|
2846
|
+
if (providerSort && !("provider" in extra)) body.provider = { sort: providerSort };
|
|
2827
2847
|
return body;
|
|
2828
2848
|
}
|
|
2829
2849
|
function pruneReasoningForSend(messages) {
|
|
@@ -2849,7 +2869,8 @@ async function callModel(messages, includeTools = true, signal, opts) {
|
|
|
2849
2869
|
effort: state.reasoningEffort,
|
|
2850
2870
|
reasoningSupported: shouldSendReasoning(state.model),
|
|
2851
2871
|
extra: config.openRouterExtra,
|
|
2852
|
-
tools: opts?.tools
|
|
2872
|
+
tools: opts?.tools,
|
|
2873
|
+
providerSort: config.providerSort
|
|
2853
2874
|
});
|
|
2854
2875
|
const tries = config.retryAttempts;
|
|
2855
2876
|
for (let attempt = 1; attempt <= tries; attempt++) {
|
|
@@ -3428,7 +3449,69 @@ async function handleAskUser(args) {
|
|
|
3428
3449
|
if (choice) console.log(color.green(` \u2192 ${stripControl(choice.label)}`) + "\n");
|
|
3429
3450
|
return askUserMessage(question, choice, true);
|
|
3430
3451
|
}
|
|
3431
|
-
|
|
3452
|
+
var PARALLEL_SAFE = /* @__PURE__ */ new Set([
|
|
3453
|
+
"read_file",
|
|
3454
|
+
"search",
|
|
3455
|
+
"list_dir",
|
|
3456
|
+
"read_skill",
|
|
3457
|
+
"web_fetch",
|
|
3458
|
+
"web_search",
|
|
3459
|
+
"read_dev_signals",
|
|
3460
|
+
"check_task"
|
|
3461
|
+
]);
|
|
3462
|
+
function lastMutationIndex(calls) {
|
|
3463
|
+
return calls.reduce((acc, c, i) => c.function.name === "write_file" || c.function.name === "edit_file" ? i : acc, -1);
|
|
3464
|
+
}
|
|
3465
|
+
function isParallelSafe(call, deps) {
|
|
3466
|
+
if (!config.parallelTools) return false;
|
|
3467
|
+
if (!PARALLEL_SAFE.has(call.function.name)) return false;
|
|
3468
|
+
const tool = toolsByName.get(call.function.name);
|
|
3469
|
+
if (!tool) return false;
|
|
3470
|
+
let args;
|
|
3471
|
+
try {
|
|
3472
|
+
args = JSON.parse(call.function.arguments);
|
|
3473
|
+
} catch {
|
|
3474
|
+
return false;
|
|
3475
|
+
}
|
|
3476
|
+
const decision = decideApproval(tool, args, {
|
|
3477
|
+
mode: state.mode,
|
|
3478
|
+
autoApprove: config.autoApprove,
|
|
3479
|
+
approvedTools: deps.approvedTools,
|
|
3480
|
+
approvedGuardKeys: deps.approvedGuardKeys,
|
|
3481
|
+
toolName: call.function.name,
|
|
3482
|
+
dangerouslySkip: config.dangerouslySkipPermissions
|
|
3483
|
+
});
|
|
3484
|
+
return decision.action === "run";
|
|
3485
|
+
}
|
|
3486
|
+
async function runReadOnlyBatch(block, messages, step, deps) {
|
|
3487
|
+
const { callCounts, signal } = deps;
|
|
3488
|
+
const parts = await Promise.all(block.map(async (call) => {
|
|
3489
|
+
const sig = `${call.function.name}:${call.function.arguments}`;
|
|
3490
|
+
const seen = (callCounts.get(sig) ?? 0) + 1;
|
|
3491
|
+
callCounts.set(sig, seen);
|
|
3492
|
+
if (seen >= config.loopRepeatLimit) {
|
|
3493
|
+
return { call, out: color.yellow(` \u21B3 skipped \u2014 repeated identical call ${seen}\xD7`), content: "You have already called this exact tool with these exact arguments several times; it is not making progress. Stop repeating it \u2014 try a different approach or give your final answer." };
|
|
3494
|
+
}
|
|
3495
|
+
let callArgs = {};
|
|
3496
|
+
try {
|
|
3497
|
+
callArgs = JSON.parse(call.function.arguments);
|
|
3498
|
+
} catch {
|
|
3499
|
+
}
|
|
3500
|
+
if (config.traceFile) trace.push({ tool: call.function.name, args: call.function.arguments, step });
|
|
3501
|
+
let result = await runTool(call, signal);
|
|
3502
|
+
const summary = summarizeResult(call.function.name, callArgs, result);
|
|
3503
|
+
if (result.length > config.maxToolResultChars) {
|
|
3504
|
+
result = result.slice(0, config.maxToolResultChars) + `
|
|
3505
|
+
\u2026[truncated ${result.length - config.maxToolResultChars} chars]`;
|
|
3506
|
+
}
|
|
3507
|
+
return { call, out: " " + renderToolCall(call.function.name, callArgs) + summary, content: result };
|
|
3508
|
+
}));
|
|
3509
|
+
for (const p of parts) {
|
|
3510
|
+
process.stdout.write(p.out + "\n");
|
|
3511
|
+
messages.push({ role: "tool", tool_call_id: p.call.id, content: p.content });
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
async function handleToolCall(call, messages, step, deps, verifyThisCall = true) {
|
|
3432
3515
|
const { approvedTools, approvedGuardKeys, callCounts, ask, signal } = deps;
|
|
3433
3516
|
const pushTool = (content) => messages.push({ role: "tool", tool_call_id: call.id, content });
|
|
3434
3517
|
const sig = `${call.function.name}:${call.function.arguments}`;
|
|
@@ -3503,7 +3586,7 @@ async function handleToolCall(call, messages, step, deps) {
|
|
|
3503
3586
|
}
|
|
3504
3587
|
const summary = summarizeResult(call.function.name, callArgs, result);
|
|
3505
3588
|
let verifyOut = "";
|
|
3506
|
-
if (config.verifyCommand && (call.function.name === "write_file" || call.function.name === "edit_file")) {
|
|
3589
|
+
if (verifyThisCall && config.verifyCommand && (call.function.name === "write_file" || call.function.name === "edit_file")) {
|
|
3507
3590
|
verifyOut = await runVerify(signal);
|
|
3508
3591
|
result += `
|
|
3509
3592
|
|
|
@@ -3560,9 +3643,21 @@ async function runTurn(messages, userInput, ask, approvedTools, approvedGuardKey
|
|
|
3560
3643
|
break;
|
|
3561
3644
|
}
|
|
3562
3645
|
if (message.tool_calls && message.tool_calls.length > 0) {
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3646
|
+
const calls = message.tool_calls;
|
|
3647
|
+
const lastMutationIdx = lastMutationIndex(calls);
|
|
3648
|
+
let i = 0;
|
|
3649
|
+
while (i < calls.length && !signal?.aborted) {
|
|
3650
|
+
if (isParallelSafe(calls[i], deps)) {
|
|
3651
|
+
let j = i + 1;
|
|
3652
|
+
while (j < calls.length && isParallelSafe(calls[j], deps)) j++;
|
|
3653
|
+
if (j - i > 1) {
|
|
3654
|
+
await runReadOnlyBatch(calls.slice(i, j), messages, step, deps);
|
|
3655
|
+
i = j;
|
|
3656
|
+
continue;
|
|
3657
|
+
}
|
|
3658
|
+
}
|
|
3659
|
+
await handleToolCall(calls[i], messages, step, deps, i === lastMutationIdx);
|
|
3660
|
+
i++;
|
|
3566
3661
|
}
|
|
3567
3662
|
} else {
|
|
3568
3663
|
answered = !steering2?.length;
|
|
@@ -4414,6 +4509,7 @@ ${instr.trusted}`;
|
|
|
4414
4509
|
process.exit(1);
|
|
4415
4510
|
}
|
|
4416
4511
|
state.apiKey = apiKey;
|
|
4512
|
+
primeCatalog();
|
|
4417
4513
|
const ask = tty ? (q) => readChoice(q) : (q) => rl.question(q);
|
|
4418
4514
|
let activeTurn = null;
|
|
4419
4515
|
let userTurns = 0;
|