@burtson-labs/bandit-engine 2.0.55 → 2.0.58
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 +76 -76
- package/dist/{chat-IDE6Z4Q4.mjs → chat-MXC6O7M5.mjs} +3 -3
- package/dist/chat-provider.js +20 -67
- package/dist/chat-provider.js.map +1 -1
- package/dist/chat-provider.mjs +2 -2
- package/dist/{chunk-TLY6A6XL.mjs → chunk-N7GCS2BH.mjs} +156 -113
- package/dist/chunk-N7GCS2BH.mjs.map +1 -0
- package/dist/{chunk-AVV7HDGR.mjs → chunk-POTQI33D.mjs} +2 -2
- package/dist/{chunk-EHNWQ4T3.mjs → chunk-QPBG6JQE.mjs} +21 -68
- package/dist/chunk-QPBG6JQE.mjs.map +1 -0
- package/dist/{chunk-NP2OHTTX.mjs → chunk-VU5N57QZ.mjs} +3 -3
- package/dist/index.js +176 -180
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -4
- package/dist/management/management.js +176 -180
- package/dist/management/management.js.map +1 -1
- package/dist/management/management.mjs +2 -2
- package/package.json +2 -2
- package/dist/chunk-EHNWQ4T3.mjs.map +0 -1
- package/dist/chunk-TLY6A6XL.mjs.map +0 -1
- /package/dist/{chat-IDE6Z4Q4.mjs.map → chat-MXC6O7M5.mjs.map} +0 -0
- /package/dist/{chunk-AVV7HDGR.mjs.map → chunk-POTQI33D.mjs.map} +0 -0
- /package/dist/{chunk-NP2OHTTX.mjs.map → chunk-VU5N57QZ.mjs.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -3260,7 +3260,7 @@ var init_knowledgeStore = __esm({
|
|
|
3260
3260
|
});
|
|
3261
3261
|
|
|
3262
3262
|
// src/store/mcpToolsStore.ts
|
|
3263
|
-
var import_zustand11, healthCheckTool,
|
|
3263
|
+
var import_zustand11, healthCheckTool, webSearchTool, webFetchTool, imageGenerationTool, defaultTools, useMCPToolsStore;
|
|
3264
3264
|
var init_mcpToolsStore = __esm({
|
|
3265
3265
|
"src/store/mcpToolsStore.ts"() {
|
|
3266
3266
|
"use strict";
|
|
@@ -3286,94 +3286,47 @@ var init_mcpToolsStore = __esm({
|
|
|
3286
3286
|
method: "GET",
|
|
3287
3287
|
isBuiltIn: true
|
|
3288
3288
|
};
|
|
3289
|
-
|
|
3290
|
-
id: "
|
|
3291
|
-
name: "
|
|
3292
|
-
description: "
|
|
3289
|
+
webSearchTool = {
|
|
3290
|
+
id: "web-search",
|
|
3291
|
+
name: "web_search",
|
|
3292
|
+
description: "Search the web for current information, documentation, and facts",
|
|
3293
3293
|
enabled: true,
|
|
3294
3294
|
type: "function",
|
|
3295
3295
|
function: {
|
|
3296
|
-
name: "
|
|
3297
|
-
description: "
|
|
3296
|
+
name: "web_search",
|
|
3297
|
+
description: "Search the web and return ranked results with snippets (and an optional summarized answer). Use for current events, documentation, libraries, error messages, and factual lookups.",
|
|
3298
3298
|
parameters: {
|
|
3299
3299
|
type: "object",
|
|
3300
3300
|
properties: {
|
|
3301
|
-
|
|
3302
|
-
count: { type: "number", description: "Number of
|
|
3303
|
-
|
|
3304
|
-
},
|
|
3305
|
-
required: []
|
|
3306
|
-
}
|
|
3307
|
-
},
|
|
3308
|
-
endpoint: "/mcp/news",
|
|
3309
|
-
method: "GET",
|
|
3310
|
-
isBuiltIn: true
|
|
3311
|
-
};
|
|
3312
|
-
weatherTool = {
|
|
3313
|
-
id: "weather",
|
|
3314
|
-
name: "weather",
|
|
3315
|
-
description: "Get current weather conditions and forecasts by location",
|
|
3316
|
-
enabled: true,
|
|
3317
|
-
type: "function",
|
|
3318
|
-
function: {
|
|
3319
|
-
name: "weather",
|
|
3320
|
-
description: "Get weather information by location",
|
|
3321
|
-
parameters: {
|
|
3322
|
-
type: "object",
|
|
3323
|
-
properties: {
|
|
3324
|
-
zip: { type: "string", description: "US zip code" },
|
|
3325
|
-
latitude: { type: "number", description: "Latitude" },
|
|
3326
|
-
longitude: { type: "number", description: "Longitude" }
|
|
3327
|
-
},
|
|
3328
|
-
required: []
|
|
3329
|
-
}
|
|
3330
|
-
},
|
|
3331
|
-
endpoint: "/mcp/weather",
|
|
3332
|
-
method: "GET",
|
|
3333
|
-
isBuiltIn: true
|
|
3334
|
-
};
|
|
3335
|
-
docsTool = {
|
|
3336
|
-
id: "docs",
|
|
3337
|
-
name: "docs",
|
|
3338
|
-
description: "Search framework documentation",
|
|
3339
|
-
enabled: true,
|
|
3340
|
-
type: "function",
|
|
3341
|
-
function: {
|
|
3342
|
-
name: "docs",
|
|
3343
|
-
description: "Search framework documentation",
|
|
3344
|
-
parameters: {
|
|
3345
|
-
type: "object",
|
|
3346
|
-
properties: {
|
|
3347
|
-
query: { type: "string", description: "Search query" },
|
|
3348
|
-
framework: { type: "string", description: "Specific framework to search" },
|
|
3349
|
-
count: { type: "number", description: "Number of results (1-50)" }
|
|
3301
|
+
query: { type: "string", description: "The search query \u2014 natural language or keywords" },
|
|
3302
|
+
count: { type: "number", description: "Number of results to return (1-10, default 5)" },
|
|
3303
|
+
include_answer: { type: "boolean", description: "Include a short summarized answer when available" }
|
|
3350
3304
|
},
|
|
3351
3305
|
required: ["query"]
|
|
3352
3306
|
}
|
|
3353
3307
|
},
|
|
3354
|
-
endpoint: "/mcp/
|
|
3308
|
+
endpoint: "/mcp/web-search",
|
|
3355
3309
|
method: "GET",
|
|
3356
3310
|
isBuiltIn: true
|
|
3357
3311
|
};
|
|
3358
|
-
|
|
3359
|
-
id: "
|
|
3360
|
-
name: "
|
|
3361
|
-
description: "
|
|
3312
|
+
webFetchTool = {
|
|
3313
|
+
id: "web-fetch",
|
|
3314
|
+
name: "web_fetch",
|
|
3315
|
+
description: "Fetch the text content of a specific URL",
|
|
3362
3316
|
enabled: true,
|
|
3363
3317
|
type: "function",
|
|
3364
3318
|
function: {
|
|
3365
|
-
name: "
|
|
3366
|
-
description: "
|
|
3319
|
+
name: "web_fetch",
|
|
3320
|
+
description: "Fetch a single public URL and return its trimmed text content. Use when you already have a specific link you need to read.",
|
|
3367
3321
|
parameters: {
|
|
3368
3322
|
type: "object",
|
|
3369
3323
|
properties: {
|
|
3370
|
-
|
|
3371
|
-
date: { type: "string", description: "Date in YYYY-MM-DD format" }
|
|
3324
|
+
url: { type: "string", description: "Absolute http(s) URL to fetch" }
|
|
3372
3325
|
},
|
|
3373
|
-
required: []
|
|
3326
|
+
required: ["url"]
|
|
3374
3327
|
}
|
|
3375
3328
|
},
|
|
3376
|
-
endpoint: "/mcp/
|
|
3329
|
+
endpoint: "/mcp/web-fetch",
|
|
3377
3330
|
method: "GET",
|
|
3378
3331
|
isBuiltIn: true
|
|
3379
3332
|
};
|
|
@@ -3401,7 +3354,7 @@ var init_mcpToolsStore = __esm({
|
|
|
3401
3354
|
method: "POST",
|
|
3402
3355
|
isBuiltIn: true
|
|
3403
3356
|
};
|
|
3404
|
-
defaultTools = [healthCheckTool,
|
|
3357
|
+
defaultTools = [healthCheckTool, webSearchTool, webFetchTool, imageGenerationTool];
|
|
3405
3358
|
useMCPToolsStore = (0, import_zustand11.create)((set, get) => ({
|
|
3406
3359
|
tools: defaultTools,
|
|
3407
3360
|
isLoaded: false,
|
|
@@ -15483,7 +15436,7 @@ var init_stt_client = __esm({
|
|
|
15483
15436
|
normalizedBlob = new Blob([blob], { type: "audio/webm" });
|
|
15484
15437
|
}
|
|
15485
15438
|
const body = new FormData();
|
|
15486
|
-
const filename = normalizedBlob.type.includes("ogg") ? "audio.ogg" : normalizedBlob.type.includes("wav") ? "audio.wav" : normalizedBlob.type.includes("mp3") ? "audio.mp3" : "audio.webm";
|
|
15439
|
+
const filename = normalizedBlob.type.includes("ogg") ? "audio.ogg" : normalizedBlob.type.includes("wav") ? "audio.wav" : normalizedBlob.type.includes("mp4") || normalizedBlob.type.includes("m4a") || normalizedBlob.type.includes("aac") ? "audio.mp4" : normalizedBlob.type.includes("mp3") ? "audio.mp3" : "audio.webm";
|
|
15487
15440
|
body.append("audio", normalizedBlob, filename);
|
|
15488
15441
|
body.append("file", normalizedBlob, filename);
|
|
15489
15442
|
body.append("audioFile", normalizedBlob, filename);
|
|
@@ -20558,6 +20511,7 @@ USE THE ABOVE CONTENT to answer the user's question. Reference specific informat
|
|
|
20558
20511
|
- Only use tools for live data (news, weather, sports scores) when specifically requested
|
|
20559
20512
|
- Trust and utilize the provided context without hesitation`;
|
|
20560
20513
|
enhancedSystemPrompt += ragGuidance;
|
|
20514
|
+
const systemPromptForSummary = enhancedSystemPrompt;
|
|
20561
20515
|
const mcpToolsAvailable = isMCPAvailable();
|
|
20562
20516
|
if (mcpToolsAvailable) {
|
|
20563
20517
|
const enabledTools = getEnabledMCPToolsForAI();
|
|
@@ -20573,10 +20527,10 @@ USE THE ABOVE CONTENT to answer the user's question. Reference specific informat
|
|
|
20573
20527
|
TOOL USAGE PROTOCOL (conservative approach)
|
|
20574
20528
|
- PRIORITIZE your built-in knowledge and the provided context ABOVE to answer questions first.
|
|
20575
20529
|
- Use your training data and general knowledge confidently for common topics, concepts, and questions.
|
|
20576
|
-
- Only call tools for SPECIFIC, CURRENT information that requires real-time data:
|
|
20577
|
-
*
|
|
20578
|
-
*
|
|
20579
|
-
*
|
|
20530
|
+
- Only call tools for SPECIFIC, CURRENT information that requires real-time data or a source you don't already have:
|
|
20531
|
+
* web_search() - when asked about recent/current events, breaking news, live information (weather, prices, sports scores), or when you need to look up documentation, libraries, APIs, error messages, or verify a specific fact
|
|
20532
|
+
* web_fetch() - ONLY when you already have a specific URL whose contents you need to read
|
|
20533
|
+
* image_generation() - ONLY when explicitly asked to create or generate an image
|
|
20580
20534
|
- For general questions about concepts, definitions, explanations, or how-to topics, use your built-in knowledge WITHOUT calling tools.
|
|
20581
20535
|
- Examples of what NOT to use tools for: "who are you?", "what is React?", "explain machine learning", "how does X work?", general programming questions.
|
|
20582
20536
|
- When a tool is truly needed, call exactly ONE tool that best matches the request.
|
|
@@ -20588,11 +20542,11 @@ functionName({"param": "value"})
|
|
|
20588
20542
|
Examples of appropriate tool usage:
|
|
20589
20543
|
|
|
20590
20544
|
\`\`\`tool_code
|
|
20591
|
-
|
|
20545
|
+
web_search({"query": "latest AI developments 2026", "count": 5})
|
|
20592
20546
|
\`\`\`
|
|
20593
20547
|
|
|
20594
20548
|
\`\`\`tool_code
|
|
20595
|
-
|
|
20549
|
+
web_fetch({"url": "https://example.com/changelog"})
|
|
20596
20550
|
\`\`\`
|
|
20597
20551
|
`;
|
|
20598
20552
|
enhancedSystemPrompt += `
|
|
@@ -20635,6 +20589,7 @@ ${protocol}`;
|
|
|
20635
20589
|
if (openIdx !== -1) result = result.slice(0, openIdx);
|
|
20636
20590
|
return result.trimStart();
|
|
20637
20591
|
};
|
|
20592
|
+
const stripToolBlocks = (text) => text.replace(/```(?:tool_code|TOOL_CODE)\s*\n[\s\S]*?\n```/gi, "").trim();
|
|
20638
20593
|
const flushNow = () => {
|
|
20639
20594
|
clearFlushTimer();
|
|
20640
20595
|
if (!sawToolBlock) {
|
|
@@ -20708,6 +20663,8 @@ ${protocol}`;
|
|
|
20708
20663
|
}
|
|
20709
20664
|
const toolCallMatches = fullMessage.match(/```(?:tool_code|TOOL_CODE)\s*\n([^`]+)\n```/gi);
|
|
20710
20665
|
let enhancedMessage = fullMessage;
|
|
20666
|
+
const summarizableResults = [];
|
|
20667
|
+
const inlineImageBlocks = [];
|
|
20711
20668
|
if (toolCallMatches && toolCallMatches.length > 0 && mcpToolsAvailable) {
|
|
20712
20669
|
debugLogger.info("Detected tool calls in AI response", {
|
|
20713
20670
|
toolCallCount: toolCallMatches.length,
|
|
@@ -20748,47 +20705,43 @@ ${protocol}`;
|
|
|
20748
20705
|
});
|
|
20749
20706
|
let resultText = "";
|
|
20750
20707
|
if (result.success) {
|
|
20751
|
-
if (functionName === "
|
|
20752
|
-
const
|
|
20753
|
-
const
|
|
20754
|
-
const
|
|
20755
|
-
|
|
20756
|
-
|
|
20757
|
-
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
|
|
20761
|
-
|
|
20762
|
-
|
|
20763
|
-
|
|
20764
|
-
|
|
20765
|
-
|
|
20766
|
-
|
|
20767
|
-
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
|
|
20773
|
-
|
|
20774
|
-
const awayTokens = tokens(game.awayTeam);
|
|
20775
|
-
const hits = [...homeTokens, ...awayTokens].reduce(
|
|
20776
|
-
(acc, token) => acc + (q.includes(token) ? 1 : 0),
|
|
20777
|
-
0
|
|
20708
|
+
if (functionName === "web_search" || functionName === "web-search") {
|
|
20709
|
+
const search = result.data ?? {};
|
|
20710
|
+
const items = Array.isArray(search.results) ? search.results : [];
|
|
20711
|
+
const blocks = [];
|
|
20712
|
+
if (typeof search.answer === "string" && search.answer.trim().length > 0) {
|
|
20713
|
+
blocks.push(search.answer.trim());
|
|
20714
|
+
}
|
|
20715
|
+
if (items.length > 0) {
|
|
20716
|
+
blocks.push(
|
|
20717
|
+
items.slice(0, 6).map((item, index) => {
|
|
20718
|
+
const title = item.title?.trim() || "Untitled";
|
|
20719
|
+
const url = item.url?.trim();
|
|
20720
|
+
const snippet = item.content?.trim();
|
|
20721
|
+
let line = `${index + 1}. **${title}**`;
|
|
20722
|
+
if (url) line += `
|
|
20723
|
+
${url}`;
|
|
20724
|
+
if (snippet) {
|
|
20725
|
+
const truncated = snippet.length > 300 ? `${snippet.slice(0, 300)}\u2026` : snippet;
|
|
20726
|
+
line += `
|
|
20727
|
+
${truncated}`;
|
|
20728
|
+
}
|
|
20729
|
+
return line;
|
|
20730
|
+
}).join("\n\n")
|
|
20778
20731
|
);
|
|
20779
|
-
if (hits > bestScore) {
|
|
20780
|
-
bestScore = hits;
|
|
20781
|
-
best = game;
|
|
20782
|
-
}
|
|
20783
20732
|
}
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
|
|
20788
|
-
resultText =
|
|
20789
|
-
- ${topGames.map(scoreLine).join("\n- ")}`;
|
|
20733
|
+
resultText = blocks.length ? blocks.join("\n\n") : `No results found${search.query ? ` for "${search.query}"` : ""}.`;
|
|
20734
|
+
} else if (functionName === "web_fetch" || functionName === "web-fetch") {
|
|
20735
|
+
const fetched = result.data ?? {};
|
|
20736
|
+
if (fetched.blocked || fetched.error && !fetched.content) {
|
|
20737
|
+
resultText = fetched.error || "Unable to fetch that URL.";
|
|
20790
20738
|
} else {
|
|
20791
|
-
|
|
20739
|
+
const body = (fetched.content ?? "").trim();
|
|
20740
|
+
const preview = body.length > 2e3 ? `${body.slice(0, 2e3)}\u2026` : body;
|
|
20741
|
+
const source = fetched.url ? `**Source:** ${fetched.url}
|
|
20742
|
+
|
|
20743
|
+
` : "";
|
|
20744
|
+
resultText = preview ? `${source}${preview}` : `${source}No readable content found.`;
|
|
20792
20745
|
}
|
|
20793
20746
|
} else if (functionName === "image_generation" || functionName === "image-generation") {
|
|
20794
20747
|
const imageData = result.data ?? {};
|
|
@@ -20799,63 +20752,6 @@ ${protocol}`;
|
|
|
20799
20752
|
|
|
20800
20753
|
${revisedPrompt ? `Prompt refinement: \u201C${revisedPrompt}\u201D
|
|
20801
20754
|
` : ""}Note: the image link may expire in ~2 hours.` : "Image generated successfully.";
|
|
20802
|
-
} else if (functionName === "news" && Array.isArray(result.data)) {
|
|
20803
|
-
const items = result.data.slice(0, 3);
|
|
20804
|
-
resultText = items.length ? `## Top News Results
|
|
20805
|
-
|
|
20806
|
-
${items.map((item, index) => {
|
|
20807
|
-
const title = item.title ?? "Untitled";
|
|
20808
|
-
const source = item.source ?? "Unknown";
|
|
20809
|
-
const url = item.url ?? item.link;
|
|
20810
|
-
const description = item.description ?? item.summary;
|
|
20811
|
-
const publishedAt = item.publishedAt ?? item.published;
|
|
20812
|
-
let newsItem = `### ${index + 1}. ${title}
|
|
20813
|
-
`;
|
|
20814
|
-
if (typeof description === "string" && description.length > 0) {
|
|
20815
|
-
const truncated = description.length > 150 ? `${description.slice(0, 150)}...` : description;
|
|
20816
|
-
newsItem += `${truncated}
|
|
20817
|
-
|
|
20818
|
-
`;
|
|
20819
|
-
}
|
|
20820
|
-
newsItem += `**Source:** ${source}
|
|
20821
|
-
`;
|
|
20822
|
-
if (publishedAt) {
|
|
20823
|
-
const date = new Date(publishedAt);
|
|
20824
|
-
if (!Number.isNaN(date.getTime())) {
|
|
20825
|
-
newsItem += `**Published:** ${date.toLocaleDateString()} at ${date.toLocaleTimeString(
|
|
20826
|
-
[],
|
|
20827
|
-
{ hour: "2-digit", minute: "2-digit" }
|
|
20828
|
-
)}
|
|
20829
|
-
`;
|
|
20830
|
-
}
|
|
20831
|
-
}
|
|
20832
|
-
if (typeof url === "string" && url.length > 0) {
|
|
20833
|
-
newsItem += `
|
|
20834
|
-
**[\u{1F4F0} Read Full Article](${url})**
|
|
20835
|
-
`;
|
|
20836
|
-
}
|
|
20837
|
-
return newsItem;
|
|
20838
|
-
}).join("\n---\n\n")}` : "No news results found.";
|
|
20839
|
-
} else if (functionName === "docs" && Array.isArray(result.data)) {
|
|
20840
|
-
const items = result.data.slice(0, 3);
|
|
20841
|
-
resultText = items.length ? `Relevant docs:
|
|
20842
|
-
- ${items.map((item) => {
|
|
20843
|
-
const title = item.title ?? "Untitled doc";
|
|
20844
|
-
const url = item.url ?? item.link;
|
|
20845
|
-
return url ? `${title} \u2014 ${url}` : title;
|
|
20846
|
-
}).join("\n- ")}` : "No documentation results found.";
|
|
20847
|
-
} else if (functionName === "weather") {
|
|
20848
|
-
const weatherData = result.data ?? {};
|
|
20849
|
-
const informative = [weatherData.message, weatherData.details, weatherData.error].map((value) => typeof value === "string" ? value.trim() : void 0).filter((value) => Boolean(value) && value.toLowerCase() !== "n/a");
|
|
20850
|
-
if (informative.length > 0) {
|
|
20851
|
-
const locationLabel = typeof weatherData.location === "string" && weatherData.location.length > 0 ? ` for ${weatherData.location}` : "";
|
|
20852
|
-
resultText = `Weather service notice${locationLabel}: ${informative.join(" \u2014 ")}`;
|
|
20853
|
-
} else {
|
|
20854
|
-
const parts = [weatherData.location, weatherData.description, weatherData.temperature].map(
|
|
20855
|
-
(value) => typeof value === "number" || typeof value === "string" ? String(value).trim() : void 0
|
|
20856
|
-
).filter((value) => Boolean(value));
|
|
20857
|
-
resultText = parts.length ? parts.join(" \u2014 ") : "No weather data found.";
|
|
20858
|
-
}
|
|
20859
20755
|
} else if (typeof result.data === "string") {
|
|
20860
20756
|
resultText = result.data;
|
|
20861
20757
|
} else if (result.data) {
|
|
@@ -20866,16 +20762,16 @@ ${items.map((item, index) => {
|
|
|
20866
20762
|
} else {
|
|
20867
20763
|
const data = result.data ?? {};
|
|
20868
20764
|
const informative = [data.message, data.details, data.error, result.error].map((value) => typeof value === "string" ? value.trim() : void 0).filter((value) => Boolean(value) && value.toLowerCase() !== "n/a");
|
|
20869
|
-
|
|
20870
|
-
const locationLabel = typeof data.location === "string" && data.location.length > 0 ? ` for ${data.location}` : "";
|
|
20871
|
-
resultText = `Weather service issue${locationLabel}: ${informative.join(" \u2014 ")}`;
|
|
20872
|
-
} else if (informative.length) {
|
|
20873
|
-
resultText = informative.join(" \u2014 ");
|
|
20874
|
-
} else {
|
|
20875
|
-
resultText = `I couldn't complete that request: ${result.error || "Unknown error"}.`;
|
|
20876
|
-
}
|
|
20765
|
+
resultText = informative.length ? informative.join(" \u2014 ") : `I couldn't complete that request: ${result.error || "Unknown error"}.`;
|
|
20877
20766
|
}
|
|
20878
20767
|
enhancedMessage = enhancedMessage.replace(placeholderToken, resultText);
|
|
20768
|
+
if (result.success) {
|
|
20769
|
+
if (functionName === "image_generation" || functionName === "image-generation") {
|
|
20770
|
+
inlineImageBlocks.push(resultText);
|
|
20771
|
+
} else if (functionName !== "check_gateway_health") {
|
|
20772
|
+
summarizableResults.push({ name: functionName, output: resultText });
|
|
20773
|
+
}
|
|
20774
|
+
}
|
|
20879
20775
|
debugLogger.info("Tool execution completed", {
|
|
20880
20776
|
functionName,
|
|
20881
20777
|
success: result.success,
|
|
@@ -20898,6 +20794,65 @@ ${items.map((item, index) => {
|
|
|
20898
20794
|
}
|
|
20899
20795
|
}
|
|
20900
20796
|
}
|
|
20797
|
+
if (summarizableResults.length > 0) {
|
|
20798
|
+
try {
|
|
20799
|
+
const toolResultsText = summarizableResults.map((r) => `## ${r.name}
|
|
20800
|
+
${r.output}`).join("\n\n");
|
|
20801
|
+
const summaryMessages = [
|
|
20802
|
+
{ role: "system", content: systemPromptForSummary },
|
|
20803
|
+
...contextMessages,
|
|
20804
|
+
{ role: "user", content: question },
|
|
20805
|
+
{ role: "assistant", content: stripToolBlocks(fullMessage) || "Let me look that up." },
|
|
20806
|
+
{
|
|
20807
|
+
role: "user",
|
|
20808
|
+
content: `I ran the tool(s) you requested. Here are the raw results:
|
|
20809
|
+
|
|
20810
|
+
${toolResultsText}
|
|
20811
|
+
|
|
20812
|
+
Using these results together with your own knowledge, answer my original question concisely and in a natural, well-formatted way. Cite source URLs inline when you rely on them. Do NOT output tool_code or call any tools again.`
|
|
20813
|
+
}
|
|
20814
|
+
];
|
|
20815
|
+
const summaryRequest = {
|
|
20816
|
+
model: modelName,
|
|
20817
|
+
messages: summaryMessages,
|
|
20818
|
+
stream: true,
|
|
20819
|
+
options: { num_predict: tokenLimit + 250 }
|
|
20820
|
+
};
|
|
20821
|
+
clearFlushTimer();
|
|
20822
|
+
setStreamBuffer("");
|
|
20823
|
+
const summaryText = await new Promise((resolve) => {
|
|
20824
|
+
let acc = "";
|
|
20825
|
+
const summarySub = provider.chat(summaryRequest).subscribe({
|
|
20826
|
+
next: (data) => {
|
|
20827
|
+
if (data?.message?.content) {
|
|
20828
|
+
acc += data.message.content;
|
|
20829
|
+
const visible = stripThinking(acc);
|
|
20830
|
+
latestDisplayMessage = visible;
|
|
20831
|
+
lastPartialRef.current.text = visible;
|
|
20832
|
+
setStreamBuffer(visible);
|
|
20833
|
+
}
|
|
20834
|
+
},
|
|
20835
|
+
error: (summaryErr) => {
|
|
20836
|
+
debugLogger.error("Summarization pass failed", {
|
|
20837
|
+
error: summaryErr instanceof Error ? summaryErr.message : String(summaryErr)
|
|
20838
|
+
});
|
|
20839
|
+
resolve("");
|
|
20840
|
+
},
|
|
20841
|
+
complete: () => resolve(stripThinking(acc).trim())
|
|
20842
|
+
});
|
|
20843
|
+
currentSubRef.current = summarySub;
|
|
20844
|
+
});
|
|
20845
|
+
if (summaryText.trim()) {
|
|
20846
|
+
enhancedMessage = summaryText + (inlineImageBlocks.length ? `
|
|
20847
|
+
|
|
20848
|
+
${inlineImageBlocks.join("\n\n")}` : "");
|
|
20849
|
+
}
|
|
20850
|
+
} catch (summaryError) {
|
|
20851
|
+
debugLogger.error("Summarization pass threw", {
|
|
20852
|
+
error: summaryError instanceof Error ? summaryError.message : String(summaryError)
|
|
20853
|
+
});
|
|
20854
|
+
}
|
|
20855
|
+
}
|
|
20901
20856
|
}
|
|
20902
20857
|
overrideComponentStatus("Idle");
|
|
20903
20858
|
setIsSubmitting(false);
|
|
@@ -28245,7 +28200,7 @@ var init_ConnectionStatus = __esm({
|
|
|
28245
28200
|
});
|
|
28246
28201
|
|
|
28247
28202
|
// src/hooks/useVoiceMode.ts
|
|
28248
|
-
var import_react35, RMS_BASELINE, RMS_NORMALIZER, computeRms, useVoiceMode;
|
|
28203
|
+
var import_react35, RMS_BASELINE, RMS_NORMALIZER, computeRms, pickSupportedMimeType, useVoiceMode;
|
|
28249
28204
|
var init_useVoiceMode = __esm({
|
|
28250
28205
|
"src/hooks/useVoiceMode.ts"() {
|
|
28251
28206
|
"use strict";
|
|
@@ -28263,6 +28218,19 @@ var init_useVoiceMode = __esm({
|
|
|
28263
28218
|
}
|
|
28264
28219
|
return Math.sqrt(sumSquares / data.length);
|
|
28265
28220
|
};
|
|
28221
|
+
pickSupportedMimeType = () => {
|
|
28222
|
+
if (typeof MediaRecorder === "undefined" || typeof MediaRecorder.isTypeSupported !== "function") {
|
|
28223
|
+
return void 0;
|
|
28224
|
+
}
|
|
28225
|
+
const candidates = [
|
|
28226
|
+
"audio/webm;codecs=opus",
|
|
28227
|
+
"audio/webm",
|
|
28228
|
+
"audio/mp4;codecs=mp4a.40.2",
|
|
28229
|
+
"audio/mp4",
|
|
28230
|
+
"audio/aac"
|
|
28231
|
+
];
|
|
28232
|
+
return candidates.find((type) => MediaRecorder.isTypeSupported(type));
|
|
28233
|
+
};
|
|
28266
28234
|
useVoiceMode = (config) => {
|
|
28267
28235
|
const enabled = useVoiceModeStore((state) => state.enabled);
|
|
28268
28236
|
const setStatus = useVoiceModeStore((state) => state.setStatus);
|
|
@@ -28286,10 +28254,15 @@ var init_useVoiceMode = __esm({
|
|
|
28286
28254
|
let silenceStartAt = 0;
|
|
28287
28255
|
const isRecordingRef = { current: false };
|
|
28288
28256
|
const isProcessingRef = { current: false };
|
|
28257
|
+
let removeResumeListeners = null;
|
|
28289
28258
|
const amplitudeThreshold = configRef.current.amplitudeThreshold ?? 0.025;
|
|
28290
28259
|
const minSpeechMs = configRef.current.minSpeechMs ?? 180;
|
|
28291
28260
|
const minSilenceMs = configRef.current.minSilenceMs ?? 720;
|
|
28292
28261
|
const clearAudioSession = async () => {
|
|
28262
|
+
if (removeResumeListeners) {
|
|
28263
|
+
removeResumeListeners();
|
|
28264
|
+
removeResumeListeners = null;
|
|
28265
|
+
}
|
|
28293
28266
|
if (rafId) {
|
|
28294
28267
|
cancelAnimationFrame(rafId);
|
|
28295
28268
|
rafId = null;
|
|
@@ -28381,7 +28354,8 @@ var init_useVoiceMode = __esm({
|
|
|
28381
28354
|
const startRecording = (stream) => {
|
|
28382
28355
|
chunks = [];
|
|
28383
28356
|
try {
|
|
28384
|
-
|
|
28357
|
+
const mimeType = pickSupportedMimeType();
|
|
28358
|
+
recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
|
|
28385
28359
|
recorder.addEventListener("dataavailable", (event) => {
|
|
28386
28360
|
if (event.data && event.data.size > 0) {
|
|
28387
28361
|
chunks.push(event.data);
|
|
@@ -28475,6 +28449,28 @@ var init_useVoiceMode = __esm({
|
|
|
28475
28449
|
dataArray
|
|
28476
28450
|
};
|
|
28477
28451
|
resetTransientState();
|
|
28452
|
+
if (audioContext.state === "suspended") {
|
|
28453
|
+
try {
|
|
28454
|
+
await audioContext.resume();
|
|
28455
|
+
} catch (resumeError) {
|
|
28456
|
+
debugLogger.warn("Voice mode audio context resume failed", { error: resumeError });
|
|
28457
|
+
}
|
|
28458
|
+
}
|
|
28459
|
+
if (!cancelled && audioContext.state === "suspended") {
|
|
28460
|
+
const resumeOnGesture = () => {
|
|
28461
|
+
audioContext.resume().catch(() => void 0);
|
|
28462
|
+
};
|
|
28463
|
+
const gestureEvents = ["touchend", "pointerdown", "click"];
|
|
28464
|
+
gestureEvents.forEach(
|
|
28465
|
+
(evt) => window.addEventListener(evt, resumeOnGesture, { once: true, passive: true })
|
|
28466
|
+
);
|
|
28467
|
+
removeResumeListeners = () => {
|
|
28468
|
+
gestureEvents.forEach((evt) => window.removeEventListener(evt, resumeOnGesture));
|
|
28469
|
+
};
|
|
28470
|
+
}
|
|
28471
|
+
if (cancelled) {
|
|
28472
|
+
return;
|
|
28473
|
+
}
|
|
28478
28474
|
monitorAudio();
|
|
28479
28475
|
} catch (error) {
|
|
28480
28476
|
debugLogger.error("Voice mode failed to initialize microphone", {
|