@botconnector/bccli 0.4.0-beta.1 → 0.4.0-beta.11
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/README.md +56 -1
- package/dist/{args-EAKPBBGX.js → args-SKWUZOJD.js} +3 -2
- package/dist/{chunk-Z5JM76EL.js → chunk-2MGINW4O.js} +4 -1
- package/dist/{chunk-QH7XXNHU.js → chunk-6BLZELE6.js} +2 -2
- package/dist/{chunk-5C6NQFSI.js → chunk-7S6JXQCH.js} +1 -1
- package/dist/{chunk-XQLXE666.js → chunk-BFZXRKW5.js} +1 -1
- package/dist/chunk-CLN4Z5E3.js +60 -0
- package/dist/{chunk-TV6LEHOH.js → chunk-DX7CZTBB.js} +1 -1
- package/dist/{chunk-OSWQPSA4.js → chunk-KV27KTOX.js} +2 -0
- package/dist/{chunk-M7INIL2C.js → chunk-TRMRDQ43.js} +17 -3
- package/dist/{chunk-5ISYVAXI.js → chunk-U7GK73CK.js} +90 -15
- package/dist/cli.js +226 -40
- package/dist/{config-XPWPGNZJ.js → config-YUNKPCNB.js} +2 -2
- package/dist/integrationCli-4PEJ74UG.js +583 -0
- package/dist/{login-FTMR64IA.js → login-N2CJC6RU.js} +1 -1
- package/dist/{mcpCli-BV3IGR47.js → mcpCli-DZWQPTOS.js} +3 -3
- package/dist/providerCli-Q7LRM2NP.js +12 -0
- package/dist/{ui-LWZ75D7H.js → ui-6GTQUJOE.js} +211 -39
- package/package.json +2 -1
- package/dist/providerCli-SJRCBSRE.js +0 -11
package/dist/cli.js
CHANGED
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
HELP_TEXT,
|
|
4
|
-
parseCliArgs
|
|
5
|
-
} from "./chunk-M7INIL2C.js";
|
|
6
|
-
import {
|
|
7
|
-
addProviderKey,
|
|
8
|
-
createProvider,
|
|
9
|
-
listAllModels
|
|
10
|
-
} from "./chunk-5ISYVAXI.js";
|
|
11
|
-
import {
|
|
12
|
-
runLogin
|
|
13
|
-
} from "./chunk-QH7XXNHU.js";
|
|
14
2
|
import {
|
|
15
3
|
BUILTIN_AGENTS,
|
|
16
4
|
buildSystemPrompt,
|
|
@@ -20,13 +8,26 @@ import {
|
|
|
20
8
|
loadSkills,
|
|
21
9
|
parseFrontmatter,
|
|
22
10
|
runPrint
|
|
23
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-KV27KTOX.js";
|
|
12
|
+
import {
|
|
13
|
+
HELP_TEXT,
|
|
14
|
+
parseCliArgs
|
|
15
|
+
} from "./chunk-TRMRDQ43.js";
|
|
24
16
|
import {
|
|
25
17
|
Permissions
|
|
26
18
|
} from "./chunk-ELML4KVQ.js";
|
|
19
|
+
import {
|
|
20
|
+
addProviderKey,
|
|
21
|
+
createProvider,
|
|
22
|
+
listAllModels
|
|
23
|
+
} from "./chunk-U7GK73CK.js";
|
|
27
24
|
import {
|
|
28
25
|
providerName
|
|
29
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-7S6JXQCH.js";
|
|
27
|
+
import "./chunk-CLN4Z5E3.js";
|
|
28
|
+
import {
|
|
29
|
+
runLogin
|
|
30
|
+
} from "./chunk-6BLZELE6.js";
|
|
30
31
|
import {
|
|
31
32
|
Session,
|
|
32
33
|
pruneSessions
|
|
@@ -36,7 +37,7 @@ import {
|
|
|
36
37
|
bccliHome,
|
|
37
38
|
loadConfig,
|
|
38
39
|
resolveModel
|
|
39
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-2MGINW4O.js";
|
|
40
41
|
|
|
41
42
|
// src/tools/index.ts
|
|
42
43
|
import { z as z8 } from "zod";
|
|
@@ -300,6 +301,20 @@ async function readCapped(res) {
|
|
|
300
301
|
function htmlToText(html) {
|
|
301
302
|
return html.replace(/<(script|style|noscript)[\s\S]*?<\/\1>/gi, "").replace(/<(br|\/p|\/div|\/h[1-6]|\/li|\/tr)\s*\/?>/gi, "\n").replace(/<[^>]+>/g, "").replace(/ /g, " ").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, "&").split("\n").map((l) => l.replace(/\s+/g, " ").trim()).filter(Boolean).join("\n");
|
|
302
303
|
}
|
|
304
|
+
function describeFetchError(error) {
|
|
305
|
+
const cause = error.cause;
|
|
306
|
+
const code = cause?.code ?? "";
|
|
307
|
+
const detail = cause?.message ?? error.message;
|
|
308
|
+
if (error.name === "TimeoutError") return "tidak ada jawaban dalam 30 detik";
|
|
309
|
+
if (code === "ENOTFOUND" || code === "EAI_AGAIN") return `${detail} \u2014 DNS tidak menemukan host (salah ketik, offline, atau diblokir DNS/ISP)`;
|
|
310
|
+
if (/CERT|SELF_SIGNED|UNABLE_TO/.test(code)) {
|
|
311
|
+
return `${detail} \u2014 sertifikat TLS ditolak; sering karena antivirus/proxy yang memeriksa HTTPS. Coba jalankan dengan NODE_OPTIONS=--use-system-ca`;
|
|
312
|
+
}
|
|
313
|
+
if (/ECONNRESET|ECONNREFUSED|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|UND_ERR_CONNECT_TIMEOUT|UND_ERR_SOCKET/.test(code)) {
|
|
314
|
+
return `${detail} \u2014 koneksi gagal (firewall, proxy, atau situs diblokir jaringan)`;
|
|
315
|
+
}
|
|
316
|
+
return code ? `${detail} (${code})` : detail;
|
|
317
|
+
}
|
|
303
318
|
var fetchTool = defineTool({
|
|
304
319
|
name: "fetch",
|
|
305
320
|
description: "Fetch a URL (http/https). HTML is converted to plain text. Max 50k characters.",
|
|
@@ -327,12 +342,12 @@ var fetchTool = defineTool({
|
|
|
327
342
|
url = next;
|
|
328
343
|
}
|
|
329
344
|
} catch (error) {
|
|
330
|
-
return { output: `Gagal mengambil ${input.url}: ${error
|
|
345
|
+
return { output: `Gagal mengambil ${input.url}: ${describeFetchError(error)}`, isError: true };
|
|
331
346
|
}
|
|
332
347
|
if (!res) return { output: `Gagal mengambil ${input.url}`, isError: true };
|
|
333
348
|
const { text: body, truncated } = await readCapped(res);
|
|
334
|
-
if (!res.ok) return { output: `HTTP ${res.status} dari ${input.url}: ${body.slice(0, 500)}`, isError: true };
|
|
335
349
|
const text = (res.headers.get("content-type") ?? "").includes("html") ? htmlToText(body) : body;
|
|
350
|
+
if (!res.ok) return { output: `HTTP ${res.status} dari ${input.url}: ${text.slice(0, 500)}`, isError: true };
|
|
336
351
|
const clipped = text.length > MAX_CHARS || truncated ? `${text.slice(0, MAX_CHARS)}
|
|
337
352
|
\u2026 [dipotong]` : text;
|
|
338
353
|
const display = truncated ? "lebih dari 5 MB, dipotong" : `${text.length} karakter`;
|
|
@@ -521,6 +536,71 @@ function toolDefinitions(tools) {
|
|
|
521
536
|
});
|
|
522
537
|
}
|
|
523
538
|
|
|
539
|
+
// src/textToolCalls.ts
|
|
540
|
+
var PAIR = /(?:<arg_key>\s*|`)?([A-Za-z_]\w*)(?:\s*<\/arg_key>)?`?\s*(?:=\s*`|<arg_value>)([\s\S]*?)<\/arg_value>/g;
|
|
541
|
+
var CALL_START = /<tool_call>|\n?[^\n]*\bTool call list\b[^\n]*|\n\s*\d+\.\s*Tool:/g;
|
|
542
|
+
function coerce(value, type) {
|
|
543
|
+
const types = Array.isArray(type) ? type : [type];
|
|
544
|
+
const v = value.trim();
|
|
545
|
+
if ((types.includes("integer") || types.includes("number")) && v !== "" && !Number.isNaN(Number(v))) return Number(v);
|
|
546
|
+
if (types.includes("boolean") && /^(true|false)$/i.test(v)) return v.toLowerCase() === "true";
|
|
547
|
+
if ((types.includes("object") || types.includes("array")) && /^[[{]/.test(v)) {
|
|
548
|
+
try {
|
|
549
|
+
return JSON.parse(v);
|
|
550
|
+
} catch {
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return value.replace(/^\n+|\n+$/g, "");
|
|
554
|
+
}
|
|
555
|
+
function pickTool(name, keys, tools) {
|
|
556
|
+
const named = name && tools.find((t) => t.function.name === name);
|
|
557
|
+
if (named) return named;
|
|
558
|
+
let best;
|
|
559
|
+
let bestScore = 0;
|
|
560
|
+
let tie = false;
|
|
561
|
+
for (const t of tools) {
|
|
562
|
+
const params = t.function.parameters;
|
|
563
|
+
const props = Object.keys(params.properties ?? {});
|
|
564
|
+
if (!(params.required ?? []).every((r) => keys.includes(r))) continue;
|
|
565
|
+
const score = keys.filter((k) => props.includes(k)).length;
|
|
566
|
+
if (score > bestScore) [best, bestScore, tie] = [t, score, false];
|
|
567
|
+
else if (score === bestScore && score > 0) tie = true;
|
|
568
|
+
}
|
|
569
|
+
return tie ? void 0 : best;
|
|
570
|
+
}
|
|
571
|
+
function recoverTextToolCalls(text, tools) {
|
|
572
|
+
if (!/<\/arg_value>|<tool_call>/.test(text)) return null;
|
|
573
|
+
const starts = [...text.matchAll(CALL_START)].map((m) => m.index ?? 0);
|
|
574
|
+
const firstPair = text.search(PAIR);
|
|
575
|
+
const cut = Math.min(...[...starts, firstPair].filter((i) => i >= 0));
|
|
576
|
+
const bounds = starts.filter((i) => i >= cut);
|
|
577
|
+
if (!bounds.length || bounds[0] > cut) bounds.unshift(cut);
|
|
578
|
+
const toolCalls = [];
|
|
579
|
+
bounds.forEach((start, n) => {
|
|
580
|
+
const segment = text.slice(start, bounds[n + 1] ?? text.length);
|
|
581
|
+
const name = /<tool_call>\s*([A-Za-z_][\w.-]*)/.exec(segment)?.[1] ?? /Tool:\s*`?([A-Za-z_][\w.-]*)`?/.exec(segment)?.[1];
|
|
582
|
+
let args = [];
|
|
583
|
+
const flush = () => {
|
|
584
|
+
if (!args.length) return;
|
|
585
|
+
const keys = args.map(([k]) => k);
|
|
586
|
+
const tool = pickTool(name, keys, tools);
|
|
587
|
+
if (tool) {
|
|
588
|
+
const props = tool.function.parameters.properties ?? {};
|
|
589
|
+
const input = Object.fromEntries(args.filter(([k]) => k in props).map(([k, v]) => [k, coerce(v, props[k].type)]));
|
|
590
|
+
toolCalls.push({ id: `text_call_${toolCalls.length}`, name: tool.function.name, arguments: JSON.stringify(input) });
|
|
591
|
+
}
|
|
592
|
+
args = [];
|
|
593
|
+
};
|
|
594
|
+
for (const m of segment.matchAll(PAIR)) {
|
|
595
|
+
if (args.some(([k]) => k === m[1])) flush();
|
|
596
|
+
args.push([m[1], m[2]]);
|
|
597
|
+
}
|
|
598
|
+
flush();
|
|
599
|
+
});
|
|
600
|
+
if (!toolCalls.length) return null;
|
|
601
|
+
return { text: text.slice(0, cut).trim(), toolCalls };
|
|
602
|
+
}
|
|
603
|
+
|
|
524
604
|
// src/agent.ts
|
|
525
605
|
var estimateTokens = (text) => Math.ceil(text.length / 4);
|
|
526
606
|
var COMPACT_PROMPT = "Summarize the conversation so far for yourself so you can continue the work with no other context. Include: the user goals, decisions made, files touched and their current state, commands run and results, the task in progress and the next step. Be concise but complete.";
|
|
@@ -537,6 +617,7 @@ var Agent = class {
|
|
|
537
617
|
this.maxSteps = opts.maxSteps ?? 50;
|
|
538
618
|
this.contextWindow = opts.contextWindow ?? 128e3;
|
|
539
619
|
this.systemPrompt = opts.systemPrompt;
|
|
620
|
+
this.reasoning = opts.reasoning ?? "auto";
|
|
540
621
|
}
|
|
541
622
|
opts;
|
|
542
623
|
provider;
|
|
@@ -546,6 +627,7 @@ var Agent = class {
|
|
|
546
627
|
lastInputTokens = 0;
|
|
547
628
|
onEvent = () => {
|
|
548
629
|
};
|
|
630
|
+
reasoning;
|
|
549
631
|
askPermission = async () => "no";
|
|
550
632
|
tools;
|
|
551
633
|
definitions;
|
|
@@ -595,7 +677,8 @@ var Agent = class {
|
|
|
595
677
|
messages: [{ role: "system", content: this.systemPrompt }, ...this.messages, { role: "user", content: COMPACT_PROMPT }],
|
|
596
678
|
// Some gateways reject tool_calls in history when no tools are declared.
|
|
597
679
|
tools: this.definitions,
|
|
598
|
-
signal
|
|
680
|
+
signal,
|
|
681
|
+
reasoning: this.reasoning
|
|
599
682
|
});
|
|
600
683
|
this.clear();
|
|
601
684
|
this.push({ role: "user", content: `Ringkasan percakapan sebelumnya:
|
|
@@ -615,12 +698,21 @@ ${completion.text}` });
|
|
|
615
698
|
await this.compact(signal);
|
|
616
699
|
this.push({ role: "user", content: `Lanjutkan tugas ini sesuai ringkasan di atas: ${text}` });
|
|
617
700
|
}
|
|
618
|
-
|
|
701
|
+
let completion = await this.provider.chat({
|
|
619
702
|
messages: [{ role: "system", content: this.systemPrompt }, ...this.messages],
|
|
620
703
|
tools: this.turnDefinitions,
|
|
621
704
|
signal,
|
|
622
|
-
onText: (delta) => this.onEvent({ type: "text", delta })
|
|
705
|
+
onText: (delta) => this.onEvent({ type: "text", delta }),
|
|
706
|
+
onThinking: (delta) => this.onEvent({ type: "thinking", delta }),
|
|
707
|
+
reasoning: this.reasoning
|
|
623
708
|
});
|
|
709
|
+
if (!completion.toolCalls.length && completion.finishReason !== "repetition") {
|
|
710
|
+
const recovered = recoverTextToolCalls(completion.text, this.turnDefinitions);
|
|
711
|
+
if (recovered) {
|
|
712
|
+
completion = { ...completion, ...recovered };
|
|
713
|
+
this.onEvent({ type: "textReplace", text: recovered.text });
|
|
714
|
+
}
|
|
715
|
+
}
|
|
624
716
|
const usage = completion.usage ?? {
|
|
625
717
|
inputTokens: estimateTokens(this.systemPrompt) + estimateTokens(JSON.stringify(this.messages)),
|
|
626
718
|
outputTokens: estimateTokens(completion.text) + (completion.toolCalls.length ? estimateTokens(JSON.stringify(completion.toolCalls)) : 0)
|
|
@@ -819,8 +911,8 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
|
|
819
911
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
820
912
|
import { z as z9 } from "zod";
|
|
821
913
|
function mcpToolName(server, tool, taken) {
|
|
822
|
-
const
|
|
823
|
-
const base = `mcp__${
|
|
914
|
+
const clean2 = (s) => s.replace(/[^A-Za-z0-9_-]+/g, "_");
|
|
915
|
+
const base = `mcp__${clean2(server)}__${clean2(tool)}`.slice(0, 64);
|
|
824
916
|
let name = base;
|
|
825
917
|
for (let n = 2; taken.has(name); n++) name = `${base.slice(0, 64 - String(n).length - 1)}_${n}`;
|
|
826
918
|
taken.add(name);
|
|
@@ -965,8 +1057,69 @@ ${body}`, display: skill.description.slice(0, 60) };
|
|
|
965
1057
|
});
|
|
966
1058
|
}
|
|
967
1059
|
|
|
968
|
-
// src/tools/
|
|
1060
|
+
// src/tools/websearch.ts
|
|
969
1061
|
import { z as z12 } from "zod";
|
|
1062
|
+
var clean = (items, max) => (Array.isArray(items) ? items : []).filter((r) => typeof r?.url === "string" && /^https?:\/\//.test(r.url)).slice(0, max).map((r) => ({
|
|
1063
|
+
title: String(r.title || r.url).slice(0, 200),
|
|
1064
|
+
url: r.url,
|
|
1065
|
+
snippet: String(r.snippet || r.description || "").replace(/\s+/g, " ").trim().slice(0, 600)
|
|
1066
|
+
}));
|
|
1067
|
+
async function postJson(url, body, headers, signal) {
|
|
1068
|
+
const res = await fetch(url, {
|
|
1069
|
+
method: "POST",
|
|
1070
|
+
headers: { "content-type": "application/json", ...headers },
|
|
1071
|
+
body: JSON.stringify(body),
|
|
1072
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(3e4)])
|
|
1073
|
+
});
|
|
1074
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1075
|
+
return res.json();
|
|
1076
|
+
}
|
|
1077
|
+
function createWebSearchTool(opts) {
|
|
1078
|
+
const keenableURL = opts.keenableURL ?? "https://api.keenable.ai/v1/search/public";
|
|
1079
|
+
return defineTool({
|
|
1080
|
+
name: "web_search",
|
|
1081
|
+
description: "Search the web. Returns titles, URLs and short snippets. Use it to find the right pages instead of guessing URLs; then fetch a result URL when you need the full page.",
|
|
1082
|
+
schema: z12.object({
|
|
1083
|
+
query: z12.string().min(1).max(500).describe("Search query"),
|
|
1084
|
+
max_results: z12.number().int().min(1).max(10).optional().describe("Number of results (default 6)")
|
|
1085
|
+
}),
|
|
1086
|
+
kind: "read",
|
|
1087
|
+
target: (input) => input.query,
|
|
1088
|
+
parallelSafe: () => true,
|
|
1089
|
+
async run(input, ctx) {
|
|
1090
|
+
const max = input.max_results ?? 6;
|
|
1091
|
+
const errors = [];
|
|
1092
|
+
let results = [];
|
|
1093
|
+
const bc = opts.botconnector();
|
|
1094
|
+
if (bc) {
|
|
1095
|
+
try {
|
|
1096
|
+
const data = await postJson(`${bc.baseURL.replace(/\/+$/, "")}/web/search`, { query: input.query, max_results: max }, { authorization: `Bearer ${bc.apiKey}` }, ctx.signal);
|
|
1097
|
+
results = clean(data.results, max);
|
|
1098
|
+
} catch (error) {
|
|
1099
|
+
errors.push(`BotConnector: ${error.message}`);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
if (!results.length) {
|
|
1103
|
+
try {
|
|
1104
|
+
const data = await postJson(keenableURL, { query: input.query }, { "x-keenable-title": "BotConnector" }, ctx.signal);
|
|
1105
|
+
results = clean(data.results, max);
|
|
1106
|
+
} catch (error) {
|
|
1107
|
+
errors.push(`Keenable: ${error.message}`);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (!results.length) {
|
|
1111
|
+
return { output: errors.length ? `Web search gagal (${errors.join("; ")}).` : "Tidak ada hasil.", isError: errors.length > 0 };
|
|
1112
|
+
}
|
|
1113
|
+
const output = results.map((r, i) => `${i + 1}. ${r.title}
|
|
1114
|
+
${r.url}${r.snippet ? `
|
|
1115
|
+
${r.snippet}` : ""}`).join("\n");
|
|
1116
|
+
return { output, display: `${results.length} hasil` };
|
|
1117
|
+
}
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// src/tools/task.ts
|
|
1122
|
+
import { z as z13 } from "zod";
|
|
970
1123
|
function createTaskTool(opts) {
|
|
971
1124
|
const byName = new Map(opts.agents.map((a) => [a.name, a]));
|
|
972
1125
|
const list = opts.agents.map((a) => `- ${a.name}: ${a.description}`).join("\n");
|
|
@@ -974,10 +1127,10 @@ function createTaskTool(opts) {
|
|
|
974
1127
|
name: "task",
|
|
975
1128
|
description: `Delegate a self-contained sub-task to a subagent. It starts with an empty context and returns only its final report. Available agents:
|
|
976
1129
|
${list}`,
|
|
977
|
-
schema:
|
|
978
|
-
agent:
|
|
979
|
-
description:
|
|
980
|
-
prompt:
|
|
1130
|
+
schema: z13.object({
|
|
1131
|
+
agent: z13.string().describe("Agent name"),
|
|
1132
|
+
description: z13.string().describe("3-6 word summary shown to the user"),
|
|
1133
|
+
prompt: z13.string().describe("Full instructions; the subagent sees nothing else")
|
|
981
1134
|
}),
|
|
982
1135
|
kind: "read",
|
|
983
1136
|
target: (input) => `[${input.agent}] ${input.description}`,
|
|
@@ -1013,6 +1166,7 @@ ${def.prompt}`,
|
|
|
1013
1166
|
cwd: opts.cwd,
|
|
1014
1167
|
maxSteps: def.maxSteps ?? 50,
|
|
1015
1168
|
label: def.name,
|
|
1169
|
+
reasoning: opts.reasoning?.() ?? "auto",
|
|
1016
1170
|
// Subagent edits belong to the parent's turn so /undo reverts them too.
|
|
1017
1171
|
checkpoint: ctx.checkpoint
|
|
1018
1172
|
});
|
|
@@ -1041,7 +1195,7 @@ ${def.prompt}`,
|
|
|
1041
1195
|
}
|
|
1042
1196
|
|
|
1043
1197
|
// src/tools/todo.ts
|
|
1044
|
-
import { z as
|
|
1198
|
+
import { z as z14 } from "zod";
|
|
1045
1199
|
var TodoStore = class {
|
|
1046
1200
|
items = [];
|
|
1047
1201
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -1058,8 +1212,8 @@ function createTodoTool(store) {
|
|
|
1058
1212
|
return defineTool({
|
|
1059
1213
|
name: "todo_write",
|
|
1060
1214
|
description: "Write the task list for multi-step work (3+ steps). Send the whole list every time; exactly one item in_progress while working. Mark items completed as soon as they are done.",
|
|
1061
|
-
schema:
|
|
1062
|
-
todos:
|
|
1215
|
+
schema: z14.object({
|
|
1216
|
+
todos: z14.array(z14.object({ content: z14.string(), status: z14.enum(["pending", "in_progress", "completed"]) }))
|
|
1063
1217
|
}),
|
|
1064
1218
|
kind: "read",
|
|
1065
1219
|
target: (input) => `${input.todos.length} item`,
|
|
@@ -1081,9 +1235,10 @@ function createRuntime(opts) {
|
|
|
1081
1235
|
const home = bccliHome(env);
|
|
1082
1236
|
let config = loadConfig(opts.cwd, env);
|
|
1083
1237
|
let modelRef = opts.args.model ?? config.model;
|
|
1238
|
+
let reasoning = opts.args.reasoning ?? config.reasoning;
|
|
1084
1239
|
const makeProvider = (ref) => {
|
|
1085
1240
|
const resolved = resolveModel(config, ref, env);
|
|
1086
|
-
return opts.provider ?? createProvider({ baseURL: resolved.baseURL, apiKey: resolved.apiKey, model: resolved.model });
|
|
1241
|
+
return opts.provider ?? createProvider({ baseURL: resolved.baseURL, apiKey: resolved.apiKey, model: resolved.model, providerId: resolved.providerId });
|
|
1087
1242
|
};
|
|
1088
1243
|
const provider = makeProvider(modelRef);
|
|
1089
1244
|
const mode = opts.args.allowAll ? "allowAll" : opts.args.permissionMode ?? config.permissionMode;
|
|
@@ -1107,7 +1262,17 @@ function createRuntime(opts) {
|
|
|
1107
1262
|
}
|
|
1108
1263
|
}
|
|
1109
1264
|
const systemPrompt = buildSystemPrompt({ cwd: opts.cwd, home, model: modelRef, skills });
|
|
1110
|
-
const
|
|
1265
|
+
const webSearch = createWebSearchTool({
|
|
1266
|
+
botconnector: () => {
|
|
1267
|
+
try {
|
|
1268
|
+
const bc = resolveModel(config, "bc-cloud/search", env);
|
|
1269
|
+
return bc.apiKey ? { baseURL: bc.baseURL, apiKey: bc.apiKey } : void 0;
|
|
1270
|
+
} catch {
|
|
1271
|
+
return void 0;
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
});
|
|
1275
|
+
const baseTools = [...ALL_TOOLS, webSearch, createSkillTool(skills), createTodoTool(todos), createExitPlanTool({ permissions, interaction })];
|
|
1111
1276
|
const task = createTaskTool({
|
|
1112
1277
|
agents: [...BUILTIN_AGENTS, ...agentDefs],
|
|
1113
1278
|
// Subagents get whatever the main agent has right now (incl. MCP tools), minus task itself.
|
|
@@ -1116,7 +1281,8 @@ function createRuntime(opts) {
|
|
|
1116
1281
|
provider: () => agent.provider,
|
|
1117
1282
|
providerFor: makeProvider,
|
|
1118
1283
|
systemPrompt,
|
|
1119
|
-
cwd: opts.cwd
|
|
1284
|
+
cwd: opts.cwd,
|
|
1285
|
+
reasoning: () => reasoning
|
|
1120
1286
|
});
|
|
1121
1287
|
const agent = new Agent({
|
|
1122
1288
|
provider,
|
|
@@ -1125,6 +1291,7 @@ function createRuntime(opts) {
|
|
|
1125
1291
|
systemPrompt,
|
|
1126
1292
|
cwd: opts.cwd,
|
|
1127
1293
|
history,
|
|
1294
|
+
reasoning,
|
|
1128
1295
|
onMessage: (m) => session.append(m),
|
|
1129
1296
|
onReset: () => session.reset(),
|
|
1130
1297
|
onTurnStart: () => checkpoints.beginTurn(),
|
|
@@ -1166,6 +1333,9 @@ function createRuntime(opts) {
|
|
|
1166
1333
|
get modelRef() {
|
|
1167
1334
|
return modelRef;
|
|
1168
1335
|
},
|
|
1336
|
+
get reasoning() {
|
|
1337
|
+
return reasoning;
|
|
1338
|
+
},
|
|
1169
1339
|
agent,
|
|
1170
1340
|
get session() {
|
|
1171
1341
|
return session;
|
|
@@ -1173,6 +1343,8 @@ function createRuntime(opts) {
|
|
|
1173
1343
|
resume(previous) {
|
|
1174
1344
|
session = previous;
|
|
1175
1345
|
agent.load(previous.load());
|
|
1346
|
+
agent.totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
1347
|
+
todos.set([]);
|
|
1176
1348
|
checkpoints.clear();
|
|
1177
1349
|
},
|
|
1178
1350
|
newSession() {
|
|
@@ -1193,12 +1365,16 @@ function createRuntime(opts) {
|
|
|
1193
1365
|
setModel(ref) {
|
|
1194
1366
|
agent.provider = makeProvider(ref);
|
|
1195
1367
|
modelRef = ref;
|
|
1368
|
+
},
|
|
1369
|
+
setReasoning(level) {
|
|
1370
|
+
reasoning = level;
|
|
1371
|
+
agent.reasoning = level;
|
|
1196
1372
|
}
|
|
1197
1373
|
};
|
|
1198
1374
|
}
|
|
1199
1375
|
|
|
1200
1376
|
// src/version.ts
|
|
1201
|
-
var VERSION = true ? "0.4.0-beta.
|
|
1377
|
+
var VERSION = true ? "0.4.0-beta.11" : "0.0.0-dev";
|
|
1202
1378
|
|
|
1203
1379
|
// src/cli.ts
|
|
1204
1380
|
async function main() {
|
|
@@ -1214,15 +1390,25 @@ async function main() {
|
|
|
1214
1390
|
const cwd = process.cwd();
|
|
1215
1391
|
if (args.command === "login") return runLogin(args.loginProvider ?? "bc-cloud", cwd);
|
|
1216
1392
|
if (args.command === "mcp") {
|
|
1217
|
-
const { runMcpCommand } = await import("./mcpCli-
|
|
1218
|
-
const { readSecret } = await import("./login-
|
|
1393
|
+
const { runMcpCommand } = await import("./mcpCli-DZWQPTOS.js");
|
|
1394
|
+
const { readSecret } = await import("./login-N2CJC6RU.js");
|
|
1219
1395
|
return runMcpCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1220
1396
|
}
|
|
1221
1397
|
if (args.command === "provider") {
|
|
1222
|
-
const { runProviderCommand } = await import("./providerCli-
|
|
1223
|
-
const { readSecret } = await import("./login-
|
|
1398
|
+
const { runProviderCommand } = await import("./providerCli-Q7LRM2NP.js");
|
|
1399
|
+
const { readSecret } = await import("./login-N2CJC6RU.js");
|
|
1224
1400
|
return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1225
1401
|
}
|
|
1402
|
+
if (args.command === "connect" || args.command === "disconnect" || args.command === "integrations") {
|
|
1403
|
+
const { runIntegrationCommand } = await import("./integrationCli-4PEJ74UG.js");
|
|
1404
|
+
return runIntegrationCommand(args, {
|
|
1405
|
+
env: process.env,
|
|
1406
|
+
cwd,
|
|
1407
|
+
out: (s) => console.log(s),
|
|
1408
|
+
err: (s) => console.error(s),
|
|
1409
|
+
fetch: globalThis.fetch
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1226
1412
|
if (args.command === "models") {
|
|
1227
1413
|
const config = loadConfig(cwd);
|
|
1228
1414
|
const resolved = resolveModel(config, args.model ?? config.model);
|
|
@@ -1237,7 +1423,7 @@ async function main() {
|
|
|
1237
1423
|
}
|
|
1238
1424
|
if (args.print) {
|
|
1239
1425
|
if (!args.prompt) throw new ConfigError('Mode -p butuh tugas, contoh: bccli -p "jelaskan repo ini"');
|
|
1240
|
-
const { serversToStart } = await import("./config-
|
|
1426
|
+
const { serversToStart } = await import("./config-YUNKPCNB.js");
|
|
1241
1427
|
const plan = serversToStart(rt.home, cwd);
|
|
1242
1428
|
for (const s of plan.needTrust) {
|
|
1243
1429
|
console.error(`Server MCP project "${s.name}" dilewati (belum diizinkan; jalankan bccli interaktif sekali untuk menyetujuinya).`);
|
|
@@ -1250,7 +1436,7 @@ async function main() {
|
|
|
1250
1436
|
}
|
|
1251
1437
|
}
|
|
1252
1438
|
if (!process.stdin.isTTY) throw new ConfigError('Mode interaktif butuh terminal. Untuk skrip/CI pakai: bccli -p "tugas"');
|
|
1253
|
-
const { startInteractive } = await import("./ui-
|
|
1439
|
+
const { startInteractive } = await import("./ui-6GTQUJOE.js");
|
|
1254
1440
|
return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
|
|
1255
1441
|
}
|
|
1256
1442
|
main().then(
|