@botconnector/bccli 0.4.0-beta.2 → 0.4.0-beta.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/cli.js +74 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -521,6 +521,71 @@ function toolDefinitions(tools) {
|
|
|
521
521
|
});
|
|
522
522
|
}
|
|
523
523
|
|
|
524
|
+
// src/textToolCalls.ts
|
|
525
|
+
var PAIR = /(?:<arg_key>\s*|`)?([A-Za-z_]\w*)(?:\s*<\/arg_key>)?`?\s*(?:=\s*`|<arg_value>)([\s\S]*?)<\/arg_value>/g;
|
|
526
|
+
var CALL_START = /<tool_call>|\n?[^\n]*\bTool call list\b[^\n]*|\n\s*\d+\.\s*Tool:/g;
|
|
527
|
+
function coerce(value, type) {
|
|
528
|
+
const types = Array.isArray(type) ? type : [type];
|
|
529
|
+
const v = value.trim();
|
|
530
|
+
if ((types.includes("integer") || types.includes("number")) && v !== "" && !Number.isNaN(Number(v))) return Number(v);
|
|
531
|
+
if (types.includes("boolean") && /^(true|false)$/i.test(v)) return v.toLowerCase() === "true";
|
|
532
|
+
if ((types.includes("object") || types.includes("array")) && /^[[{]/.test(v)) {
|
|
533
|
+
try {
|
|
534
|
+
return JSON.parse(v);
|
|
535
|
+
} catch {
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return value.replace(/^\n+|\n+$/g, "");
|
|
539
|
+
}
|
|
540
|
+
function pickTool(name, keys, tools) {
|
|
541
|
+
const named = name && tools.find((t) => t.function.name === name);
|
|
542
|
+
if (named) return named;
|
|
543
|
+
let best;
|
|
544
|
+
let bestScore = 0;
|
|
545
|
+
let tie = false;
|
|
546
|
+
for (const t of tools) {
|
|
547
|
+
const params = t.function.parameters;
|
|
548
|
+
const props = Object.keys(params.properties ?? {});
|
|
549
|
+
if (!(params.required ?? []).every((r) => keys.includes(r))) continue;
|
|
550
|
+
const score = keys.filter((k) => props.includes(k)).length;
|
|
551
|
+
if (score > bestScore) [best, bestScore, tie] = [t, score, false];
|
|
552
|
+
else if (score === bestScore && score > 0) tie = true;
|
|
553
|
+
}
|
|
554
|
+
return tie ? void 0 : best;
|
|
555
|
+
}
|
|
556
|
+
function recoverTextToolCalls(text, tools) {
|
|
557
|
+
if (!/<\/arg_value>|<tool_call>/.test(text)) return null;
|
|
558
|
+
const starts = [...text.matchAll(CALL_START)].map((m) => m.index ?? 0);
|
|
559
|
+
const firstPair = text.search(PAIR);
|
|
560
|
+
const cut = Math.min(...[...starts, firstPair].filter((i) => i >= 0));
|
|
561
|
+
const bounds = starts.filter((i) => i >= cut);
|
|
562
|
+
if (!bounds.length || bounds[0] > cut) bounds.unshift(cut);
|
|
563
|
+
const toolCalls = [];
|
|
564
|
+
bounds.forEach((start, n) => {
|
|
565
|
+
const segment = text.slice(start, bounds[n + 1] ?? text.length);
|
|
566
|
+
const name = /<tool_call>\s*([A-Za-z_][\w.-]*)/.exec(segment)?.[1] ?? /Tool:\s*`?([A-Za-z_][\w.-]*)`?/.exec(segment)?.[1];
|
|
567
|
+
let args = [];
|
|
568
|
+
const flush = () => {
|
|
569
|
+
if (!args.length) return;
|
|
570
|
+
const keys = args.map(([k]) => k);
|
|
571
|
+
const tool = pickTool(name, keys, tools);
|
|
572
|
+
if (tool) {
|
|
573
|
+
const props = tool.function.parameters.properties ?? {};
|
|
574
|
+
const input = Object.fromEntries(args.filter(([k]) => k in props).map(([k, v]) => [k, coerce(v, props[k].type)]));
|
|
575
|
+
toolCalls.push({ id: `text_call_${toolCalls.length}`, name: tool.function.name, arguments: JSON.stringify(input) });
|
|
576
|
+
}
|
|
577
|
+
args = [];
|
|
578
|
+
};
|
|
579
|
+
for (const m of segment.matchAll(PAIR)) {
|
|
580
|
+
if (args.some(([k]) => k === m[1])) flush();
|
|
581
|
+
args.push([m[1], m[2]]);
|
|
582
|
+
}
|
|
583
|
+
flush();
|
|
584
|
+
});
|
|
585
|
+
if (!toolCalls.length) return null;
|
|
586
|
+
return { text: text.slice(0, cut).trim(), toolCalls };
|
|
587
|
+
}
|
|
588
|
+
|
|
524
589
|
// src/agent.ts
|
|
525
590
|
var estimateTokens = (text) => Math.ceil(text.length / 4);
|
|
526
591
|
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.";
|
|
@@ -615,12 +680,19 @@ ${completion.text}` });
|
|
|
615
680
|
await this.compact(signal);
|
|
616
681
|
this.push({ role: "user", content: `Lanjutkan tugas ini sesuai ringkasan di atas: ${text}` });
|
|
617
682
|
}
|
|
618
|
-
|
|
683
|
+
let completion = await this.provider.chat({
|
|
619
684
|
messages: [{ role: "system", content: this.systemPrompt }, ...this.messages],
|
|
620
685
|
tools: this.turnDefinitions,
|
|
621
686
|
signal,
|
|
622
687
|
onText: (delta) => this.onEvent({ type: "text", delta })
|
|
623
688
|
});
|
|
689
|
+
if (!completion.toolCalls.length && completion.finishReason !== "repetition") {
|
|
690
|
+
const recovered = recoverTextToolCalls(completion.text, this.turnDefinitions);
|
|
691
|
+
if (recovered) {
|
|
692
|
+
completion = { ...completion, ...recovered };
|
|
693
|
+
this.onEvent({ type: "textReplace", text: recovered.text });
|
|
694
|
+
}
|
|
695
|
+
}
|
|
624
696
|
const usage = completion.usage ?? {
|
|
625
697
|
inputTokens: estimateTokens(this.systemPrompt) + estimateTokens(JSON.stringify(this.messages)),
|
|
626
698
|
outputTokens: estimateTokens(completion.text) + (completion.toolCalls.length ? estimateTokens(JSON.stringify(completion.toolCalls)) : 0)
|
|
@@ -1200,7 +1272,7 @@ function createRuntime(opts) {
|
|
|
1200
1272
|
}
|
|
1201
1273
|
|
|
1202
1274
|
// src/version.ts
|
|
1203
|
-
var VERSION = true ? "0.4.0-beta.
|
|
1275
|
+
var VERSION = true ? "0.4.0-beta.3" : "0.0.0-dev";
|
|
1204
1276
|
|
|
1205
1277
|
// src/cli.ts
|
|
1206
1278
|
async function main() {
|