@burtson-labs/bandit-engine 2.0.148 → 2.0.150

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/index.js CHANGED
@@ -11424,6 +11424,46 @@ var init_lucide_icons = __esm({
11424
11424
  }
11425
11425
  });
11426
11426
 
11427
+ // src/utils/openFileLink.ts
11428
+ var FILE_EXT_RE, isStandalonePwa, isFileLink, maybeHandleFileLinkClick;
11429
+ var init_openFileLink = __esm({
11430
+ "src/utils/openFileLink.ts"() {
11431
+ "use strict";
11432
+ init_debugLogger();
11433
+ FILE_EXT_RE = /\.(docx|pptx|xlsx|csv|json|md|txt|html|xml|ya?ml|pdf|zip)(?:[?#]|$)/i;
11434
+ isStandalonePwa = () => typeof window !== "undefined" && (window.matchMedia?.("(display-mode: standalone)").matches || window.navigator.standalone === true);
11435
+ isFileLink = (href) => Boolean(href && FILE_EXT_RE.test(href));
11436
+ maybeHandleFileLinkClick = (event, href) => {
11437
+ if (!href || !isStandalonePwa() || !isFileLink(href)) return;
11438
+ event.preventDefault();
11439
+ void (async () => {
11440
+ try {
11441
+ const res = await fetch(href);
11442
+ if (!res.ok) throw new Error(`fetch ${res.status}`);
11443
+ const blob = await res.blob();
11444
+ const rawName = new URL(href, window.location.href).pathname.split("/").pop() || "download";
11445
+ const name = decodeURIComponent(rawName);
11446
+ const file = new File([blob], name, {
11447
+ type: blob.type || "application/octet-stream"
11448
+ });
11449
+ const nav = navigator;
11450
+ if (nav.canShare?.({ files: [file] }) && nav.share) {
11451
+ await nav.share({ files: [file], title: name });
11452
+ return;
11453
+ }
11454
+ window.location.href = URL.createObjectURL(blob);
11455
+ } catch (error) {
11456
+ debugLogger.warn("openFileLink: share flow failed, falling back", {
11457
+ error: error instanceof Error ? error.message : String(error)
11458
+ });
11459
+ if (error?.name === "AbortError") return;
11460
+ window.open(href, "_blank", "noopener");
11461
+ }
11462
+ })();
11463
+ };
11464
+ }
11465
+ });
11466
+
11427
11467
  // src/components/StreamingMarkdown.tsx
11428
11468
  var import_react10, import_material4, import_react_markdown, import_remark_gfm, import_rehype_raw, import_rehype_sanitize2, import_styles2, import_jsx_runtime6, StreamingMarkdown, arePropsEqual, StreamingMarkdown_default;
11429
11469
  var init_StreamingMarkdown = __esm({
@@ -11439,6 +11479,7 @@ var init_StreamingMarkdown = __esm({
11439
11479
  init_lowlight();
11440
11480
  init_markdownRendering();
11441
11481
  init_lucide_icons();
11482
+ init_openFileLink();
11442
11483
  import_jsx_runtime6 = require("react/jsx-runtime");
11443
11484
  StreamingMarkdown = ({
11444
11485
  content,
@@ -11592,6 +11633,7 @@ ${listMarkdown}`;
11592
11633
  href,
11593
11634
  target: "_blank",
11594
11635
  rel: "noopener noreferrer",
11636
+ onClick: (e) => maybeHandleFileLinkClick(e, href),
11595
11637
  style: {
11596
11638
  color: theme.palette.info?.main ?? theme.palette.primary.main,
11597
11639
  textDecoration: "underline",
@@ -14509,6 +14551,7 @@ var init_ai_response_text_field = __esm({
14509
14551
  init_lowlight();
14510
14552
  init_markdownRendering();
14511
14553
  init_lucide_icons();
14554
+ init_openFileLink();
14512
14555
  init_ai_response_action_bar();
14513
14556
  import_jsx_runtime13 = require("react/jsx-runtime");
14514
14557
  brainIcon = "https://cdn.burtson.ai/images/brain-icon.png";
@@ -14941,6 +14984,7 @@ ${sourcesMarkdownList.join("\n")}`;
14941
14984
  },
14942
14985
  target: "_blank",
14943
14986
  rel: "noopener noreferrer",
14987
+ onClick: (e) => maybeHandleFileLinkClick(e, href),
14944
14988
  children
14945
14989
  }
14946
14990
  );
@@ -20990,6 +21034,10 @@ ${protocol}`;
20990
21034
  /\b(?:web_search|web_fetch|image_generation|create_file|ask_user)\s*\(/
20991
21035
  );
20992
21036
  if (callIdx !== -1) t = t.slice(0, callIdx);
21037
+ const jsonIdx = t.search(
21038
+ /\{\s*"name"\s*:\s*"(?:web_search|web_fetch|image_generation|create_file|ask_user)"/
21039
+ );
21040
+ if (jsonIdx !== -1) t = t.slice(0, jsonIdx);
20993
21041
  t = t.replace(/```[\w-]*\s*$/, "");
20994
21042
  const fenceCount = (t.match(/```/g) || []).length;
20995
21043
  if (fenceCount % 2 === 1) t = t.slice(0, t.lastIndexOf("```"));
@@ -21055,6 +21103,9 @@ ${protocol}`;
21055
21103
  const visibleMessage = stripThinking(fullMessage);
21056
21104
  const bareToolMatch = visibleMessage.match(
21057
21105
  /\b(web_search|web_fetch|image_generation|create_file|ask_user)\s*\(/
21106
+ ) || // JSON-form calls from cloud/native-tool engines.
21107
+ visibleMessage.match(
21108
+ /\{\s*"name"\s*:\s*"(web_search|web_fetch|image_generation|create_file|ask_user)"/
21058
21109
  );
21059
21110
  if (/```(?:tool_code|TOOL_CODE)/.test(visibleMessage) || bareToolMatch) {
21060
21111
  sawToolBlock = true;
@@ -21182,6 +21233,70 @@ ${fn}(${argStr})
21182
21233
  }
21183
21234
  return out;
21184
21235
  };
21236
+ const bridgeJsonToolBlobs = (message) => {
21237
+ const KNOWN = ["web_search", "web_fetch", "image_generation", "create_file", "ask_user", "ask-user"];
21238
+ const re = new RegExp(`\\{\\s*"name"\\s*:\\s*"(${KNOWN.join("|")})"`, "g");
21239
+ const spans = [];
21240
+ let m;
21241
+ while ((m = re.exec(message)) !== null) {
21242
+ let depth = 0;
21243
+ let i = m.index;
21244
+ let inStr = false;
21245
+ let esc = false;
21246
+ for (; i < message.length; i++) {
21247
+ const ch = message[i];
21248
+ if (esc) {
21249
+ esc = false;
21250
+ continue;
21251
+ }
21252
+ if (ch === "\\") {
21253
+ esc = true;
21254
+ continue;
21255
+ }
21256
+ if (ch === '"') {
21257
+ inStr = !inStr;
21258
+ continue;
21259
+ }
21260
+ if (inStr) continue;
21261
+ if (ch === "{") depth++;
21262
+ else if (ch === "}") {
21263
+ depth--;
21264
+ if (depth === 0) {
21265
+ i++;
21266
+ break;
21267
+ }
21268
+ }
21269
+ }
21270
+ const blob = message.slice(m.index, i);
21271
+ try {
21272
+ const parsed = JSON.parse(blob);
21273
+ const args = parsed.arguments ?? parsed.parameters ?? parsed.input ?? {};
21274
+ let start = m.index;
21275
+ let end = i;
21276
+ const fenceOpen = message.slice(0, start).match(/```[a-zA-Z0-9_-]*[ \t]*\n[ \t]*$/);
21277
+ if (fenceOpen) {
21278
+ start -= fenceOpen[0].length;
21279
+ const fenceClose = message.slice(end).match(/^[ \t]*\n?```/);
21280
+ if (fenceClose) end += fenceClose[0].length;
21281
+ }
21282
+ spans.push({
21283
+ start,
21284
+ end,
21285
+ fn: parsed.name,
21286
+ args: typeof args === "string" ? args : JSON.stringify(args)
21287
+ });
21288
+ } catch {
21289
+ }
21290
+ re.lastIndex = i;
21291
+ }
21292
+ let result = message;
21293
+ for (let k = spans.length - 1; k >= 0; k--) {
21294
+ const s = spans[k];
21295
+ result = result.slice(0, s.start) + "\n```tool_code\n" + s.fn + "(" + s.args + ")\n```\n" + result.slice(s.end);
21296
+ }
21297
+ return result;
21298
+ };
21299
+ fullMessage = bridgeJsonToolBlobs(fullMessage);
21185
21300
  const toolCallMatches = extractToolCalls(fullMessage);
21186
21301
  let enhancedMessage = fullMessage;
21187
21302
  const summarizableResults = [];