@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
package/dist/index.js
CHANGED
|
@@ -14862,7 +14862,11 @@ ${listMarkdown}`;
|
|
|
14862
14862
|
href,
|
|
14863
14863
|
target: "_blank",
|
|
14864
14864
|
rel: "noopener noreferrer",
|
|
14865
|
-
style: {
|
|
14865
|
+
style: {
|
|
14866
|
+
color: theme.palette.info?.main ?? theme.palette.primary.main,
|
|
14867
|
+
textDecoration: "underline",
|
|
14868
|
+
textUnderlineOffset: "2px"
|
|
14869
|
+
},
|
|
14866
14870
|
...props,
|
|
14867
14871
|
children
|
|
14868
14872
|
}
|
|
@@ -19107,6 +19111,330 @@ ${sanitize(
|
|
|
19107
19111
|
}
|
|
19108
19112
|
});
|
|
19109
19113
|
|
|
19114
|
+
// src/services/telemetry/otlpExporter.ts
|
|
19115
|
+
function redactSecretsString(s) {
|
|
19116
|
+
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]");
|
|
19117
|
+
}
|
|
19118
|
+
function resolveTelemetryConfig(opts) {
|
|
19119
|
+
if (!opts.telemetry?.enabled) return null;
|
|
19120
|
+
const endpoint = (opts.telemetry.endpoint ?? "https://otlp.burtson.ai").replace(/\/+$/, "");
|
|
19121
|
+
const headers = { ...opts.telemetry.headers ?? {} };
|
|
19122
|
+
const hasAuth = Object.keys(headers).some((k) => k.toLowerCase() === "authorization");
|
|
19123
|
+
if (!hasAuth && opts.banditApiKey) {
|
|
19124
|
+
headers["Authorization"] = `Bearer ${opts.banditApiKey}`;
|
|
19125
|
+
}
|
|
19126
|
+
const mode = opts.telemetry.mode ?? "metrics+traces";
|
|
19127
|
+
return { endpoint, headers, mode, serviceName: opts.telemetry.serviceName ?? "bandit-web" };
|
|
19128
|
+
}
|
|
19129
|
+
function toAttrs(rec) {
|
|
19130
|
+
const out = [];
|
|
19131
|
+
for (const [key, v] of Object.entries(rec)) {
|
|
19132
|
+
if (v === void 0 || v === null || v === "") continue;
|
|
19133
|
+
if (typeof v === "boolean") out.push({ key, value: { boolValue: v } });
|
|
19134
|
+
else if (typeof v === "number")
|
|
19135
|
+
out.push({ key, value: Number.isInteger(v) ? { intValue: String(v) } : { doubleValue: v } });
|
|
19136
|
+
else out.push({ key, value: { stringValue: v } });
|
|
19137
|
+
}
|
|
19138
|
+
return out;
|
|
19139
|
+
}
|
|
19140
|
+
function hex(bytes) {
|
|
19141
|
+
const arr = new Uint8Array(bytes);
|
|
19142
|
+
if (webCrypto?.getRandomValues) webCrypto.getRandomValues(arr);
|
|
19143
|
+
return Array.from(arr, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
19144
|
+
}
|
|
19145
|
+
function histogramPoint(value, bounds, attrs, startMs, endMs) {
|
|
19146
|
+
const counts = new Array(bounds.length + 1).fill(0);
|
|
19147
|
+
let idx = bounds.findIndex((b) => value <= b);
|
|
19148
|
+
if (idx === -1) idx = bounds.length;
|
|
19149
|
+
counts[idx] = 1;
|
|
19150
|
+
return {
|
|
19151
|
+
attributes: toAttrs(attrs),
|
|
19152
|
+
startTimeUnixNano: nano(startMs),
|
|
19153
|
+
timeUnixNano: nano(endMs),
|
|
19154
|
+
count: "1",
|
|
19155
|
+
sum: value,
|
|
19156
|
+
bucketCounts: counts.map(String),
|
|
19157
|
+
explicitBounds: bounds
|
|
19158
|
+
};
|
|
19159
|
+
}
|
|
19160
|
+
function sumPoint(value, attrs, startMs, endMs) {
|
|
19161
|
+
return {
|
|
19162
|
+
attributes: toAttrs(attrs),
|
|
19163
|
+
startTimeUnixNano: nano(startMs),
|
|
19164
|
+
timeUnixNano: nano(endMs),
|
|
19165
|
+
asInt: String(Math.round(value))
|
|
19166
|
+
};
|
|
19167
|
+
}
|
|
19168
|
+
var webCrypto, nano, TTFT_BUCKETS, DURATION_BUCKETS, clip, TelemetryExporter;
|
|
19169
|
+
var init_otlpExporter = __esm({
|
|
19170
|
+
"src/services/telemetry/otlpExporter.ts"() {
|
|
19171
|
+
"use strict";
|
|
19172
|
+
init_debugLogger();
|
|
19173
|
+
webCrypto = globalThis.crypto;
|
|
19174
|
+
nano = (ms) => String(Math.round(ms * 1e6));
|
|
19175
|
+
TTFT_BUCKETS = [0.1, 0.25, 0.5, 1, 2, 5, 10, 30];
|
|
19176
|
+
DURATION_BUCKETS = [0.5, 1, 2, 5, 10, 30, 60, 120, 300];
|
|
19177
|
+
clip = (s, n = 120) => redactSecretsString(s.slice(0, n)).slice(0, n);
|
|
19178
|
+
TelemetryExporter = class {
|
|
19179
|
+
cfg;
|
|
19180
|
+
now;
|
|
19181
|
+
traceId = "";
|
|
19182
|
+
turn = null;
|
|
19183
|
+
llm = null;
|
|
19184
|
+
llmFirstChunkMs = 0;
|
|
19185
|
+
openTools = [];
|
|
19186
|
+
completedSpans = [];
|
|
19187
|
+
model = "";
|
|
19188
|
+
turnChunkChars = 0;
|
|
19189
|
+
turnTokens = 0;
|
|
19190
|
+
ttftSeconds = null;
|
|
19191
|
+
constructor(cfg, opts) {
|
|
19192
|
+
this.cfg = cfg;
|
|
19193
|
+
this.now = opts?.now ?? (() => Date.now());
|
|
19194
|
+
}
|
|
19195
|
+
startTurn(goal, model) {
|
|
19196
|
+
this.traceId = hex(16);
|
|
19197
|
+
this.model = model;
|
|
19198
|
+
this.turnChunkChars = 0;
|
|
19199
|
+
this.turnTokens = 0;
|
|
19200
|
+
this.ttftSeconds = null;
|
|
19201
|
+
this.llm = null;
|
|
19202
|
+
this.llmFirstChunkMs = 0;
|
|
19203
|
+
this.openTools = [];
|
|
19204
|
+
this.completedSpans = [];
|
|
19205
|
+
this.turn = {
|
|
19206
|
+
spanId: hex(8),
|
|
19207
|
+
name: "agent.turn",
|
|
19208
|
+
startMs: this.now(),
|
|
19209
|
+
attrs: { "gen_ai.request.model": model, "bandit.turn.goal": clip(goal, 160) }
|
|
19210
|
+
};
|
|
19211
|
+
}
|
|
19212
|
+
/** Fed from the chat turn lifecycle. Best-effort; swallows bad payloads. */
|
|
19213
|
+
onEvent(type, payload) {
|
|
19214
|
+
if (!this.turn) return;
|
|
19215
|
+
try {
|
|
19216
|
+
const p = payload ?? {};
|
|
19217
|
+
switch (type) {
|
|
19218
|
+
case "tool_loop:llm_start":
|
|
19219
|
+
this.llm = {
|
|
19220
|
+
spanId: hex(8),
|
|
19221
|
+
parentSpanId: this.turn.spanId,
|
|
19222
|
+
name: "llm.generate",
|
|
19223
|
+
startMs: this.now(),
|
|
19224
|
+
attrs: { "gen_ai.request.model": this.model }
|
|
19225
|
+
};
|
|
19226
|
+
this.llmFirstChunkMs = 0;
|
|
19227
|
+
break;
|
|
19228
|
+
case "tool_loop:llm_chunk": {
|
|
19229
|
+
const chunk = typeof p.chunk === "string" ? p.chunk : "";
|
|
19230
|
+
if (this.llm && this.llmFirstChunkMs === 0 && chunk.length > 0) {
|
|
19231
|
+
this.llmFirstChunkMs = this.now();
|
|
19232
|
+
const ttft = (this.llmFirstChunkMs - this.llm.startMs) / 1e3;
|
|
19233
|
+
if (this.ttftSeconds === null) this.ttftSeconds = ttft;
|
|
19234
|
+
this.llm.attrs["bandit.llm.ttft_seconds"] = ttft;
|
|
19235
|
+
}
|
|
19236
|
+
this.turnChunkChars += chunk.length;
|
|
19237
|
+
this.turnTokens = Math.floor(this.turnChunkChars / 4);
|
|
19238
|
+
break;
|
|
19239
|
+
}
|
|
19240
|
+
case "tool_loop:llm_response":
|
|
19241
|
+
if (this.llm) {
|
|
19242
|
+
this.llm.endMs = this.now();
|
|
19243
|
+
if (typeof p.responseLength === "number") this.llm.attrs["bandit.llm.response_chars"] = p.responseLength;
|
|
19244
|
+
this.completedSpans.push(this.llm);
|
|
19245
|
+
this.llm = null;
|
|
19246
|
+
}
|
|
19247
|
+
break;
|
|
19248
|
+
case "tool_loop:tool_execute": {
|
|
19249
|
+
const name = typeof p.name === "string" ? p.name : "tool";
|
|
19250
|
+
const params = p.params ?? {};
|
|
19251
|
+
const primary = params.query ?? params.url ?? params.prompt ?? params.topic ?? "";
|
|
19252
|
+
this.openTools.push({
|
|
19253
|
+
spanId: hex(8),
|
|
19254
|
+
parentSpanId: this.turn.spanId,
|
|
19255
|
+
name: `tool.${name}`,
|
|
19256
|
+
startMs: this.now(),
|
|
19257
|
+
attrs: { "bandit.tool.name": name, "bandit.tool.primary": primary ? clip(primary) : void 0 }
|
|
19258
|
+
});
|
|
19259
|
+
break;
|
|
19260
|
+
}
|
|
19261
|
+
case "tool_loop:tool_result":
|
|
19262
|
+
case "tool_loop:tool_error": {
|
|
19263
|
+
const name = typeof p.name === "string" ? p.name : void 0;
|
|
19264
|
+
const span = this.takeOpenTool(name);
|
|
19265
|
+
if (span) {
|
|
19266
|
+
span.endMs = this.now();
|
|
19267
|
+
if (type === "tool_loop:tool_error" || p.isError === true) span.error = "tool error";
|
|
19268
|
+
this.completedSpans.push(span);
|
|
19269
|
+
}
|
|
19270
|
+
break;
|
|
19271
|
+
}
|
|
19272
|
+
}
|
|
19273
|
+
} catch {
|
|
19274
|
+
}
|
|
19275
|
+
}
|
|
19276
|
+
takeOpenTool(name) {
|
|
19277
|
+
if (name) {
|
|
19278
|
+
for (let i = this.openTools.length - 1; i >= 0; i -= 1) {
|
|
19279
|
+
if (this.openTools[i].name === `tool.${name}`) return this.openTools.splice(i, 1)[0];
|
|
19280
|
+
}
|
|
19281
|
+
}
|
|
19282
|
+
return this.openTools.shift();
|
|
19283
|
+
}
|
|
19284
|
+
/** Close the turn, build OTLP traces + metrics, and flush. Never rejects. */
|
|
19285
|
+
async endTurn(outcome) {
|
|
19286
|
+
const turn = this.turn;
|
|
19287
|
+
if (!turn) return;
|
|
19288
|
+
this.turn = null;
|
|
19289
|
+
const end = this.now();
|
|
19290
|
+
if (this.llm && !this.llm.endMs) {
|
|
19291
|
+
this.llm.endMs = end;
|
|
19292
|
+
this.completedSpans.push(this.llm);
|
|
19293
|
+
this.llm = null;
|
|
19294
|
+
}
|
|
19295
|
+
for (const t of this.openTools.splice(0)) {
|
|
19296
|
+
t.endMs = end;
|
|
19297
|
+
t.error = t.error ?? "incomplete";
|
|
19298
|
+
this.completedSpans.push(t);
|
|
19299
|
+
}
|
|
19300
|
+
turn.endMs = end;
|
|
19301
|
+
if (outcome?.error) turn.error = outcome.error;
|
|
19302
|
+
const traceId = this.traceId;
|
|
19303
|
+
const spans = [turn, ...this.completedSpans];
|
|
19304
|
+
const jobs = [];
|
|
19305
|
+
if (this.cfg.mode === "metrics+traces") jobs.push(this.post("/v1/traces", this.buildTraces(traceId, spans)));
|
|
19306
|
+
jobs.push(this.post("/v1/metrics", this.buildMetrics(turn)));
|
|
19307
|
+
try {
|
|
19308
|
+
await Promise.all(jobs);
|
|
19309
|
+
} catch {
|
|
19310
|
+
}
|
|
19311
|
+
}
|
|
19312
|
+
buildTraces(traceId, spans) {
|
|
19313
|
+
return {
|
|
19314
|
+
resourceSpans: [
|
|
19315
|
+
{
|
|
19316
|
+
resource: { attributes: toAttrs({ "service.name": this.cfg.serviceName }) },
|
|
19317
|
+
scopeSpans: [
|
|
19318
|
+
{
|
|
19319
|
+
scope: { name: this.cfg.serviceName },
|
|
19320
|
+
spans: spans.map((s) => ({
|
|
19321
|
+
traceId,
|
|
19322
|
+
spanId: s.spanId,
|
|
19323
|
+
parentSpanId: s.parentSpanId,
|
|
19324
|
+
name: s.name,
|
|
19325
|
+
kind: 1,
|
|
19326
|
+
startTimeUnixNano: nano(s.startMs),
|
|
19327
|
+
endTimeUnixNano: nano(s.endMs ?? s.startMs),
|
|
19328
|
+
attributes: toAttrs(s.attrs),
|
|
19329
|
+
status: s.error ? { code: 2, message: s.error.slice(0, 200) } : { code: 1 }
|
|
19330
|
+
}))
|
|
19331
|
+
}
|
|
19332
|
+
]
|
|
19333
|
+
}
|
|
19334
|
+
]
|
|
19335
|
+
};
|
|
19336
|
+
}
|
|
19337
|
+
buildMetrics(turn) {
|
|
19338
|
+
const start = turn.startMs;
|
|
19339
|
+
const end = turn.endMs ?? this.now();
|
|
19340
|
+
const metrics = [];
|
|
19341
|
+
if (this.turnTokens > 0) {
|
|
19342
|
+
metrics.push({
|
|
19343
|
+
name: "bandit.llm.tokens",
|
|
19344
|
+
sum: {
|
|
19345
|
+
aggregationTemporality: 1,
|
|
19346
|
+
isMonotonic: true,
|
|
19347
|
+
dataPoints: [sumPoint(this.turnTokens, { type: "output", "gen_ai.request.model": this.model }, start, end)]
|
|
19348
|
+
}
|
|
19349
|
+
});
|
|
19350
|
+
}
|
|
19351
|
+
if (this.ttftSeconds !== null) {
|
|
19352
|
+
metrics.push({
|
|
19353
|
+
name: "bandit.llm.ttft",
|
|
19354
|
+
unit: "s",
|
|
19355
|
+
histogram: {
|
|
19356
|
+
aggregationTemporality: 1,
|
|
19357
|
+
dataPoints: [histogramPoint(this.ttftSeconds, TTFT_BUCKETS, { "gen_ai.request.model": this.model }, start, end)]
|
|
19358
|
+
}
|
|
19359
|
+
});
|
|
19360
|
+
}
|
|
19361
|
+
metrics.push({
|
|
19362
|
+
name: "bandit.turn.duration",
|
|
19363
|
+
unit: "s",
|
|
19364
|
+
histogram: {
|
|
19365
|
+
aggregationTemporality: 1,
|
|
19366
|
+
dataPoints: [histogramPoint((end - start) / 1e3, DURATION_BUCKETS, { "gen_ai.request.model": this.model }, start, end)]
|
|
19367
|
+
}
|
|
19368
|
+
});
|
|
19369
|
+
return {
|
|
19370
|
+
resourceMetrics: [
|
|
19371
|
+
{
|
|
19372
|
+
resource: { attributes: toAttrs({ "service.name": this.cfg.serviceName }) },
|
|
19373
|
+
scopeMetrics: [{ scope: { name: this.cfg.serviceName }, metrics }]
|
|
19374
|
+
}
|
|
19375
|
+
]
|
|
19376
|
+
};
|
|
19377
|
+
}
|
|
19378
|
+
async post(path, body) {
|
|
19379
|
+
const doFetch = globalThis.fetch;
|
|
19380
|
+
if (!doFetch) return;
|
|
19381
|
+
const ctrl = new AbortController();
|
|
19382
|
+
const timer = setTimeout(() => ctrl.abort(), 4e3);
|
|
19383
|
+
try {
|
|
19384
|
+
await doFetch(`${this.cfg.endpoint}${path}`, {
|
|
19385
|
+
method: "POST",
|
|
19386
|
+
headers: { "Content-Type": "application/json", ...this.cfg.headers },
|
|
19387
|
+
body: JSON.stringify(body),
|
|
19388
|
+
signal: ctrl.signal
|
|
19389
|
+
});
|
|
19390
|
+
} catch (e) {
|
|
19391
|
+
debugLogger.debug("[telemetry] OTLP post failed", {
|
|
19392
|
+
path,
|
|
19393
|
+
error: e instanceof Error ? e.message : String(e)
|
|
19394
|
+
});
|
|
19395
|
+
} finally {
|
|
19396
|
+
clearTimeout(timer);
|
|
19397
|
+
}
|
|
19398
|
+
}
|
|
19399
|
+
};
|
|
19400
|
+
}
|
|
19401
|
+
});
|
|
19402
|
+
|
|
19403
|
+
// src/services/telemetry/index.ts
|
|
19404
|
+
function syncTelemetry() {
|
|
19405
|
+
try {
|
|
19406
|
+
const settings = usePackageSettingsStore.getState().settings;
|
|
19407
|
+
const cfg = resolveTelemetryConfig({
|
|
19408
|
+
telemetry: settings?.telemetry,
|
|
19409
|
+
banditApiKey: authenticationService.getToken() ?? void 0
|
|
19410
|
+
});
|
|
19411
|
+
active = cfg ? new TelemetryExporter(cfg) : null;
|
|
19412
|
+
} catch {
|
|
19413
|
+
active = null;
|
|
19414
|
+
}
|
|
19415
|
+
return active !== null;
|
|
19416
|
+
}
|
|
19417
|
+
function telemetryStartTurn(goal, model) {
|
|
19418
|
+
active?.startTurn(goal, model);
|
|
19419
|
+
}
|
|
19420
|
+
function telemetryEvent(type, payload) {
|
|
19421
|
+
active?.onEvent(type, payload);
|
|
19422
|
+
}
|
|
19423
|
+
function telemetryEndTurn(outcome) {
|
|
19424
|
+
void active?.endTurn(outcome);
|
|
19425
|
+
}
|
|
19426
|
+
var active;
|
|
19427
|
+
var init_telemetry = __esm({
|
|
19428
|
+
"src/services/telemetry/index.ts"() {
|
|
19429
|
+
"use strict";
|
|
19430
|
+
init_otlpExporter();
|
|
19431
|
+
init_packageSettingsStore();
|
|
19432
|
+
init_authenticationService();
|
|
19433
|
+
init_otlpExporter();
|
|
19434
|
+
active = null;
|
|
19435
|
+
}
|
|
19436
|
+
});
|
|
19437
|
+
|
|
19110
19438
|
// src/chat/hooks/useMemoryEnhancer.tsx
|
|
19111
19439
|
var import_rxjs20, MEMORY_LIMIT, MIN_MEMORY_WORDS, MERGE_THRESHOLD, REJECT_ECHO_THRESHOLD, REJECT_DUPLICATE_THRESHOLD, CONTEXTUAL_DIVERGENCE_THRESHOLD, normalizeText, isStructurallyDuplicate, isAboutBandit, hasEngagementValue, isMemoryTooShortOrGeneric, isPersonalText, mergeMemory, isVoiceShifted, sanitizeMemory, sanitizeMemoryText, shouldAcceptMemory, isContextuallyDivergent, useMemoryEnhancer;
|
|
19112
19440
|
var init_useMemoryEnhancer = __esm({
|
|
@@ -19848,6 +20176,7 @@ var init_useAIProvider = __esm({
|
|
|
19848
20176
|
import_react22 = require("react");
|
|
19849
20177
|
init_knowledgeStore();
|
|
19850
20178
|
init_aiProviderStore();
|
|
20179
|
+
init_telemetry();
|
|
19851
20180
|
init_conversationStore();
|
|
19852
20181
|
init_useMemoryEnhancer();
|
|
19853
20182
|
init_useVectorStore();
|
|
@@ -20612,6 +20941,9 @@ ${protocol}`;
|
|
|
20612
20941
|
setStreamBuffer(latestDisplayMessage);
|
|
20613
20942
|
}, delay);
|
|
20614
20943
|
};
|
|
20944
|
+
syncTelemetry();
|
|
20945
|
+
telemetryStartTurn(question, modelName);
|
|
20946
|
+
telemetryEvent("tool_loop:llm_start");
|
|
20615
20947
|
const stream = provider.chat(request);
|
|
20616
20948
|
const initialPlaceholderQuestion = lastEntry?.question;
|
|
20617
20949
|
lastPartialRef.current = { text: "", images: [...imageList], usedDocs, question };
|
|
@@ -20625,7 +20957,10 @@ ${protocol}`;
|
|
|
20625
20957
|
const sub = stream.subscribe({
|
|
20626
20958
|
next: (data) => {
|
|
20627
20959
|
if (!data?.message?.content && !data?.message?.tool_calls) return;
|
|
20628
|
-
if (data.message.content)
|
|
20960
|
+
if (data.message.content) {
|
|
20961
|
+
fullMessage += data.message.content;
|
|
20962
|
+
telemetryEvent("tool_loop:llm_chunk", { chunk: data.message.content });
|
|
20963
|
+
}
|
|
20629
20964
|
const inThinkBlock = /<think>/.test(fullMessage) && !/<think>[\s\S]*<\/think>/.test(fullMessage);
|
|
20630
20965
|
setIsThinking?.(inThinkBlock);
|
|
20631
20966
|
const visibleMessage = stripThinking(fullMessage);
|
|
@@ -20657,6 +20992,7 @@ ${protocol}`;
|
|
|
20657
20992
|
setIsThinking?.(false);
|
|
20658
20993
|
setPendingMessage(null);
|
|
20659
20994
|
setLogoVisible(false);
|
|
20995
|
+
telemetryEndTurn({ error: err?.message || "stream error" });
|
|
20660
20996
|
if (onError) {
|
|
20661
20997
|
onError(err);
|
|
20662
20998
|
}
|
|
@@ -20664,6 +21000,7 @@ ${protocol}`;
|
|
|
20664
21000
|
complete: async () => {
|
|
20665
21001
|
try {
|
|
20666
21002
|
setIsThinking?.(false);
|
|
21003
|
+
telemetryEvent("tool_loop:llm_response", { responseLength: fullMessage.length });
|
|
20667
21004
|
latestDisplayMessage = stripThinking(fullMessage);
|
|
20668
21005
|
if (!sawToolBlock) {
|
|
20669
21006
|
flushNow();
|
|
@@ -20672,6 +21009,7 @@ ${protocol}`;
|
|
|
20672
21009
|
let enhancedMessage = fullMessage;
|
|
20673
21010
|
const summarizableResults = [];
|
|
20674
21011
|
const inlineImageBlocks = [];
|
|
21012
|
+
const collectedSources = [];
|
|
20675
21013
|
if (toolCallMatches && toolCallMatches.length > 0 && mcpToolsAvailable) {
|
|
20676
21014
|
debugLogger.info("Detected tool calls in AI response", {
|
|
20677
21015
|
toolCallCount: toolCallMatches.length,
|
|
@@ -20706,10 +21044,21 @@ ${protocol}`;
|
|
|
20706
21044
|
});
|
|
20707
21045
|
const placeholderToken = `<<TOOL_LOADING_${functionName}_${Math.random().toString(36).slice(2)}>>`;
|
|
20708
21046
|
enhancedMessage = enhancedMessage.replace(match, placeholderToken);
|
|
21047
|
+
clearFlushTimer();
|
|
21048
|
+
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";
|
|
21049
|
+
const toolPreamble = stripToolBlocks(fullMessage).trim();
|
|
21050
|
+
setStreamBuffer(toolPreamble ? `${toolPreamble}
|
|
21051
|
+
|
|
21052
|
+
_${toolStatus}_` : `_${toolStatus}_`);
|
|
21053
|
+
telemetryEvent("tool_loop:tool_execute", { name: functionName, params: parsedParams });
|
|
20709
21054
|
const result = await executeMCPTool({
|
|
20710
21055
|
toolName: functionName,
|
|
20711
21056
|
parameters: parsedParams
|
|
20712
21057
|
});
|
|
21058
|
+
telemetryEvent(result.success ? "tool_loop:tool_result" : "tool_loop:tool_error", {
|
|
21059
|
+
name: functionName,
|
|
21060
|
+
isError: !result.success
|
|
21061
|
+
});
|
|
20713
21062
|
let resultText = "";
|
|
20714
21063
|
if (result.success) {
|
|
20715
21064
|
if (functionName === "web_search" || functionName === "web-search") {
|
|
@@ -20723,18 +21072,16 @@ ${protocol}`;
|
|
|
20723
21072
|
blocks.push(
|
|
20724
21073
|
items.slice(0, 6).map((item, index) => {
|
|
20725
21074
|
const title = item.title?.trim() || "Untitled";
|
|
20726
|
-
const url = item.url?.trim();
|
|
21075
|
+
const url = item.url?.trim() || "";
|
|
20727
21076
|
const snippet = item.content?.trim();
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
${url}`;
|
|
21077
|
+
if (url) collectedSources.push({ title, url });
|
|
21078
|
+
let line = url ? `${index + 1}. [${title}](${url})` : `${index + 1}. ${title}`;
|
|
20731
21079
|
if (snippet) {
|
|
20732
21080
|
const truncated = snippet.length > 300 ? `${snippet.slice(0, 300)}\u2026` : snippet;
|
|
20733
|
-
line += `
|
|
20734
|
-
${truncated}`;
|
|
21081
|
+
line += ` \u2014 ${truncated}`;
|
|
20735
21082
|
}
|
|
20736
21083
|
return line;
|
|
20737
|
-
}).join("\n
|
|
21084
|
+
}).join("\n")
|
|
20738
21085
|
);
|
|
20739
21086
|
}
|
|
20740
21087
|
resultText = blocks.length ? blocks.join("\n\n") : `No results found${search.query ? ` for "${search.query}"` : ""}.`;
|
|
@@ -20816,7 +21163,7 @@ ${r.output}`).join("\n\n");
|
|
|
20816
21163
|
|
|
20817
21164
|
${toolResultsText}
|
|
20818
21165
|
|
|
20819
|
-
Using these results together with your own knowledge, answer my original question concisely and in a natural, well-formatted way.
|
|
21166
|
+
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.`
|
|
20820
21167
|
}
|
|
20821
21168
|
];
|
|
20822
21169
|
const summaryRequest = {
|
|
@@ -20830,7 +21177,7 @@ Using these results together with your own knowledge, answer my original questio
|
|
|
20830
21177
|
setStreamBuffer(
|
|
20831
21178
|
summaryPreamble ? `${summaryPreamble}
|
|
20832
21179
|
|
|
20833
|
-
|
|
21180
|
+
_Writing the answer\u2026_` : "_Writing the answer\u2026_"
|
|
20834
21181
|
);
|
|
20835
21182
|
const summaryText = await new Promise((resolve) => {
|
|
20836
21183
|
let acc = "";
|
|
@@ -20871,7 +21218,18 @@ _Working on it\u2026_` : "_Working on it\u2026_"
|
|
|
20871
21218
|
}, 3e4);
|
|
20872
21219
|
});
|
|
20873
21220
|
if (summaryText.trim()) {
|
|
20874
|
-
|
|
21221
|
+
const sourcesMd = collectedSources.length ? `
|
|
21222
|
+
|
|
21223
|
+
**Sources**
|
|
21224
|
+
${collectedSources.slice(0, 6).map((s) => {
|
|
21225
|
+
let domain = s.url;
|
|
21226
|
+
try {
|
|
21227
|
+
domain = new URL(s.url).hostname.replace(/^www\./, "");
|
|
21228
|
+
} catch {
|
|
21229
|
+
}
|
|
21230
|
+
return `- [${s.title || domain}](${s.url}) \u2014 ${domain}`;
|
|
21231
|
+
}).join("\n")}` : "";
|
|
21232
|
+
enhancedMessage = summaryText + sourcesMd + (inlineImageBlocks.length ? `
|
|
20875
21233
|
|
|
20876
21234
|
${inlineImageBlocks.join("\n\n")}` : "");
|
|
20877
21235
|
}
|
|
@@ -20920,6 +21278,7 @@ ${inlineImageBlocks.join("\n\n")}` : "");
|
|
|
20920
21278
|
}
|
|
20921
21279
|
setInputValue("");
|
|
20922
21280
|
setPastedImages([]);
|
|
21281
|
+
telemetryEndTurn();
|
|
20923
21282
|
setTimeout(() => {
|
|
20924
21283
|
clearFlushTimer();
|
|
20925
21284
|
setPendingMessage(null);
|
|
@@ -20935,6 +21294,7 @@ ${inlineImageBlocks.join("\n\n")}` : "");
|
|
|
20935
21294
|
overrideComponentStatus("Idle");
|
|
20936
21295
|
setIsSubmitting(false);
|
|
20937
21296
|
setIsStreaming(false);
|
|
21297
|
+
telemetryEndTurn({ error: e instanceof Error ? e.message : String(e) });
|
|
20938
21298
|
}
|
|
20939
21299
|
}
|
|
20940
21300
|
});
|
|
@@ -23793,10 +24153,10 @@ var init_enhanced_mobile_conversations_modal = __esm({
|
|
|
23793
24153
|
(0, import_react30.useEffect)(() => {
|
|
23794
24154
|
setDeletedConversationIds((prev) => {
|
|
23795
24155
|
let changed = false;
|
|
23796
|
-
const
|
|
24156
|
+
const active2 = new Set(conversations.map((conv) => conv.id));
|
|
23797
24157
|
const next = /* @__PURE__ */ new Set();
|
|
23798
24158
|
prev.forEach((id) => {
|
|
23799
|
-
if (
|
|
24159
|
+
if (active2.has(id)) {
|
|
23800
24160
|
next.add(id);
|
|
23801
24161
|
} else {
|
|
23802
24162
|
changed = true;
|