@bike4mind/cli 0.2.31-feat-wolfram-alpha-tool.19431 → 0.2.31-feat-cli-websocket-streaming.19470

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.
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  HydrationEngine,
4
4
  createHydrationEngine
5
- } from "./chunk-RUI6HNLO.js";
5
+ } from "./chunk-GQGOWACU.js";
6
6
  export {
7
7
  HydrationEngine,
8
8
  createHydrationEngine
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-HP6AES2S.js";
4
+ } from "./chunk-2HFZJMGD.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/artifactExtractor.js
7
7
  var ARTIFACT_TAG_REGEX = /<artifact\s+(.*?)>([\s\S]*?)<\/artifact>/gi;
@@ -307,7 +307,6 @@ var b4mLLMTools = z5.enum([
307
307
  "weather_info",
308
308
  "web_search",
309
309
  "web_fetch",
310
- "wolfram_alpha",
311
310
  "math_evaluate",
312
311
  "mermaid_chart",
313
312
  "current_datetime",
@@ -327,6 +326,8 @@ var b4mLLMTools = z5.enum([
327
326
  // Knowledge base search
328
327
  "search_knowledge_base",
329
328
  "retrieve_knowledge_content",
329
+ // Agent delegation
330
+ "delegate_to_agent",
330
331
  // Quantum optimization tools
331
332
  "quantum_schedule",
332
333
  "quantum_formulate",
@@ -1216,6 +1217,29 @@ var VoiceSessionSendTranscriptAction = z10.object({
1216
1217
  conversationItemId: z10.string(),
1217
1218
  timestamp: z10.coerce.date().optional()
1218
1219
  });
1220
+ var CliCompletionRequestAction = z10.object({
1221
+ action: z10.literal("cli_completion_request"),
1222
+ accessToken: z10.string(),
1223
+ requestId: z10.string().uuid(),
1224
+ model: z10.string(),
1225
+ messages: z10.array(z10.object({
1226
+ role: z10.enum(["user", "assistant", "system"]),
1227
+ content: z10.union([z10.string(), z10.array(z10.unknown())])
1228
+ })),
1229
+ options: z10.object({
1230
+ temperature: z10.number().optional(),
1231
+ maxTokens: z10.number().optional(),
1232
+ stream: z10.boolean().optional(),
1233
+ tools: z10.array(z10.unknown()).optional()
1234
+ }).optional()
1235
+ });
1236
+ var CliToolRequestAction = z10.object({
1237
+ action: z10.literal("cli_tool_request"),
1238
+ accessToken: z10.string(),
1239
+ requestId: z10.string().uuid(),
1240
+ toolName: z10.string(),
1241
+ input: z10.record(z10.unknown())
1242
+ });
1219
1243
  var VoiceSessionEndedAction = z10.object({
1220
1244
  action: z10.literal("voice_session_ended"),
1221
1245
  userId: z10.string(),
@@ -1504,6 +1528,36 @@ var VoiceCreditsExhaustedAction = z10.object({
1504
1528
  creditsUsed: z10.number(),
1505
1529
  clientId: z10.string().optional()
1506
1530
  });
1531
+ var CliCompletionChunkAction = z10.object({
1532
+ action: z10.literal("cli_completion_chunk"),
1533
+ requestId: z10.string(),
1534
+ chunk: z10.object({
1535
+ type: z10.enum(["content", "tool_use"]),
1536
+ text: z10.string(),
1537
+ tools: z10.array(z10.unknown()).optional(),
1538
+ usage: z10.object({
1539
+ inputTokens: z10.number().optional(),
1540
+ outputTokens: z10.number().optional()
1541
+ }).optional(),
1542
+ thinking: z10.array(z10.unknown()).optional()
1543
+ })
1544
+ });
1545
+ var CliCompletionDoneAction = z10.object({
1546
+ action: z10.literal("cli_completion_done"),
1547
+ requestId: z10.string()
1548
+ });
1549
+ var CliCompletionErrorAction = z10.object({
1550
+ action: z10.literal("cli_completion_error"),
1551
+ requestId: z10.string(),
1552
+ error: z10.string()
1553
+ });
1554
+ var CliToolResponseAction = z10.object({
1555
+ action: z10.literal("cli_tool_response"),
1556
+ requestId: z10.string(),
1557
+ success: z10.boolean(),
1558
+ content: z10.unknown().optional(),
1559
+ error: z10.string().optional()
1560
+ });
1507
1561
  var SessionCreatedAction = shareableDocumentSchema.extend({
1508
1562
  action: z10.literal("session.created"),
1509
1563
  id: z10.string(),
@@ -1538,7 +1592,9 @@ var MessageDataToServer = z10.discriminatedUnion("action", [
1538
1592
  DataUnsubscribeRequestAction,
1539
1593
  HeartbeatAction,
1540
1594
  VoiceSessionSendTranscriptAction,
1541
- VoiceSessionEndedAction
1595
+ VoiceSessionEndedAction,
1596
+ CliCompletionRequestAction,
1597
+ CliToolRequestAction
1542
1598
  ]);
1543
1599
  var MessageDataToClient = z10.discriminatedUnion("action", [
1544
1600
  DataSubscriptionUpdateAction,
@@ -1564,7 +1620,11 @@ var MessageDataToClient = z10.discriminatedUnion("action", [
1564
1620
  PiHistoryCompleteAction,
1565
1621
  PiHistoryErrorAction,
1566
1622
  SessionCreatedAction,
1567
- VoiceCreditsExhaustedAction
1623
+ VoiceCreditsExhaustedAction,
1624
+ CliCompletionChunkAction,
1625
+ CliCompletionDoneAction,
1626
+ CliCompletionErrorAction,
1627
+ CliToolResponseAction
1568
1628
  ]);
1569
1629
 
1570
1630
  // ../../b4m-core/packages/common/dist/src/schemas/cliCompletions.js
@@ -2441,7 +2501,6 @@ var SettingKeySchema = z21.enum([
2441
2501
  "SystemFiles",
2442
2502
  "OpenWeatherKey",
2443
2503
  "SerperKey",
2444
- "WolframAlphaKey",
2445
2504
  "VectorThreshold",
2446
2505
  "bflApiKey",
2447
2506
  "EnableMCPServer",
@@ -2879,13 +2938,10 @@ var API_SERVICE_GROUPS = {
2879
2938
  },
2880
2939
  SEARCH: {
2881
2940
  id: "searchAPIService",
2882
- name: "Search & Compute",
2883
- description: "Search and computational API integration settings",
2941
+ name: "Search Service",
2942
+ description: "Serper Search API integration settings",
2884
2943
  icon: "Search",
2885
- settings: [
2886
- { key: "SerperKey", order: 1 },
2887
- { key: "WolframAlphaKey", order: 2 }
2888
- ]
2944
+ settings: [{ key: "SerperKey", order: 1 }]
2889
2945
  },
2890
2946
  CALENDAR: {
2891
2947
  id: "calendarAPIService",
@@ -3668,16 +3724,6 @@ var settingsMap = {
3668
3724
  order: 1,
3669
3725
  isSensitive: true
3670
3726
  }),
3671
- WolframAlphaKey: makeStringSetting({
3672
- key: "WolframAlphaKey",
3673
- name: "Wolfram Alpha API Key",
3674
- defaultValue: "",
3675
- description: "The AppID for Wolfram Alpha LLM API. Get one at developer.wolframalpha.com.",
3676
- category: "Tools",
3677
- group: API_SERVICE_GROUPS.SEARCH.id,
3678
- order: 2,
3679
- isSensitive: true
3680
- }),
3681
3727
  VectorThreshold: makeNumberSetting({
3682
3728
  key: "VectorThreshold",
3683
3729
  name: "Vector Threshold",
@@ -9388,7 +9434,16 @@ var VIEW_REGISTRY = [
9388
9434
  description: "Configure which solvers to race \u2014 greedy, simulated annealing, tabu search, genetic algorithm, ant colony",
9389
9435
  navigationType: "action",
9390
9436
  target: "scheduling.solvers",
9391
- keywords: ["solvers", "tabu", "simulated annealing", "genetic algorithm", "ant colony", "greedy", "solver race", "configure solvers"]
9437
+ keywords: [
9438
+ "solvers",
9439
+ "tabu",
9440
+ "simulated annealing",
9441
+ "genetic algorithm",
9442
+ "ant colony",
9443
+ "greedy",
9444
+ "solver race",
9445
+ "configure solvers"
9446
+ ]
9392
9447
  },
9393
9448
  {
9394
9449
  id: "opti.scheduling.results",
@@ -9397,7 +9452,15 @@ var VIEW_REGISTRY = [
9397
9452
  description: "View solver race results \u2014 progress, best schedule, makespan comparison, utilization",
9398
9453
  navigationType: "action",
9399
9454
  target: "scheduling.results",
9400
- keywords: ["results", "race results", "makespan", "comparison", "best schedule", "utilization", "solver comparison"]
9455
+ keywords: [
9456
+ "results",
9457
+ "race results",
9458
+ "makespan",
9459
+ "comparison",
9460
+ "best schedule",
9461
+ "utilization",
9462
+ "solver comparison"
9463
+ ]
9401
9464
  },
9402
9465
  {
9403
9466
  id: "opti.scheduling.gantt",
@@ -10147,6 +10210,8 @@ export {
10147
10210
  DataUnsubscribeRequestAction,
10148
10211
  HeartbeatAction,
10149
10212
  VoiceSessionSendTranscriptAction,
10213
+ CliCompletionRequestAction,
10214
+ CliToolRequestAction,
10150
10215
  VoiceSessionEndedAction,
10151
10216
  DataSubscriptionUpdateAction,
10152
10217
  LLMStatusUpdateAction,
@@ -10171,6 +10236,10 @@ export {
10171
10236
  ImportHistoryJobProgressUpdateAction,
10172
10237
  ResearchModeStreamAction,
10173
10238
  VoiceCreditsExhaustedAction,
10239
+ CliCompletionChunkAction,
10240
+ CliCompletionDoneAction,
10241
+ CliCompletionErrorAction,
10242
+ CliToolResponseAction,
10174
10243
  SessionCreatedAction,
10175
10244
  MessageDataToServer,
10176
10245
  MessageDataToClient,
@@ -595,12 +595,13 @@ var HydrationEngine = class {
595
595
  return numericInputs[0] / numericInputs[1];
596
596
  case "ABS":
597
597
  return numericInputs.length > 0 ? Math.abs(numericInputs[0]) : 0;
598
- case "ROUND":
598
+ case "ROUND": {
599
599
  if (numericInputs.length === 0)
600
600
  return 0;
601
601
  const decimals = numericInputs[1] ?? 0;
602
602
  const factor = Math.pow(10, decimals);
603
603
  return Math.round(numericInputs[0] * factor) / factor;
604
+ }
604
605
  case "FLOOR":
605
606
  return numericInputs.length > 0 ? Math.floor(numericInputs[0]) : 0;
606
607
  case "CEIL":
@@ -624,12 +625,13 @@ var HydrationEngine = class {
624
625
  return numericInputs.length > 0 ? Math.max(...numericInputs) : 0;
625
626
  case "COUNT":
626
627
  return inputs.filter((v) => v !== null).length;
627
- case "MEDIAN":
628
+ case "MEDIAN": {
628
629
  if (numericInputs.length === 0)
629
630
  return 0;
630
631
  const sorted = [...numericInputs].sort((a, b) => a - b);
631
632
  const mid = Math.floor(sorted.length / 2);
632
633
  return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
634
+ }
633
635
  // Logical
634
636
  case "IF":
635
637
  return inputs[0] ? inputs[1] : inputs[2];
@@ -649,13 +651,14 @@ var HydrationEngine = class {
649
651
  return inputs.length >= 2 && inputs[0] >= inputs[1];
650
652
  case "LESS_THAN_OR_EQUAL":
651
653
  return inputs.length >= 2 && inputs[0] <= inputs[1];
652
- case "BETWEEN":
654
+ case "BETWEEN": {
653
655
  if (inputs.length < 3)
654
656
  return false;
655
657
  const val = inputs[0];
656
658
  const min = inputs[1];
657
659
  const max = inputs[2];
658
660
  return val >= min && val <= max;
661
+ }
659
662
  // Financial
660
663
  case "PERCENT_OF":
661
664
  if (numericInputs.length < 2 || numericInputs[1] === 0)
@@ -714,11 +717,12 @@ var HydrationEngine = class {
714
717
  case "REFERENCE":
715
718
  return inputs[0];
716
719
  // Pass through
717
- case "LOOKUP":
720
+ case "LOOKUP": {
718
721
  if (inputs.length < 2)
719
722
  return null;
720
723
  const index = inputs[0];
721
724
  return inputs[Math.min(index + 1, inputs.length - 1)];
725
+ }
722
726
  default:
723
727
  context.errors.push({
724
728
  type: "INVALID_OPERATION",
@@ -7,11 +7,11 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-Z5CU4KFU.js";
10
+ } from "./chunk-SYJA4DXH.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
14
- } from "./chunk-HP6AES2S.js";
14
+ } from "./chunk-2HFZJMGD.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/fabFileService/create.js
17
17
  import { z } from "zod";
@@ -6,12 +6,12 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-Z5CU4KFU.js";
9
+ } from "./chunk-SYJA4DXH.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
13
13
  isSupportedEmbeddingModel
14
- } from "./chunk-HP6AES2S.js";
14
+ } from "./chunk-2HFZJMGD.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
17
17
  import { z } from "zod";
@@ -62,11 +62,6 @@ var getOpenWeatherKey = async (adapters) => {
62
62
  const settings = await db.adminSettings.findBySettingName("OpenWeatherKey");
63
63
  return settings?.settingValue;
64
64
  };
65
- var getWolframAlphaKey = async (adapters) => {
66
- const { db } = adapters;
67
- const settings = await db.adminSettings.findBySettingName("WolframAlphaKey");
68
- return settings?.settingValue;
69
- };
70
65
  var getEffectiveApiKey = async (userId, params, adapters) => {
71
66
  const { db } = adapters;
72
67
  const apiKey = await getApiKey(userId, params, adapters);
@@ -234,7 +229,6 @@ function findMostSimilarMemento(targetEmbedding, mementos) {
234
229
  export {
235
230
  getSerperKey,
236
231
  getOpenWeatherKey,
237
- getWolframAlphaKey,
238
232
  getEffectiveApiKey,
239
233
  getRelevantMementos,
240
234
  findMostSimilarMemento
@@ -16,7 +16,7 @@ import {
16
16
  dayjsConfig_default,
17
17
  extractSnippetMeta,
18
18
  settingsMap
19
- } from "./chunk-HP6AES2S.js";
19
+ } from "./chunk-2HFZJMGD.js";
20
20
  import {
21
21
  Logger
22
22
  } from "./chunk-OCYRD7D6.js";
@@ -591,6 +591,125 @@ function getSettingsCacheStats() {
591
591
  // ../../b4m-core/packages/utils/dist/src/ingest.js
592
592
  import axios from "axios";
593
593
  import mime2 from "mime-types";
594
+
595
+ // ../../b4m-core/packages/utils/dist/src/ssrfProtection.js
596
+ import dns from "dns";
597
+ import { promisify } from "util";
598
+ var dnsResolve4 = promisify(dns.resolve4);
599
+ var dnsResolve6 = promisify(dns.resolve6);
600
+ function isPrivateIPv4(ip) {
601
+ const ipv4Match = ip.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
602
+ if (!ipv4Match)
603
+ return false;
604
+ const [, a, b, c] = ipv4Match.map(Number);
605
+ if (a === 10)
606
+ return true;
607
+ if (a === 172 && b >= 16 && b <= 31)
608
+ return true;
609
+ if (a === 192 && b === 168)
610
+ return true;
611
+ if (a === 127)
612
+ return true;
613
+ if (a === 169 && b === 254)
614
+ return true;
615
+ if (a === 0)
616
+ return true;
617
+ if (a === 100 && b >= 64 && b <= 127)
618
+ return true;
619
+ if (a === 192 && b === 0 && c === 0)
620
+ return true;
621
+ if (a === 192 && b === 0 && c === 2 || a === 198 && b === 51 && c === 100 || a === 203 && b === 0 && c === 113)
622
+ return true;
623
+ if (a >= 224 && a <= 239)
624
+ return true;
625
+ if (a >= 240)
626
+ return true;
627
+ return false;
628
+ }
629
+ function isPrivateIPv6(ip) {
630
+ const normalized = ip.toLowerCase();
631
+ if (normalized === "::1" || normalized === "0:0:0:0:0:0:0:1")
632
+ return true;
633
+ if (normalized === "::" || normalized === "0:0:0:0:0:0:0:0")
634
+ return true;
635
+ if (normalized.startsWith("fe8") || normalized.startsWith("fe9") || normalized.startsWith("fea") || normalized.startsWith("feb"))
636
+ return true;
637
+ if (normalized.startsWith("fc") || normalized.startsWith("fd"))
638
+ return true;
639
+ if (normalized.startsWith("ff"))
640
+ return true;
641
+ const ipv4MappedMatch = normalized.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
642
+ if (ipv4MappedMatch) {
643
+ return isPrivateIPv4(ipv4MappedMatch[1]);
644
+ }
645
+ if (normalized.startsWith("2001:db8:") || normalized.startsWith("2001:0db8:"))
646
+ return true;
647
+ if (normalized.startsWith("100::") || normalized.startsWith("0100::"))
648
+ return true;
649
+ if (normalized.startsWith("64:ff9b:") || normalized.startsWith("0064:ff9b:"))
650
+ return true;
651
+ return false;
652
+ }
653
+ function isPrivateIP(ip) {
654
+ if (/^(\d{1,3}\.){3}\d{1,3}$/.test(ip)) {
655
+ return isPrivateIPv4(ip);
656
+ }
657
+ return isPrivateIPv6(ip);
658
+ }
659
+ function isPrivateOrInternalHostname(hostname) {
660
+ const normalized = hostname.toLowerCase();
661
+ if (normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized === "0.0.0.0" || normalized.endsWith(".localhost") || normalized.endsWith(".local")) {
662
+ return true;
663
+ }
664
+ if (normalized === "169.254.169.254" || normalized === "instance-data" || normalized === "metadata.google.internal" || normalized === "metadata.internal") {
665
+ return true;
666
+ }
667
+ if (normalized.endsWith(".cluster.local") || normalized.endsWith(".svc.cluster.local") || normalized.endsWith(".pod.cluster.local")) {
668
+ return true;
669
+ }
670
+ if (/^(\d{1,3}\.){3}\d{1,3}$/.test(normalized)) {
671
+ return isPrivateIPv4(normalized);
672
+ }
673
+ if (normalized.includes(":")) {
674
+ return isPrivateIPv6(normalized);
675
+ }
676
+ return false;
677
+ }
678
+ async function validateUrlForFetch(url) {
679
+ try {
680
+ const parsed = new URL(url);
681
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
682
+ return { valid: false, error: "URL must use HTTP or HTTPS protocol" };
683
+ }
684
+ if (isPrivateOrInternalHostname(parsed.hostname)) {
685
+ return { valid: false, error: "URL points to a private or internal network" };
686
+ }
687
+ const isIPv4Address = /^(\d{1,3}\.){3}\d{1,3}$/.test(parsed.hostname);
688
+ const isIPv6Address = parsed.hostname.includes(":");
689
+ if (!isIPv4Address && !isIPv6Address) {
690
+ try {
691
+ const ipv4Addresses = await dnsResolve4(parsed.hostname).catch(() => []);
692
+ const ipv6Addresses = await dnsResolve6(parsed.hostname).catch(() => []);
693
+ const allAddresses = [...ipv4Addresses, ...ipv6Addresses];
694
+ if (allAddresses.length === 0) {
695
+ return { valid: false, error: "Could not resolve hostname" };
696
+ }
697
+ for (const ip of allAddresses) {
698
+ if (isPrivateIP(ip)) {
699
+ return { valid: false, error: `Hostname resolves to private IP address (${ip})` };
700
+ }
701
+ }
702
+ } catch {
703
+ return { valid: false, error: "Could not resolve hostname" };
704
+ }
705
+ }
706
+ return { valid: true };
707
+ } catch {
708
+ return { valid: false, error: "Invalid URL format" };
709
+ }
710
+ }
711
+
712
+ // ../../b4m-core/packages/utils/dist/src/ingest.js
594
713
  var URL_REGEX = /https?:\/\/(?:[-\w.])+(?:\:[0-9]+)?(?:\/(?:[\w\/_.])*(?:\?(?:[\w&=%.])*)?(?:\#(?:[\w.])*)?)?/gi;
595
714
  function detectURLs(string) {
596
715
  const urlsFound = string.match(URL_REGEX) || [];
@@ -603,15 +722,22 @@ function urlExists(stringWithPossibleUrl) {
603
722
  const cleanString = stringWithPossibleUrl.replace(/\n/g, " ").replace(/,/g, " ");
604
723
  return detectURLs(cleanString);
605
724
  }
725
+ var URL_FETCH_TIMEOUT_MS = 1e4;
606
726
  async function fetchAndParseURL(url, { logger }) {
607
727
  logger.updateMetadata({ failedUrl: null });
608
728
  try {
729
+ const ssrfValidation = await validateUrlForFetch(url);
730
+ if (!ssrfValidation.valid) {
731
+ throw new Error(`URL blocked for security reasons: ${ssrfValidation.error}`);
732
+ }
609
733
  let urlMimeType = "text/plain";
610
734
  if (url.split(".")?.pop()?.startsWith("pdf")) {
611
735
  urlMimeType = "application/pdf";
612
736
  }
613
737
  const response = await axios.get(url, {
614
- responseType: ["application/pdf"].includes(urlMimeType) ? "arraybuffer" : "text"
738
+ responseType: ["application/pdf"].includes(urlMimeType) ? "arraybuffer" : "text",
739
+ timeout: URL_FETCH_TIMEOUT_MS
740
+ // Prevent Lambda timeout exhaustion
615
741
  });
616
742
  const cheerio = await import("cheerio");
617
743
  const htmlContent = response.data;
@@ -619,17 +745,19 @@ async function fetchAndParseURL(url, { logger }) {
619
745
  const title = $("title").text() || url.split("/")?.pop();
620
746
  let urlContent = null;
621
747
  switch (urlMimeType) {
622
- case "application/pdf":
748
+ case "application/pdf": {
623
749
  const pdfbuffer = Buffer.from(response.data);
624
750
  urlContent = pdfbuffer;
625
751
  break;
626
- default:
752
+ }
753
+ default: {
627
754
  let textContent = "";
628
755
  $("body").find("p").each((index, element) => {
629
756
  textContent += $(element).text() + "\n";
630
757
  });
631
758
  urlContent = textContent || htmlContent;
632
759
  break;
760
+ }
633
761
  }
634
762
  logger.log(`Fetched ${title} with mimetype ${urlMimeType} and parsed ${url}`);
635
763
  return { title, textContent: urlContent, mimeType: urlMimeType, ext: mime2.extension(urlMimeType) || null };
@@ -1155,8 +1283,30 @@ function separateUrls(urls) {
1155
1283
  const nonImageUrls = urls.filter((url) => !imageExtensions.some((ext) => url.toLowerCase().endsWith(ext)));
1156
1284
  return { imageUrls, nonImageUrls };
1157
1285
  }
1158
- var urlContentCache = /* @__PURE__ */ new Map();
1159
- var CACHE_TTL_MS = 5 * 60 * 1e3;
1286
+ function sanitizeUrlForLogging(url) {
1287
+ try {
1288
+ const parsed = new URL(url);
1289
+ const sensitiveParams = [
1290
+ "token",
1291
+ "key",
1292
+ "api_key",
1293
+ "apikey",
1294
+ "secret",
1295
+ "password",
1296
+ "session",
1297
+ "auth",
1298
+ "access_token"
1299
+ ];
1300
+ sensitiveParams.forEach((param) => {
1301
+ if (parsed.searchParams.has(param)) {
1302
+ parsed.searchParams.set(param, "[REDACTED]");
1303
+ }
1304
+ });
1305
+ return parsed.toString();
1306
+ } catch {
1307
+ return url.substring(0, 100) + (url.length > 100 ? "..." : "");
1308
+ }
1309
+ }
1160
1310
  async function processUrlsFromPrompt(userPrompt, maxContentBuffer, userId, sendStatusUpdate, logger, options = { verbose: false }) {
1161
1311
  if (!hasURLs(userPrompt)) {
1162
1312
  if (options?.verbose) {
@@ -1164,6 +1314,7 @@ async function processUrlsFromPrompt(userPrompt, maxContentBuffer, userId, sendS
1164
1314
  }
1165
1315
  return { userMessages: [], remainingPrompt: userPrompt };
1166
1316
  }
1317
+ const urlContentCache = /* @__PURE__ */ new Map();
1167
1318
  sendStatusUpdate("Processing URLs from user prompt...");
1168
1319
  const userMessages = [];
1169
1320
  const promptMeta = extractSnippetMeta(userPrompt);
@@ -1191,20 +1342,26 @@ async function processUrlsFromPrompt(userPrompt, maxContentBuffer, userId, sendS
1191
1342
  try {
1192
1343
  const cached = urlContentCache.get(url);
1193
1344
  let textContent;
1194
- if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
1195
- if (options?.verbose) {
1196
- logger.log(`Using cached content for URL: ${url}`);
1197
- }
1198
- textContent = cached.content;
1345
+ if (cached) {
1346
+ logger.info("URL_FETCH", {
1347
+ userId,
1348
+ url: sanitizeUrlForLogging(url),
1349
+ cacheHit: true,
1350
+ source: "same-request-dedup"
1351
+ });
1352
+ textContent = cached;
1199
1353
  } else {
1200
1354
  const result = await fetchAndParseURL(url, { logger });
1201
1355
  if (typeof result.textContent !== "string")
1202
1356
  throw new Error("textContent is not a string");
1203
1357
  textContent = result.textContent;
1204
- urlContentCache.set(url, {
1205
- content: textContent,
1206
- timestamp: Date.now()
1358
+ logger.info("URL_FETCH", {
1359
+ userId,
1360
+ url: sanitizeUrlForLogging(url),
1361
+ cacheHit: false,
1362
+ contentLength: textContent.length
1207
1363
  });
1364
+ urlContentCache.set(url, textContent);
1208
1365
  }
1209
1366
  const message = {
1210
1367
  role: "user",
@@ -11600,6 +11757,9 @@ function findAutomaticFallback(originalModel, availableModels, apiKeyTable, logg
11600
11757
  "gemini-2.5-flash-preview-05-20": ["claude-3-5-haiku-20241022", "gpt-4o-mini", "claude-3-haiku-20240307"],
11601
11758
  "gemini-1.5-pro": ["claude-3-5-sonnet-20241022", "gpt-4o", "claude-3-opus-20240229"],
11602
11759
  "gemini-1.5-flash": ["claude-3-5-haiku-20241022", "gpt-4o-mini", "claude-3-haiku-20240307"],
11760
+ // Claude 4.5/4.6 Opus models fallback to Sonnet 4.5
11761
+ "claude-opus-4-5-20251101": ["claude-sonnet-4-5-20250929", "gpt-5", "claude-haiku-4-5-20251001"],
11762
+ "claude-opus-4-6": ["claude-sonnet-4-5-20250929", "gpt-5", "claude-haiku-4-5-20251001"],
11603
11763
  // Claude models fallback to other Claude models or GPT
11604
11764
  "claude-3-5-sonnet-20241022": ["claude-3-opus-20240229", "gpt-4o", "claude-3-sonnet-20240229"],
11605
11765
  "claude-3-opus-20240229": ["claude-3-5-sonnet-20241022", "gpt-4o", "claude-3-sonnet-20240229"],
@@ -11609,7 +11769,7 @@ function findAutomaticFallback(originalModel, availableModels, apiKeyTable, logg
11609
11769
  };
11610
11770
  const preferences = fallbackPreferences[originalModel.id] || [];
11611
11771
  if (preferences.length === 0) {
11612
- preferences.push("claude-3-5-sonnet-20241022", "gpt-4o", "claude-3-haiku-20240307");
11772
+ preferences.push("claude-sonnet-4-5-20250929", "gpt-5", "claude-haiku-4-5-20251001");
11613
11773
  }
11614
11774
  for (const modelId of preferences) {
11615
11775
  const fallbackModel = availableModels.find((m) => m.id === modelId);
@@ -12015,6 +12175,9 @@ export {
12015
12175
  warmUpSettingsCache,
12016
12176
  shutdownSettingsCache,
12017
12177
  getSettingsCacheStats,
12178
+ isPrivateIP,
12179
+ isPrivateOrInternalHostname,
12180
+ validateUrlForFetch,
12018
12181
  URL_REGEX,
12019
12182
  detectURLs,
12020
12183
  hasURLs,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-Z5CU4KFU.js";
5
+ } from "./chunk-SYJA4DXH.js";
6
6
  import {
7
7
  CompletionApiUsageTransaction,
8
8
  GenericCreditDeductTransaction,
@@ -12,7 +12,7 @@ import {
12
12
  TextGenerationUsageTransaction,
13
13
  TransferCreditTransaction,
14
14
  VideoGenerationUsageTransaction
15
- } from "./chunk-HP6AES2S.js";
15
+ } from "./chunk-2HFZJMGD.js";
16
16
 
17
17
  // ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
18
18
  import { z } from "zod";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-XAN2CAVX.js";
6
- import "./chunk-Z5CU4KFU.js";
7
- import "./chunk-HP6AES2S.js";
5
+ } from "./chunk-NIWN4JNK.js";
6
+ import "./chunk-SYJA4DXH.js";
7
+ import "./chunk-2HFZJMGD.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  createFabFile,