@burtson-labs/bandit-engine 2.0.59 → 2.0.60
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/chat-NLBCURUN.mjs +16 -0
- package/dist/chat-provider.js.map +1 -1
- package/dist/chat-provider.mjs +5 -5
- package/dist/{chunk-URKUD3OL.mjs → chunk-3AWAL2YH.mjs} +9 -9
- package/dist/{chunk-KNBWR4DS.mjs → chunk-5WQMMCZQ.mjs} +3 -3
- package/dist/{chunk-QPBG6JQE.mjs → chunk-6QTTNYF2.mjs} +2 -2
- package/dist/{chunk-POTQI33D.mjs → chunk-D55E6ZDV.mjs} +5 -5
- package/dist/{chunk-557E5VZ2.mjs → chunk-EUBVBTB3.mjs} +2 -2
- package/dist/{chunk-7ZDS33S2.mjs → chunk-IPMTNREZ.mjs} +2 -2
- package/dist/{chunk-7ZDS33S2.mjs.map → chunk-IPMTNREZ.mjs.map} +1 -1
- package/dist/{chunk-V5QRXIIO.mjs → chunk-MFDMM5MS.mjs} +357 -19
- package/dist/chunk-MFDMM5MS.mjs.map +1 -0
- package/dist/{chunk-WL7NV4WJ.mjs → chunk-PY7A3J5T.mjs} +4 -4
- package/dist/{chunk-KM7FUWCM.mjs → chunk-SRCCNBHF.mjs} +7 -3
- package/dist/chunk-SRCCNBHF.mjs.map +1 -0
- package/dist/{chunk-UFSEYVRS.mjs → chunk-VTC6AIWY.mjs} +3 -3
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +374 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +10 -10
- package/dist/management/management.js +374 -14
- package/dist/management/management.js.map +1 -1
- package/dist/management/management.mjs +8 -8
- package/dist/modals/chat-modal/chat-modal.js.map +1 -1
- package/dist/modals/chat-modal/chat-modal.mjs +4 -4
- package/dist/{modelStore-XWFHNTBT.mjs → modelStore-FBPBG7TI.mjs} +2 -2
- package/dist/{public-BzsEWB08.d.mts → public-nrOOzXCZ.d.mts} +10 -0
- package/dist/{public-BzsEWB08.d.ts → public-nrOOzXCZ.d.ts} +10 -0
- package/dist/public-types.d.mts +1 -1
- package/dist/public-types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chat-3J4GDGWW.mjs +0 -16
- package/dist/chunk-KM7FUWCM.mjs.map +0 -1
- package/dist/chunk-V5QRXIIO.mjs.map +0 -1
- /package/dist/{chat-3J4GDGWW.mjs.map → chat-NLBCURUN.mjs.map} +0 -0
- /package/dist/{chunk-URKUD3OL.mjs.map → chunk-3AWAL2YH.mjs.map} +0 -0
- /package/dist/{chunk-KNBWR4DS.mjs.map → chunk-5WQMMCZQ.mjs.map} +0 -0
- /package/dist/{chunk-QPBG6JQE.mjs.map → chunk-6QTTNYF2.mjs.map} +0 -0
- /package/dist/{chunk-POTQI33D.mjs.map → chunk-D55E6ZDV.mjs.map} +0 -0
- /package/dist/{chunk-557E5VZ2.mjs.map → chunk-EUBVBTB3.mjs.map} +0 -0
- /package/dist/{chunk-WL7NV4WJ.mjs.map → chunk-PY7A3J5T.mjs.map} +0 -0
- /package/dist/{chunk-UFSEYVRS.mjs.map → chunk-VTC6AIWY.mjs.map} +0 -0
- /package/dist/{modelStore-XWFHNTBT.mjs.map → modelStore-FBPBG7TI.mjs.map} +0 -0
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
} from "./chunk-ONQMRE2G.mjs";
|
|
4
4
|
import {
|
|
5
5
|
StreamingMarkdown_default
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-SRCCNBHF.mjs";
|
|
7
7
|
import {
|
|
8
8
|
useMCPToolsStore
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6QTTNYF2.mjs";
|
|
10
10
|
import {
|
|
11
11
|
AddIcon,
|
|
12
12
|
ArrowDownwardIcon,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
useNotificationService,
|
|
43
43
|
useTTS,
|
|
44
44
|
useVoiceStore
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-5WQMMCZQ.mjs";
|
|
46
46
|
import {
|
|
47
47
|
authenticationService,
|
|
48
48
|
brandingService_default,
|
|
@@ -67,13 +67,13 @@ import {
|
|
|
67
67
|
useMemoryStore,
|
|
68
68
|
useProjectStore,
|
|
69
69
|
useVectorStore
|
|
70
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-EUBVBTB3.mjs";
|
|
71
71
|
import {
|
|
72
72
|
indexedDBService_default,
|
|
73
73
|
useModelStore,
|
|
74
74
|
usePackageSettingsStore,
|
|
75
75
|
usePreferencesStore
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-IPMTNREZ.mjs";
|
|
77
77
|
import {
|
|
78
78
|
useAIProviderStore
|
|
79
79
|
} from "./chunk-H3BYFEIE.mjs";
|
|
@@ -1388,6 +1388,313 @@ var chat_input_default = ChatInput;
|
|
|
1388
1388
|
// src/chat/hooks/useAIProvider.tsx
|
|
1389
1389
|
import { useCallback, useRef as useRef3 } from "react";
|
|
1390
1390
|
|
|
1391
|
+
// src/services/telemetry/otlpExporter.ts
|
|
1392
|
+
function redactSecretsString(s) {
|
|
1393
|
+
return s.replace(/\b(?:sk|tvly|ghp|gho|pk|rk)[-_][A-Za-z0-9]{8,}\b/gi, "[redacted]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[redacted-jwt]").replace(/\bBearer\s+[A-Za-z0-9._-]{8,}/gi, "Bearer [redacted]");
|
|
1394
|
+
}
|
|
1395
|
+
function resolveTelemetryConfig(opts) {
|
|
1396
|
+
if (!opts.telemetry?.enabled) return null;
|
|
1397
|
+
const endpoint = (opts.telemetry.endpoint ?? "https://otlp.burtson.ai").replace(/\/+$/, "");
|
|
1398
|
+
const headers = { ...opts.telemetry.headers ?? {} };
|
|
1399
|
+
const hasAuth = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
|
|
1400
|
+
if (!hasAuth && opts.banditApiKey) {
|
|
1401
|
+
headers["Authorization"] = `Bearer ${opts.banditApiKey}`;
|
|
1402
|
+
}
|
|
1403
|
+
const mode = opts.telemetry.mode ?? "metrics+traces";
|
|
1404
|
+
return { endpoint, headers, mode, serviceName: opts.telemetry.serviceName ?? "bandit-web" };
|
|
1405
|
+
}
|
|
1406
|
+
function toAttrs(rec) {
|
|
1407
|
+
const out = [];
|
|
1408
|
+
for (const [key, v] of Object.entries(rec)) {
|
|
1409
|
+
if (v === void 0 || v === null || v === "") continue;
|
|
1410
|
+
if (typeof v === "boolean") out.push({ key, value: { boolValue: v } });
|
|
1411
|
+
else if (typeof v === "number")
|
|
1412
|
+
out.push({ key, value: Number.isInteger(v) ? { intValue: String(v) } : { doubleValue: v } });
|
|
1413
|
+
else out.push({ key, value: { stringValue: v } });
|
|
1414
|
+
}
|
|
1415
|
+
return out;
|
|
1416
|
+
}
|
|
1417
|
+
var webCrypto = globalThis.crypto;
|
|
1418
|
+
function hex(bytes) {
|
|
1419
|
+
const arr = new Uint8Array(bytes);
|
|
1420
|
+
if (webCrypto?.getRandomValues) webCrypto.getRandomValues(arr);
|
|
1421
|
+
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
1422
|
+
}
|
|
1423
|
+
var nano = (ms) => String(Math.round(ms * 1e6));
|
|
1424
|
+
var TTFT_BUCKETS = [0.1, 0.25, 0.5, 1, 2, 5, 10, 30];
|
|
1425
|
+
var DURATION_BUCKETS = [0.5, 1, 2, 5, 10, 30, 60, 120, 300];
|
|
1426
|
+
function histogramPoint(value, bounds, attrs, startMs, endMs) {
|
|
1427
|
+
const counts = new Array(bounds.length + 1).fill(0);
|
|
1428
|
+
let idx = bounds.findIndex((b) => value <= b);
|
|
1429
|
+
if (idx === -1) idx = bounds.length;
|
|
1430
|
+
counts[idx] = 1;
|
|
1431
|
+
return {
|
|
1432
|
+
attributes: toAttrs(attrs),
|
|
1433
|
+
startTimeUnixNano: nano(startMs),
|
|
1434
|
+
timeUnixNano: nano(endMs),
|
|
1435
|
+
count: "1",
|
|
1436
|
+
sum: value,
|
|
1437
|
+
bucketCounts: counts.map(String),
|
|
1438
|
+
explicitBounds: bounds
|
|
1439
|
+
};
|
|
1440
|
+
}
|
|
1441
|
+
function sumPoint(value, attrs, startMs, endMs) {
|
|
1442
|
+
return {
|
|
1443
|
+
attributes: toAttrs(attrs),
|
|
1444
|
+
startTimeUnixNano: nano(startMs),
|
|
1445
|
+
timeUnixNano: nano(endMs),
|
|
1446
|
+
asInt: String(Math.round(value))
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
var clip = (s, n = 120) => redactSecretsString(s.slice(0, n)).slice(0, n);
|
|
1450
|
+
var TelemetryExporter = class {
|
|
1451
|
+
cfg;
|
|
1452
|
+
now;
|
|
1453
|
+
traceId = "";
|
|
1454
|
+
turn = null;
|
|
1455
|
+
llm = null;
|
|
1456
|
+
llmFirstChunkMs = 0;
|
|
1457
|
+
openTools = [];
|
|
1458
|
+
completedSpans = [];
|
|
1459
|
+
model = "";
|
|
1460
|
+
turnChunkChars = 0;
|
|
1461
|
+
turnTokens = 0;
|
|
1462
|
+
ttftSeconds = null;
|
|
1463
|
+
constructor(cfg, opts) {
|
|
1464
|
+
this.cfg = cfg;
|
|
1465
|
+
this.now = opts?.now ?? (() => Date.now());
|
|
1466
|
+
}
|
|
1467
|
+
startTurn(goal, model) {
|
|
1468
|
+
this.traceId = hex(16);
|
|
1469
|
+
this.model = model;
|
|
1470
|
+
this.turnChunkChars = 0;
|
|
1471
|
+
this.turnTokens = 0;
|
|
1472
|
+
this.ttftSeconds = null;
|
|
1473
|
+
this.llm = null;
|
|
1474
|
+
this.llmFirstChunkMs = 0;
|
|
1475
|
+
this.openTools = [];
|
|
1476
|
+
this.completedSpans = [];
|
|
1477
|
+
this.turn = {
|
|
1478
|
+
spanId: hex(8),
|
|
1479
|
+
name: "agent.turn",
|
|
1480
|
+
startMs: this.now(),
|
|
1481
|
+
attrs: { "gen_ai.request.model": model, "bandit.turn.goal": clip(goal, 160) }
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
/** Fed from the chat turn lifecycle. Best-effort; swallows bad payloads. */
|
|
1485
|
+
onEvent(type, payload) {
|
|
1486
|
+
if (!this.turn) return;
|
|
1487
|
+
try {
|
|
1488
|
+
const p = payload ?? {};
|
|
1489
|
+
switch (type) {
|
|
1490
|
+
case "tool_loop:llm_start":
|
|
1491
|
+
this.llm = {
|
|
1492
|
+
spanId: hex(8),
|
|
1493
|
+
parentSpanId: this.turn.spanId,
|
|
1494
|
+
name: "llm.generate",
|
|
1495
|
+
startMs: this.now(),
|
|
1496
|
+
attrs: { "gen_ai.request.model": this.model }
|
|
1497
|
+
};
|
|
1498
|
+
this.llmFirstChunkMs = 0;
|
|
1499
|
+
break;
|
|
1500
|
+
case "tool_loop:llm_chunk": {
|
|
1501
|
+
const chunk = typeof p.chunk === "string" ? p.chunk : "";
|
|
1502
|
+
if (this.llm && this.llmFirstChunkMs === 0 && chunk.length > 0) {
|
|
1503
|
+
this.llmFirstChunkMs = this.now();
|
|
1504
|
+
const ttft = (this.llmFirstChunkMs - this.llm.startMs) / 1e3;
|
|
1505
|
+
if (this.ttftSeconds === null) this.ttftSeconds = ttft;
|
|
1506
|
+
this.llm.attrs["bandit.llm.ttft_seconds"] = ttft;
|
|
1507
|
+
}
|
|
1508
|
+
this.turnChunkChars += chunk.length;
|
|
1509
|
+
this.turnTokens = Math.floor(this.turnChunkChars / 4);
|
|
1510
|
+
break;
|
|
1511
|
+
}
|
|
1512
|
+
case "tool_loop:llm_response":
|
|
1513
|
+
if (this.llm) {
|
|
1514
|
+
this.llm.endMs = this.now();
|
|
1515
|
+
if (typeof p.responseLength === "number") this.llm.attrs["bandit.llm.response_chars"] = p.responseLength;
|
|
1516
|
+
this.completedSpans.push(this.llm);
|
|
1517
|
+
this.llm = null;
|
|
1518
|
+
}
|
|
1519
|
+
break;
|
|
1520
|
+
case "tool_loop:tool_execute": {
|
|
1521
|
+
const name = typeof p.name === "string" ? p.name : "tool";
|
|
1522
|
+
const params = p.params ?? {};
|
|
1523
|
+
const primary = params.query ?? params.url ?? params.prompt ?? params.topic ?? "";
|
|
1524
|
+
this.openTools.push({
|
|
1525
|
+
spanId: hex(8),
|
|
1526
|
+
parentSpanId: this.turn.spanId,
|
|
1527
|
+
name: `tool.${name}`,
|
|
1528
|
+
startMs: this.now(),
|
|
1529
|
+
attrs: { "bandit.tool.name": name, "bandit.tool.primary": primary ? clip(primary) : void 0 }
|
|
1530
|
+
});
|
|
1531
|
+
break;
|
|
1532
|
+
}
|
|
1533
|
+
case "tool_loop:tool_result":
|
|
1534
|
+
case "tool_loop:tool_error": {
|
|
1535
|
+
const name = typeof p.name === "string" ? p.name : void 0;
|
|
1536
|
+
const span = this.takeOpenTool(name);
|
|
1537
|
+
if (span) {
|
|
1538
|
+
span.endMs = this.now();
|
|
1539
|
+
if (type === "tool_loop:tool_error" || p.isError === true) span.error = "tool error";
|
|
1540
|
+
this.completedSpans.push(span);
|
|
1541
|
+
}
|
|
1542
|
+
break;
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
} catch {
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
takeOpenTool(name) {
|
|
1549
|
+
if (name) {
|
|
1550
|
+
for (let i = this.openTools.length - 1; i >= 0; i -= 1) {
|
|
1551
|
+
if (this.openTools[i].name === `tool.${name}`) return this.openTools.splice(i, 1)[0];
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
return this.openTools.shift();
|
|
1555
|
+
}
|
|
1556
|
+
/** Close the turn, build OTLP traces + metrics, and flush. Never rejects. */
|
|
1557
|
+
async endTurn(outcome) {
|
|
1558
|
+
const turn = this.turn;
|
|
1559
|
+
if (!turn) return;
|
|
1560
|
+
this.turn = null;
|
|
1561
|
+
const end = this.now();
|
|
1562
|
+
if (this.llm && !this.llm.endMs) {
|
|
1563
|
+
this.llm.endMs = end;
|
|
1564
|
+
this.completedSpans.push(this.llm);
|
|
1565
|
+
this.llm = null;
|
|
1566
|
+
}
|
|
1567
|
+
for (const t of this.openTools.splice(0)) {
|
|
1568
|
+
t.endMs = end;
|
|
1569
|
+
t.error = t.error ?? "incomplete";
|
|
1570
|
+
this.completedSpans.push(t);
|
|
1571
|
+
}
|
|
1572
|
+
turn.endMs = end;
|
|
1573
|
+
if (outcome?.error) turn.error = outcome.error;
|
|
1574
|
+
const traceId = this.traceId;
|
|
1575
|
+
const spans = [turn, ...this.completedSpans];
|
|
1576
|
+
const jobs = [];
|
|
1577
|
+
if (this.cfg.mode === "metrics+traces") jobs.push(this.post("/v1/traces", this.buildTraces(traceId, spans)));
|
|
1578
|
+
jobs.push(this.post("/v1/metrics", this.buildMetrics(turn)));
|
|
1579
|
+
try {
|
|
1580
|
+
await Promise.all(jobs);
|
|
1581
|
+
} catch {
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
buildTraces(traceId, spans) {
|
|
1585
|
+
return {
|
|
1586
|
+
resourceSpans: [
|
|
1587
|
+
{
|
|
1588
|
+
resource: { attributes: toAttrs({ "service.name": this.cfg.serviceName }) },
|
|
1589
|
+
scopeSpans: [
|
|
1590
|
+
{
|
|
1591
|
+
scope: { name: this.cfg.serviceName },
|
|
1592
|
+
spans: spans.map((s) => ({
|
|
1593
|
+
traceId,
|
|
1594
|
+
spanId: s.spanId,
|
|
1595
|
+
parentSpanId: s.parentSpanId,
|
|
1596
|
+
name: s.name,
|
|
1597
|
+
kind: 1,
|
|
1598
|
+
startTimeUnixNano: nano(s.startMs),
|
|
1599
|
+
endTimeUnixNano: nano(s.endMs ?? s.startMs),
|
|
1600
|
+
attributes: toAttrs(s.attrs),
|
|
1601
|
+
status: s.error ? { code: 2, message: s.error.slice(0, 200) } : { code: 1 }
|
|
1602
|
+
}))
|
|
1603
|
+
}
|
|
1604
|
+
]
|
|
1605
|
+
}
|
|
1606
|
+
]
|
|
1607
|
+
};
|
|
1608
|
+
}
|
|
1609
|
+
buildMetrics(turn) {
|
|
1610
|
+
const start = turn.startMs;
|
|
1611
|
+
const end = turn.endMs ?? this.now();
|
|
1612
|
+
const metrics = [];
|
|
1613
|
+
if (this.turnTokens > 0) {
|
|
1614
|
+
metrics.push({
|
|
1615
|
+
name: "bandit.llm.tokens",
|
|
1616
|
+
sum: {
|
|
1617
|
+
aggregationTemporality: 1,
|
|
1618
|
+
isMonotonic: true,
|
|
1619
|
+
dataPoints: [sumPoint(this.turnTokens, { type: "output", "gen_ai.request.model": this.model }, start, end)]
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
if (this.ttftSeconds !== null) {
|
|
1624
|
+
metrics.push({
|
|
1625
|
+
name: "bandit.llm.ttft",
|
|
1626
|
+
unit: "s",
|
|
1627
|
+
histogram: {
|
|
1628
|
+
aggregationTemporality: 1,
|
|
1629
|
+
dataPoints: [histogramPoint(this.ttftSeconds, TTFT_BUCKETS, { "gen_ai.request.model": this.model }, start, end)]
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
metrics.push({
|
|
1634
|
+
name: "bandit.turn.duration",
|
|
1635
|
+
unit: "s",
|
|
1636
|
+
histogram: {
|
|
1637
|
+
aggregationTemporality: 1,
|
|
1638
|
+
dataPoints: [histogramPoint((end - start) / 1e3, DURATION_BUCKETS, { "gen_ai.request.model": this.model }, start, end)]
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
return {
|
|
1642
|
+
resourceMetrics: [
|
|
1643
|
+
{
|
|
1644
|
+
resource: { attributes: toAttrs({ "service.name": this.cfg.serviceName }) },
|
|
1645
|
+
scopeMetrics: [{ scope: { name: this.cfg.serviceName }, metrics }]
|
|
1646
|
+
}
|
|
1647
|
+
]
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1650
|
+
async post(path, body) {
|
|
1651
|
+
const doFetch = globalThis.fetch;
|
|
1652
|
+
if (!doFetch) return;
|
|
1653
|
+
const ctrl = new AbortController();
|
|
1654
|
+
const timer = setTimeout(() => ctrl.abort(), 4e3);
|
|
1655
|
+
try {
|
|
1656
|
+
await doFetch(`${this.cfg.endpoint}${path}`, {
|
|
1657
|
+
method: "POST",
|
|
1658
|
+
headers: { "Content-Type": "application/json", ...this.cfg.headers },
|
|
1659
|
+
body: JSON.stringify(body),
|
|
1660
|
+
signal: ctrl.signal
|
|
1661
|
+
});
|
|
1662
|
+
} catch (e) {
|
|
1663
|
+
debugLogger.debug("[telemetry] OTLP post failed", {
|
|
1664
|
+
path,
|
|
1665
|
+
error: e instanceof Error ? e.message : String(e)
|
|
1666
|
+
});
|
|
1667
|
+
} finally {
|
|
1668
|
+
clearTimeout(timer);
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
|
|
1673
|
+
// src/services/telemetry/index.ts
|
|
1674
|
+
var active = null;
|
|
1675
|
+
function syncTelemetry() {
|
|
1676
|
+
try {
|
|
1677
|
+
const settings = usePackageSettingsStore.getState().settings;
|
|
1678
|
+
const cfg = resolveTelemetryConfig({
|
|
1679
|
+
telemetry: settings?.telemetry,
|
|
1680
|
+
banditApiKey: authenticationService.getToken() ?? void 0
|
|
1681
|
+
});
|
|
1682
|
+
active = cfg ? new TelemetryExporter(cfg) : null;
|
|
1683
|
+
} catch {
|
|
1684
|
+
active = null;
|
|
1685
|
+
}
|
|
1686
|
+
return active !== null;
|
|
1687
|
+
}
|
|
1688
|
+
function telemetryStartTurn(goal, model) {
|
|
1689
|
+
active?.startTurn(goal, model);
|
|
1690
|
+
}
|
|
1691
|
+
function telemetryEvent(type, payload) {
|
|
1692
|
+
active?.onEvent(type, payload);
|
|
1693
|
+
}
|
|
1694
|
+
function telemetryEndTurn(outcome) {
|
|
1695
|
+
void active?.endTurn(outcome);
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1391
1698
|
// src/chat/hooks/useMemoryEnhancer.tsx
|
|
1392
1699
|
import { lastValueFrom, map as map2 } from "rxjs";
|
|
1393
1700
|
var MEMORY_LIMIT = 100;
|
|
@@ -2835,6 +3142,9 @@ ${protocol}`;
|
|
|
2835
3142
|
setStreamBuffer(latestDisplayMessage);
|
|
2836
3143
|
}, delay);
|
|
2837
3144
|
};
|
|
3145
|
+
syncTelemetry();
|
|
3146
|
+
telemetryStartTurn(question, modelName);
|
|
3147
|
+
telemetryEvent("tool_loop:llm_start");
|
|
2838
3148
|
const stream = provider.chat(request);
|
|
2839
3149
|
const initialPlaceholderQuestion = lastEntry?.question;
|
|
2840
3150
|
lastPartialRef.current = { text: "", images: [...imageList], usedDocs, question };
|
|
@@ -2848,7 +3158,10 @@ ${protocol}`;
|
|
|
2848
3158
|
const sub = stream.subscribe({
|
|
2849
3159
|
next: (data) => {
|
|
2850
3160
|
if (!data?.message?.content && !data?.message?.tool_calls) return;
|
|
2851
|
-
if (data.message.content)
|
|
3161
|
+
if (data.message.content) {
|
|
3162
|
+
fullMessage += data.message.content;
|
|
3163
|
+
telemetryEvent("tool_loop:llm_chunk", { chunk: data.message.content });
|
|
3164
|
+
}
|
|
2852
3165
|
const inThinkBlock = /<think>/.test(fullMessage) && !/<think>[\s\S]*<\/think>/.test(fullMessage);
|
|
2853
3166
|
setIsThinking?.(inThinkBlock);
|
|
2854
3167
|
const visibleMessage = stripThinking(fullMessage);
|
|
@@ -2880,6 +3193,7 @@ ${protocol}`;
|
|
|
2880
3193
|
setIsThinking?.(false);
|
|
2881
3194
|
setPendingMessage(null);
|
|
2882
3195
|
setLogoVisible(false);
|
|
3196
|
+
telemetryEndTurn({ error: err?.message || "stream error" });
|
|
2883
3197
|
if (onError) {
|
|
2884
3198
|
onError(err);
|
|
2885
3199
|
}
|
|
@@ -2887,6 +3201,7 @@ ${protocol}`;
|
|
|
2887
3201
|
complete: async () => {
|
|
2888
3202
|
try {
|
|
2889
3203
|
setIsThinking?.(false);
|
|
3204
|
+
telemetryEvent("tool_loop:llm_response", { responseLength: fullMessage.length });
|
|
2890
3205
|
latestDisplayMessage = stripThinking(fullMessage);
|
|
2891
3206
|
if (!sawToolBlock) {
|
|
2892
3207
|
flushNow();
|
|
@@ -2895,6 +3210,7 @@ ${protocol}`;
|
|
|
2895
3210
|
let enhancedMessage = fullMessage;
|
|
2896
3211
|
const summarizableResults = [];
|
|
2897
3212
|
const inlineImageBlocks = [];
|
|
3213
|
+
const collectedSources = [];
|
|
2898
3214
|
if (toolCallMatches && toolCallMatches.length > 0 && mcpToolsAvailable) {
|
|
2899
3215
|
debugLogger.info("Detected tool calls in AI response", {
|
|
2900
3216
|
toolCallCount: toolCallMatches.length,
|
|
@@ -2929,10 +3245,21 @@ ${protocol}`;
|
|
|
2929
3245
|
});
|
|
2930
3246
|
const placeholderToken = `<<TOOL_LOADING_${functionName}_${Math.random().toString(36).slice(2)}>>`;
|
|
2931
3247
|
enhancedMessage = enhancedMessage.replace(match, placeholderToken);
|
|
3248
|
+
clearFlushTimer();
|
|
3249
|
+
const toolStatus = functionName === "web_search" || functionName === "web-search" ? "Searching the web\u2026" : functionName === "web_fetch" || functionName === "web-fetch" ? "Reading the page\u2026" : functionName === "image_generation" || functionName === "image-generation" ? "Generating the image\u2026" : "Working on it\u2026";
|
|
3250
|
+
const toolPreamble = stripToolBlocks(fullMessage).trim();
|
|
3251
|
+
setStreamBuffer(toolPreamble ? `${toolPreamble}
|
|
3252
|
+
|
|
3253
|
+
_${toolStatus}_` : `_${toolStatus}_`);
|
|
3254
|
+
telemetryEvent("tool_loop:tool_execute", { name: functionName, params: parsedParams });
|
|
2932
3255
|
const result = await executeMCPTool({
|
|
2933
3256
|
toolName: functionName,
|
|
2934
3257
|
parameters: parsedParams
|
|
2935
3258
|
});
|
|
3259
|
+
telemetryEvent(result.success ? "tool_loop:tool_result" : "tool_loop:tool_error", {
|
|
3260
|
+
name: functionName,
|
|
3261
|
+
isError: !result.success
|
|
3262
|
+
});
|
|
2936
3263
|
let resultText = "";
|
|
2937
3264
|
if (result.success) {
|
|
2938
3265
|
if (functionName === "web_search" || functionName === "web-search") {
|
|
@@ -2946,18 +3273,16 @@ ${protocol}`;
|
|
|
2946
3273
|
blocks.push(
|
|
2947
3274
|
items.slice(0, 6).map((item, index) => {
|
|
2948
3275
|
const title = item.title?.trim() || "Untitled";
|
|
2949
|
-
const url = item.url?.trim();
|
|
3276
|
+
const url = item.url?.trim() || "";
|
|
2950
3277
|
const snippet = item.content?.trim();
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
${url}`;
|
|
3278
|
+
if (url) collectedSources.push({ title, url });
|
|
3279
|
+
let line = url ? `${index + 1}. [${title}](${url})` : `${index + 1}. ${title}`;
|
|
2954
3280
|
if (snippet) {
|
|
2955
3281
|
const truncated = snippet.length > 300 ? `${snippet.slice(0, 300)}\u2026` : snippet;
|
|
2956
|
-
line += `
|
|
2957
|
-
${truncated}`;
|
|
3282
|
+
line += ` \u2014 ${truncated}`;
|
|
2958
3283
|
}
|
|
2959
3284
|
return line;
|
|
2960
|
-
}).join("\n
|
|
3285
|
+
}).join("\n")
|
|
2961
3286
|
);
|
|
2962
3287
|
}
|
|
2963
3288
|
resultText = blocks.length ? blocks.join("\n\n") : `No results found${search.query ? ` for "${search.query}"` : ""}.`;
|
|
@@ -3039,7 +3364,7 @@ ${r.output}`).join("\n\n");
|
|
|
3039
3364
|
|
|
3040
3365
|
${toolResultsText}
|
|
3041
3366
|
|
|
3042
|
-
Using these results together with your own knowledge, answer my original question concisely and in a natural, well-formatted way.
|
|
3367
|
+
Using these results together with your own knowledge, answer my original question concisely and in a natural, well-formatted way. Reference sources by name where relevant, but do NOT paste raw URLs or a list of links \u2014 a clean Sources section is added automatically below your answer. Do NOT output tool_code or call any tools again.`
|
|
3043
3368
|
}
|
|
3044
3369
|
];
|
|
3045
3370
|
const summaryRequest = {
|
|
@@ -3053,7 +3378,7 @@ Using these results together with your own knowledge, answer my original questio
|
|
|
3053
3378
|
setStreamBuffer(
|
|
3054
3379
|
summaryPreamble ? `${summaryPreamble}
|
|
3055
3380
|
|
|
3056
|
-
|
|
3381
|
+
_Writing the answer\u2026_` : "_Writing the answer\u2026_"
|
|
3057
3382
|
);
|
|
3058
3383
|
const summaryText = await new Promise((resolve) => {
|
|
3059
3384
|
let acc = "";
|
|
@@ -3094,7 +3419,18 @@ _Working on it\u2026_` : "_Working on it\u2026_"
|
|
|
3094
3419
|
}, 3e4);
|
|
3095
3420
|
});
|
|
3096
3421
|
if (summaryText.trim()) {
|
|
3097
|
-
|
|
3422
|
+
const sourcesMd = collectedSources.length ? `
|
|
3423
|
+
|
|
3424
|
+
**Sources**
|
|
3425
|
+
${collectedSources.slice(0, 6).map((s) => {
|
|
3426
|
+
let domain = s.url;
|
|
3427
|
+
try {
|
|
3428
|
+
domain = new URL(s.url).hostname.replace(/^www\./, "");
|
|
3429
|
+
} catch {
|
|
3430
|
+
}
|
|
3431
|
+
return `- [${s.title || domain}](${s.url}) \u2014 ${domain}`;
|
|
3432
|
+
}).join("\n")}` : "";
|
|
3433
|
+
enhancedMessage = summaryText + sourcesMd + (inlineImageBlocks.length ? `
|
|
3098
3434
|
|
|
3099
3435
|
${inlineImageBlocks.join("\n\n")}` : "");
|
|
3100
3436
|
}
|
|
@@ -3143,6 +3479,7 @@ ${inlineImageBlocks.join("\n\n")}` : "");
|
|
|
3143
3479
|
}
|
|
3144
3480
|
setInputValue("");
|
|
3145
3481
|
setPastedImages([]);
|
|
3482
|
+
telemetryEndTurn();
|
|
3146
3483
|
setTimeout(() => {
|
|
3147
3484
|
clearFlushTimer();
|
|
3148
3485
|
setPendingMessage(null);
|
|
@@ -3158,6 +3495,7 @@ ${inlineImageBlocks.join("\n\n")}` : "");
|
|
|
3158
3495
|
overrideComponentStatus("Idle");
|
|
3159
3496
|
setIsSubmitting(false);
|
|
3160
3497
|
setIsStreaming(false);
|
|
3498
|
+
telemetryEndTurn({ error: e instanceof Error ? e.message : String(e) });
|
|
3161
3499
|
}
|
|
3162
3500
|
}
|
|
3163
3501
|
});
|
|
@@ -6059,10 +6397,10 @@ var EnhancedMobileConversationsModal = ({
|
|
|
6059
6397
|
useEffect10(() => {
|
|
6060
6398
|
setDeletedConversationIds((prev) => {
|
|
6061
6399
|
let changed = false;
|
|
6062
|
-
const
|
|
6400
|
+
const active2 = new Set(conversations.map((conv) => conv.id));
|
|
6063
6401
|
const next = /* @__PURE__ */ new Set();
|
|
6064
6402
|
prev.forEach((id) => {
|
|
6065
|
-
if (
|
|
6403
|
+
if (active2.has(id)) {
|
|
6066
6404
|
next.add(id);
|
|
6067
6405
|
} else {
|
|
6068
6406
|
changed = true;
|
|
@@ -9248,4 +9586,4 @@ var chat_default = Chat;
|
|
|
9248
9586
|
export {
|
|
9249
9587
|
chat_default
|
|
9250
9588
|
};
|
|
9251
|
-
//# sourceMappingURL=chunk-
|
|
9589
|
+
//# sourceMappingURL=chunk-MFDMM5MS.mjs.map
|