@botconnector/bccli 0.4.0-beta.5 → 0.4.0-beta.7
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 +7 -0
- package/dist/{chunk-GW36UMHZ.js → chunk-BRTSYM5O.js} +1 -1
- package/dist/{chunk-C5AFWX7H.js → chunk-FMM53YSU.js} +4 -0
- package/dist/{chunk-5O4HD7IU.js → chunk-KV27KTOX.js} +1 -0
- package/dist/cli.js +106 -21
- package/dist/{login-F4G5QXOU.js → login-4277DGKX.js} +1 -1
- package/dist/{providerCli-MXV6PD6F.js → providerCli-6ON7QEVN.js} +1 -1
- package/dist/{ui-RYTSKEIA.js → ui-4EBFPASA.js} +34 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -80,6 +80,13 @@ per provider; ketik untuk menyaring. Pilihan tersimpan sebagai default.
|
|
|
80
80
|
izin (`permissionMode`, `allow`) dan provider yang sudah ada hanya diatur dari `~/.bccli/config.json`,
|
|
81
81
|
supaya repo yang kamu clone tidak bisa memberi dirinya izin penuh atau mencuri API key.
|
|
82
82
|
|
|
83
|
+
## Internet
|
|
84
|
+
|
|
85
|
+
- `web_search`: mencari di web tanpa perlu izin. Memakai akun BotConnector Cloud
|
|
86
|
+
bila ada key, kalau tidak langsung ke Keenable (gratis, tanpa key). Hasilnya
|
|
87
|
+
judul, URL, dan cuplikan singkat, jadi hemat token.
|
|
88
|
+
- `fetch`: membuka satu URL dari komputer ini (butuh izin per host).
|
|
89
|
+
|
|
83
90
|
## MCP
|
|
84
91
|
|
|
85
92
|
`/mcp` (atau `bccli mcp add <nama>`) memasang server dari katalog:
|
|
@@ -35,7 +35,7 @@ function readSecret(prompt) {
|
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
async function runLogin(providerId, cwd) {
|
|
38
|
-
const { runProviderCommand } = await import("./providerCli-
|
|
38
|
+
const { runProviderCommand } = await import("./providerCli-6ON7QEVN.js");
|
|
39
39
|
const { parseCliArgs } = await import("./args-FCLPQ7TO.js");
|
|
40
40
|
return runProviderCommand(parseCliArgs(["provider", "add", providerId]), {
|
|
41
41
|
env: process.env,
|
|
@@ -191,6 +191,10 @@ async function readJson(res) {
|
|
|
191
191
|
function createProvider({ baseURL, apiKey, model, fetch: doFetch = fetch, retryDelayMs = 1e3 }) {
|
|
192
192
|
const headers = { "content-type": "application/json" };
|
|
193
193
|
if (apiKey) headers.authorization = `Bearer ${apiKey}`;
|
|
194
|
+
if (/^https:\/\/api\.botconnector\.id\/v1\/?$/.test(baseURL) && apiKey?.startsWith("bc_live_")) {
|
|
195
|
+
headers["x-botconnector-client"] = "bccli";
|
|
196
|
+
headers["x-botconnector-client-version"] = "0.4.0";
|
|
197
|
+
}
|
|
194
198
|
async function post(path, body, signal) {
|
|
195
199
|
let lastError;
|
|
196
200
|
for (let attempt = 0; attempt < 4; attempt++) {
|
package/dist/cli.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
addProviderKey,
|
|
8
8
|
createProvider,
|
|
9
9
|
listAllModels
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-FMM53YSU.js";
|
|
11
11
|
import {
|
|
12
12
|
runLogin
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-BRTSYM5O.js";
|
|
14
14
|
import {
|
|
15
15
|
BUILTIN_AGENTS,
|
|
16
16
|
buildSystemPrompt,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
loadSkills,
|
|
21
21
|
parseFrontmatter,
|
|
22
22
|
runPrint
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-KV27KTOX.js";
|
|
24
24
|
import {
|
|
25
25
|
Permissions
|
|
26
26
|
} from "./chunk-ELML4KVQ.js";
|
|
@@ -300,6 +300,20 @@ async function readCapped(res) {
|
|
|
300
300
|
function htmlToText(html) {
|
|
301
301
|
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
302
|
}
|
|
303
|
+
function describeFetchError(error) {
|
|
304
|
+
const cause = error.cause;
|
|
305
|
+
const code = cause?.code ?? "";
|
|
306
|
+
const detail = cause?.message ?? error.message;
|
|
307
|
+
if (error.name === "TimeoutError") return "tidak ada jawaban dalam 30 detik";
|
|
308
|
+
if (code === "ENOTFOUND" || code === "EAI_AGAIN") return `${detail} \u2014 DNS tidak menemukan host (salah ketik, offline, atau diblokir DNS/ISP)`;
|
|
309
|
+
if (/CERT|SELF_SIGNED|UNABLE_TO/.test(code)) {
|
|
310
|
+
return `${detail} \u2014 sertifikat TLS ditolak; sering karena antivirus/proxy yang memeriksa HTTPS. Coba jalankan dengan NODE_OPTIONS=--use-system-ca`;
|
|
311
|
+
}
|
|
312
|
+
if (/ECONNRESET|ECONNREFUSED|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH|UND_ERR_CONNECT_TIMEOUT|UND_ERR_SOCKET/.test(code)) {
|
|
313
|
+
return `${detail} \u2014 koneksi gagal (firewall, proxy, atau situs diblokir jaringan)`;
|
|
314
|
+
}
|
|
315
|
+
return code ? `${detail} (${code})` : detail;
|
|
316
|
+
}
|
|
303
317
|
var fetchTool = defineTool({
|
|
304
318
|
name: "fetch",
|
|
305
319
|
description: "Fetch a URL (http/https). HTML is converted to plain text. Max 50k characters.",
|
|
@@ -327,12 +341,12 @@ var fetchTool = defineTool({
|
|
|
327
341
|
url = next;
|
|
328
342
|
}
|
|
329
343
|
} catch (error) {
|
|
330
|
-
return { output: `Gagal mengambil ${input.url}: ${error
|
|
344
|
+
return { output: `Gagal mengambil ${input.url}: ${describeFetchError(error)}`, isError: true };
|
|
331
345
|
}
|
|
332
346
|
if (!res) return { output: `Gagal mengambil ${input.url}`, isError: true };
|
|
333
347
|
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
348
|
const text = (res.headers.get("content-type") ?? "").includes("html") ? htmlToText(body) : body;
|
|
349
|
+
if (!res.ok) return { output: `HTTP ${res.status} dari ${input.url}: ${text.slice(0, 500)}`, isError: true };
|
|
336
350
|
const clipped = text.length > MAX_CHARS || truncated ? `${text.slice(0, MAX_CHARS)}
|
|
337
351
|
\u2026 [dipotong]` : text;
|
|
338
352
|
const display = truncated ? "lebih dari 5 MB, dipotong" : `${text.length} karakter`;
|
|
@@ -892,8 +906,8 @@ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"
|
|
|
892
906
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
893
907
|
import { z as z9 } from "zod";
|
|
894
908
|
function mcpToolName(server, tool, taken) {
|
|
895
|
-
const
|
|
896
|
-
const base = `mcp__${
|
|
909
|
+
const clean2 = (s) => s.replace(/[^A-Za-z0-9_-]+/g, "_");
|
|
910
|
+
const base = `mcp__${clean2(server)}__${clean2(tool)}`.slice(0, 64);
|
|
897
911
|
let name = base;
|
|
898
912
|
for (let n = 2; taken.has(name); n++) name = `${base.slice(0, 64 - String(n).length - 1)}_${n}`;
|
|
899
913
|
taken.add(name);
|
|
@@ -1038,8 +1052,69 @@ ${body}`, display: skill.description.slice(0, 60) };
|
|
|
1038
1052
|
});
|
|
1039
1053
|
}
|
|
1040
1054
|
|
|
1041
|
-
// src/tools/
|
|
1055
|
+
// src/tools/websearch.ts
|
|
1042
1056
|
import { z as z12 } from "zod";
|
|
1057
|
+
var clean = (items, max) => (Array.isArray(items) ? items : []).filter((r) => typeof r?.url === "string" && /^https?:\/\//.test(r.url)).slice(0, max).map((r) => ({
|
|
1058
|
+
title: String(r.title || r.url).slice(0, 200),
|
|
1059
|
+
url: r.url,
|
|
1060
|
+
snippet: String(r.snippet || r.description || "").replace(/\s+/g, " ").trim().slice(0, 600)
|
|
1061
|
+
}));
|
|
1062
|
+
async function postJson(url, body, headers, signal) {
|
|
1063
|
+
const res = await fetch(url, {
|
|
1064
|
+
method: "POST",
|
|
1065
|
+
headers: { "content-type": "application/json", ...headers },
|
|
1066
|
+
body: JSON.stringify(body),
|
|
1067
|
+
signal: AbortSignal.any([signal, AbortSignal.timeout(3e4)])
|
|
1068
|
+
});
|
|
1069
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1070
|
+
return res.json();
|
|
1071
|
+
}
|
|
1072
|
+
function createWebSearchTool(opts) {
|
|
1073
|
+
const keenableURL = opts.keenableURL ?? "https://api.keenable.ai/v1/search/public";
|
|
1074
|
+
return defineTool({
|
|
1075
|
+
name: "web_search",
|
|
1076
|
+
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.",
|
|
1077
|
+
schema: z12.object({
|
|
1078
|
+
query: z12.string().min(1).max(500).describe("Search query"),
|
|
1079
|
+
max_results: z12.number().int().min(1).max(10).optional().describe("Number of results (default 6)")
|
|
1080
|
+
}),
|
|
1081
|
+
kind: "read",
|
|
1082
|
+
target: (input) => input.query,
|
|
1083
|
+
parallelSafe: () => true,
|
|
1084
|
+
async run(input, ctx) {
|
|
1085
|
+
const max = input.max_results ?? 6;
|
|
1086
|
+
const errors = [];
|
|
1087
|
+
let results = [];
|
|
1088
|
+
const bc = opts.botconnector();
|
|
1089
|
+
if (bc) {
|
|
1090
|
+
try {
|
|
1091
|
+
const data = await postJson(`${bc.baseURL.replace(/\/+$/, "")}/web/search`, { query: input.query, max_results: max }, { authorization: `Bearer ${bc.apiKey}` }, ctx.signal);
|
|
1092
|
+
results = clean(data.results, max);
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
errors.push(`BotConnector: ${error.message}`);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
if (!results.length) {
|
|
1098
|
+
try {
|
|
1099
|
+
const data = await postJson(keenableURL, { query: input.query }, { "x-keenable-title": "BotConnector" }, ctx.signal);
|
|
1100
|
+
results = clean(data.results, max);
|
|
1101
|
+
} catch (error) {
|
|
1102
|
+
errors.push(`Keenable: ${error.message}`);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (!results.length) {
|
|
1106
|
+
return { output: errors.length ? `Web search gagal (${errors.join("; ")}).` : "Tidak ada hasil.", isError: errors.length > 0 };
|
|
1107
|
+
}
|
|
1108
|
+
const output = results.map((r, i) => `${i + 1}. ${r.title}
|
|
1109
|
+
${r.url}${r.snippet ? `
|
|
1110
|
+
${r.snippet}` : ""}`).join("\n");
|
|
1111
|
+
return { output, display: `${results.length} hasil` };
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// src/tools/task.ts
|
|
1117
|
+
import { z as z13 } from "zod";
|
|
1043
1118
|
function createTaskTool(opts) {
|
|
1044
1119
|
const byName = new Map(opts.agents.map((a) => [a.name, a]));
|
|
1045
1120
|
const list = opts.agents.map((a) => `- ${a.name}: ${a.description}`).join("\n");
|
|
@@ -1047,10 +1122,10 @@ function createTaskTool(opts) {
|
|
|
1047
1122
|
name: "task",
|
|
1048
1123
|
description: `Delegate a self-contained sub-task to a subagent. It starts with an empty context and returns only its final report. Available agents:
|
|
1049
1124
|
${list}`,
|
|
1050
|
-
schema:
|
|
1051
|
-
agent:
|
|
1052
|
-
description:
|
|
1053
|
-
prompt:
|
|
1125
|
+
schema: z13.object({
|
|
1126
|
+
agent: z13.string().describe("Agent name"),
|
|
1127
|
+
description: z13.string().describe("3-6 word summary shown to the user"),
|
|
1128
|
+
prompt: z13.string().describe("Full instructions; the subagent sees nothing else")
|
|
1054
1129
|
}),
|
|
1055
1130
|
kind: "read",
|
|
1056
1131
|
target: (input) => `[${input.agent}] ${input.description}`,
|
|
@@ -1114,7 +1189,7 @@ ${def.prompt}`,
|
|
|
1114
1189
|
}
|
|
1115
1190
|
|
|
1116
1191
|
// src/tools/todo.ts
|
|
1117
|
-
import { z as
|
|
1192
|
+
import { z as z14 } from "zod";
|
|
1118
1193
|
var TodoStore = class {
|
|
1119
1194
|
items = [];
|
|
1120
1195
|
listeners = /* @__PURE__ */ new Set();
|
|
@@ -1131,8 +1206,8 @@ function createTodoTool(store) {
|
|
|
1131
1206
|
return defineTool({
|
|
1132
1207
|
name: "todo_write",
|
|
1133
1208
|
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.",
|
|
1134
|
-
schema:
|
|
1135
|
-
todos:
|
|
1209
|
+
schema: z14.object({
|
|
1210
|
+
todos: z14.array(z14.object({ content: z14.string(), status: z14.enum(["pending", "in_progress", "completed"]) }))
|
|
1136
1211
|
}),
|
|
1137
1212
|
kind: "read",
|
|
1138
1213
|
target: (input) => `${input.todos.length} item`,
|
|
@@ -1180,7 +1255,17 @@ function createRuntime(opts) {
|
|
|
1180
1255
|
}
|
|
1181
1256
|
}
|
|
1182
1257
|
const systemPrompt = buildSystemPrompt({ cwd: opts.cwd, home, model: modelRef, skills });
|
|
1183
|
-
const
|
|
1258
|
+
const webSearch = createWebSearchTool({
|
|
1259
|
+
botconnector: () => {
|
|
1260
|
+
try {
|
|
1261
|
+
const bc = resolveModel(config, "bc-cloud/search", env);
|
|
1262
|
+
return bc.apiKey ? { baseURL: bc.baseURL, apiKey: bc.apiKey } : void 0;
|
|
1263
|
+
} catch {
|
|
1264
|
+
return void 0;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1268
|
+
const baseTools = [...ALL_TOOLS, webSearch, createSkillTool(skills), createTodoTool(todos), createExitPlanTool({ permissions, interaction })];
|
|
1184
1269
|
const task = createTaskTool({
|
|
1185
1270
|
agents: [...BUILTIN_AGENTS, ...agentDefs],
|
|
1186
1271
|
// Subagents get whatever the main agent has right now (incl. MCP tools), minus task itself.
|
|
@@ -1273,7 +1358,7 @@ function createRuntime(opts) {
|
|
|
1273
1358
|
}
|
|
1274
1359
|
|
|
1275
1360
|
// src/version.ts
|
|
1276
|
-
var VERSION = true ? "0.4.0-beta.
|
|
1361
|
+
var VERSION = true ? "0.4.0-beta.7" : "0.0.0-dev";
|
|
1277
1362
|
|
|
1278
1363
|
// src/cli.ts
|
|
1279
1364
|
async function main() {
|
|
@@ -1290,12 +1375,12 @@ async function main() {
|
|
|
1290
1375
|
if (args.command === "login") return runLogin(args.loginProvider ?? "bc-cloud", cwd);
|
|
1291
1376
|
if (args.command === "mcp") {
|
|
1292
1377
|
const { runMcpCommand } = await import("./mcpCli-Q2H63ISP.js");
|
|
1293
|
-
const { readSecret } = await import("./login-
|
|
1378
|
+
const { readSecret } = await import("./login-4277DGKX.js");
|
|
1294
1379
|
return runMcpCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1295
1380
|
}
|
|
1296
1381
|
if (args.command === "provider") {
|
|
1297
|
-
const { runProviderCommand } = await import("./providerCli-
|
|
1298
|
-
const { readSecret } = await import("./login-
|
|
1382
|
+
const { runProviderCommand } = await import("./providerCli-6ON7QEVN.js");
|
|
1383
|
+
const { readSecret } = await import("./login-4277DGKX.js");
|
|
1299
1384
|
return runProviderCommand(args, { env: process.env, cwd, out: (s) => console.log(s), err: (s) => console.error(s), readSecret });
|
|
1300
1385
|
}
|
|
1301
1386
|
if (args.command === "models") {
|
|
@@ -1325,7 +1410,7 @@ async function main() {
|
|
|
1325
1410
|
}
|
|
1326
1411
|
}
|
|
1327
1412
|
if (!process.stdin.isTTY) throw new ConfigError('Mode interaktif butuh terminal. Untuk skrip/CI pakai: bccli -p "tugas"');
|
|
1328
|
-
const { startInteractive } = await import("./ui-
|
|
1413
|
+
const { startInteractive } = await import("./ui-4EBFPASA.js");
|
|
1329
1414
|
return startInteractive(rt, { initialPrompt: args.prompt, resume: args.resume, version: VERSION });
|
|
1330
1415
|
}
|
|
1331
1416
|
main().then(
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
instructionPaths,
|
|
6
6
|
parseFrontmatter,
|
|
7
7
|
toolLabel
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KV27KTOX.js";
|
|
9
9
|
import {
|
|
10
10
|
nextMode
|
|
11
11
|
} from "./chunk-ELML4KVQ.js";
|
|
@@ -628,15 +628,40 @@ var NOTICES = {
|
|
|
628
628
|
stepLimit: ['Batas 50 langkah tercapai. Ketik "lanjut" untuk meneruskan.', "warn"],
|
|
629
629
|
aborted: ["Dibatalkan.", "warn"]
|
|
630
630
|
};
|
|
631
|
+
var isEmptyCont = (e) => e.kind === "assistant" && e.cont && !e.text;
|
|
631
632
|
function endTurn(t) {
|
|
632
|
-
return { done: [...t.done, ...t.live], live: [] };
|
|
633
|
+
return { done: [...t.done, ...t.live.filter((e) => !isEmptyCont(e))], live: [] };
|
|
634
|
+
}
|
|
635
|
+
var TOOL_MARKUP = /<\/?tool_call>|<\/?arg_(?:key|value)>|Tool call list|^\s*\d+\.\s*Tool:|`\s*=\s*`/;
|
|
636
|
+
function finishedCut(text) {
|
|
637
|
+
let inFence = false;
|
|
638
|
+
let pos = 0;
|
|
639
|
+
let cut = -1;
|
|
640
|
+
const lines = text.split("\n");
|
|
641
|
+
for (const line of lines.slice(0, -1)) {
|
|
642
|
+
if (TOOL_MARKUP.test(line)) break;
|
|
643
|
+
if (line.trimStart().startsWith("```")) inFence = !inFence;
|
|
644
|
+
pos += line.length + 1;
|
|
645
|
+
if (!inFence) cut = pos - 1;
|
|
646
|
+
}
|
|
647
|
+
return cut;
|
|
648
|
+
}
|
|
649
|
+
function flushLines(t) {
|
|
650
|
+
const last = t.live.at(-1);
|
|
651
|
+
if (last?.kind !== "assistant") return t;
|
|
652
|
+
const cut = finishedCut(last.text);
|
|
653
|
+
if (cut < 0) return t;
|
|
654
|
+
const chunk = last.text.slice(0, cut);
|
|
655
|
+
if (!last.cont && !chunk.trim()) return t;
|
|
656
|
+
const rest = entry({ kind: "assistant", text: last.text.slice(cut + 1), cont: true, flushed: (last.flushed ?? 0) + cut + 1 });
|
|
657
|
+
return { done: [...t.done, ...t.live.slice(0, -1).filter((e) => !isEmptyCont(e)), { ...last, text: chunk || " " }], live: [rest] };
|
|
633
658
|
}
|
|
634
659
|
function applyEvent(t, event) {
|
|
635
660
|
switch (event.type) {
|
|
636
661
|
case "text": {
|
|
637
662
|
const last = t.live.at(-1);
|
|
638
|
-
if (last?.kind === "assistant") return { ...t, live: [...t.live.slice(0, -1), { ...last, text: last.text + event.delta }] };
|
|
639
|
-
return { ...t, live: [...t.live, entry({ kind: "assistant", text: event.delta })] };
|
|
663
|
+
if (last?.kind === "assistant") return flushLines({ ...t, live: [...t.live.slice(0, -1), { ...last, text: last.text + event.delta }] });
|
|
664
|
+
return flushLines({ ...t, live: [...t.live, entry({ kind: "assistant", text: event.delta })] });
|
|
640
665
|
}
|
|
641
666
|
case "thinking": {
|
|
642
667
|
const last = t.live.at(-1);
|
|
@@ -646,12 +671,12 @@ function applyEvent(t, event) {
|
|
|
646
671
|
case "textReplace": {
|
|
647
672
|
const last = t.live.at(-1);
|
|
648
673
|
if (last?.kind !== "assistant") return t;
|
|
649
|
-
return { ...t, live: [...t.live.slice(0, -1), { ...last, text: event.text }] };
|
|
674
|
+
return { ...t, live: [...t.live.slice(0, -1), { ...last, text: event.text.slice(last.flushed ?? 0) }] };
|
|
650
675
|
}
|
|
651
676
|
case "toolStart": {
|
|
652
677
|
const running = t.live.some((e) => e.kind === "tool" && !e.done);
|
|
653
678
|
const tool = entry({ kind: "tool", callId: event.id, tool: event.tool, target: event.target, done: false });
|
|
654
|
-
return running ? { ...t, live: [...t.live, tool] } : { done: [...t.done, ...t.live], live: [tool] };
|
|
679
|
+
return running ? { ...t, live: [...t.live, tool] } : { done: [...t.done, ...t.live.filter((e) => !isEmptyCont(e))], live: [tool] };
|
|
655
680
|
}
|
|
656
681
|
case "toolEnd": {
|
|
657
682
|
const live = t.live.map(
|
|
@@ -1226,6 +1251,9 @@ ${t.output}`);
|
|
|
1226
1251
|
case "user":
|
|
1227
1252
|
return /* @__PURE__ */ jsx15(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: `> ${e.text}` }) }, e.id);
|
|
1228
1253
|
case "assistant":
|
|
1254
|
+
if (e.cont) {
|
|
1255
|
+
return e.text ? /* @__PURE__ */ jsx15(Box13, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Markdown, { text: e.text }) }, e.id) : null;
|
|
1256
|
+
}
|
|
1229
1257
|
if (!e.text.trim()) return null;
|
|
1230
1258
|
return /* @__PURE__ */ jsxs10(Box13, { marginTop: 1, children: [
|
|
1231
1259
|
/* @__PURE__ */ jsx15(Text15, { color: color(ACCENT), children: "\u25CF " }),
|