@browser-ai/core 2.1.1 → 2.1.3

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.d.mts CHANGED
@@ -52,6 +52,16 @@ declare class BrowserAIChatLanguageModel implements LanguageModelV3 {
52
52
  * @throws {UnsupportedFunctionalityError} When unsupported features like file input are used
53
53
  */
54
54
  doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
55
+ /**
56
+ * Gets the input usage for the current session, if available
57
+ * @returns The input usage or undefined if not available
58
+ */
59
+ getInputUsage(): number | undefined;
60
+ /**
61
+ * Gets the input quota for the current session, if available
62
+ * @returns The input quota or undefined if not available
63
+ */
64
+ getInputQuota(): number | undefined;
55
65
  /**
56
66
  * Check the availability of the browser AI model
57
67
  * @returns Promise resolving to "unavailable", "available", or "available-after-download"
package/dist/index.d.ts CHANGED
@@ -52,6 +52,16 @@ declare class BrowserAIChatLanguageModel implements LanguageModelV3 {
52
52
  * @throws {UnsupportedFunctionalityError} When unsupported features like file input are used
53
53
  */
54
54
  doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult>;
55
+ /**
56
+ * Gets the input usage for the current session, if available
57
+ * @returns The input usage or undefined if not available
58
+ */
59
+ getInputUsage(): number | undefined;
60
+ /**
61
+ * Gets the input quota for the current session, if available
62
+ * @returns The input quota or undefined if not available
63
+ */
64
+ getInputQuota(): number | undefined;
55
65
  /**
56
66
  * Check the availability of the browser AI model
57
67
  * @returns Promise resolving to "unavailable", "available", or "available-after-download"
package/dist/index.js CHANGED
@@ -484,6 +484,91 @@ var ToolCallFenceDetector = class {
484
484
  }
485
485
  };
486
486
 
487
+ // ../shared/src/streaming/tool-call-stream-utils.ts
488
+ function extractToolName(content) {
489
+ const jsonMatch = content.match(/\{\s*"name"\s*:\s*"([^"]+)"/);
490
+ if (jsonMatch) {
491
+ return jsonMatch[1];
492
+ }
493
+ return null;
494
+ }
495
+ var ARGUMENTS_FIELD_REGEX = /"arguments"\s*:\s*/g;
496
+ var ARGUMENTS_SEARCH_OVERLAP = 32;
497
+ function createArgumentsStreamState() {
498
+ return {
499
+ searchFrom: 0,
500
+ valueStartIndex: null,
501
+ parseIndex: 0,
502
+ started: false,
503
+ depth: 0,
504
+ inString: false,
505
+ escaped: false,
506
+ complete: false
507
+ };
508
+ }
509
+ function extractArgumentsDelta(content, state) {
510
+ if (state.complete) {
511
+ return "";
512
+ }
513
+ if (state.valueStartIndex === null) {
514
+ ARGUMENTS_FIELD_REGEX.lastIndex = state.searchFrom;
515
+ const match = ARGUMENTS_FIELD_REGEX.exec(content);
516
+ ARGUMENTS_FIELD_REGEX.lastIndex = 0;
517
+ if (!match || match.index === void 0) {
518
+ state.searchFrom = Math.max(0, content.length - ARGUMENTS_SEARCH_OVERLAP);
519
+ return "";
520
+ }
521
+ state.valueStartIndex = match.index + match[0].length;
522
+ state.parseIndex = state.valueStartIndex;
523
+ state.searchFrom = state.valueStartIndex;
524
+ }
525
+ if (state.parseIndex >= content.length) {
526
+ return "";
527
+ }
528
+ let delta = "";
529
+ for (let i = state.parseIndex; i < content.length; i++) {
530
+ const char = content[i];
531
+ delta += char;
532
+ if (!state.started) {
533
+ if (!/\s/.test(char)) {
534
+ state.started = true;
535
+ if (char === "{" || char === "[") {
536
+ state.depth = 1;
537
+ }
538
+ }
539
+ continue;
540
+ }
541
+ if (state.escaped) {
542
+ state.escaped = false;
543
+ continue;
544
+ }
545
+ if (char === "\\") {
546
+ state.escaped = true;
547
+ continue;
548
+ }
549
+ if (char === '"') {
550
+ state.inString = !state.inString;
551
+ continue;
552
+ }
553
+ if (!state.inString) {
554
+ if (char === "{" || char === "[") {
555
+ state.depth += 1;
556
+ } else if (char === "}" || char === "]") {
557
+ if (state.depth > 0) {
558
+ state.depth -= 1;
559
+ if (state.depth === 0) {
560
+ state.parseIndex = i + 1;
561
+ state.complete = true;
562
+ return delta;
563
+ }
564
+ }
565
+ }
566
+ }
567
+ }
568
+ state.parseIndex = content.length;
569
+ return delta;
570
+ }
571
+
487
572
  // src/convert-to-browser-ai-messages.ts
488
573
  var import_provider = require("@ai-sdk/provider");
489
574
  function convertBase64ToUint8Array(base64) {
@@ -912,6 +997,20 @@ var SessionManager = class {
912
997
  }
913
998
  this.session = null;
914
999
  }
1000
+ /**
1001
+ * Gets the input quota for the current session, if available
1002
+ * @returns The input quota or undefined if not available
1003
+ */
1004
+ getInputQuota() {
1005
+ return this.getCurrentSession()?.inputQuota;
1006
+ }
1007
+ /**
1008
+ * Gets the input usage for the current session, if available
1009
+ * @returns The input usage or undefined if not available
1010
+ */
1011
+ getInputUsage() {
1012
+ return this.getCurrentSession()?.inputUsage;
1013
+ }
915
1014
  /**
916
1015
  * Prepares merged session options from base config and request options
917
1016
  *
@@ -963,63 +1062,6 @@ var SessionManager = class {
963
1062
  function doesBrowserSupportBrowserAI() {
964
1063
  return typeof LanguageModel !== "undefined";
965
1064
  }
966
- function extractToolName(content) {
967
- const jsonMatch = content.match(/\{\s*"name"\s*:\s*"([^"]+)"/);
968
- if (jsonMatch) {
969
- return jsonMatch[1];
970
- }
971
- return null;
972
- }
973
- function extractArgumentsContent(content) {
974
- const match = content.match(/"arguments"\s*:\s*/);
975
- if (!match || match.index === void 0) {
976
- return "";
977
- }
978
- const startIndex = match.index + match[0].length;
979
- let result = "";
980
- let depth = 0;
981
- let inString = false;
982
- let escaped = false;
983
- let started = false;
984
- for (let i = startIndex; i < content.length; i++) {
985
- const char = content[i];
986
- result += char;
987
- if (!started) {
988
- if (!/\s/.test(char)) {
989
- started = true;
990
- if (char === "{" || char === "[") {
991
- depth = 1;
992
- }
993
- }
994
- continue;
995
- }
996
- if (escaped) {
997
- escaped = false;
998
- continue;
999
- }
1000
- if (char === "\\") {
1001
- escaped = true;
1002
- continue;
1003
- }
1004
- if (char === '"') {
1005
- inString = !inString;
1006
- continue;
1007
- }
1008
- if (!inString) {
1009
- if (char === "{" || char === "[") {
1010
- depth += 1;
1011
- } else if (char === "}" || char === "]") {
1012
- if (depth > 0) {
1013
- depth -= 1;
1014
- if (depth === 0) {
1015
- break;
1016
- }
1017
- }
1018
- }
1019
- }
1020
- }
1021
- return result;
1022
- }
1023
1065
  var BrowserAIChatLanguageModel = class {
1024
1066
  constructor(modelId, options = {}) {
1025
1067
  this.specificationVersion = "v3";
@@ -1205,6 +1247,20 @@ var BrowserAIChatLanguageModel = class {
1205
1247
  warnings
1206
1248
  };
1207
1249
  }
1250
+ /**
1251
+ * Gets the input usage for the current session, if available
1252
+ * @returns The input usage or undefined if not available
1253
+ */
1254
+ getInputUsage() {
1255
+ return this.sessionManager.getInputUsage();
1256
+ }
1257
+ /**
1258
+ * Gets the input quota for the current session, if available
1259
+ * @returns The input quota or undefined if not available
1260
+ */
1261
+ getInputQuota() {
1262
+ return this.sessionManager.getInputQuota();
1263
+ }
1208
1264
  /**
1209
1265
  * Check the availability of the browser AI model
1210
1266
  * @returns Promise resolving to "unavailable", "available", or "available-after-download"
@@ -1356,7 +1412,7 @@ var BrowserAIChatLanguageModel = class {
1356
1412
  let currentToolCallId = null;
1357
1413
  let toolInputStartEmitted = false;
1358
1414
  let accumulatedFenceContent = "";
1359
- let streamedArgumentsLength = 0;
1415
+ let argumentsStreamState = createArgumentsStreamState();
1360
1416
  let insideFence = false;
1361
1417
  while (!aborted) {
1362
1418
  const { done, value } = await currentReader.read();
@@ -1377,7 +1433,7 @@ var BrowserAIChatLanguageModel = class {
1377
1433
  currentToolCallId = `call_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
1378
1434
  toolInputStartEmitted = false;
1379
1435
  accumulatedFenceContent = "";
1380
- streamedArgumentsLength = 0;
1436
+ argumentsStreamState = createArgumentsStreamState();
1381
1437
  insideFence = true;
1382
1438
  continue;
1383
1439
  }
@@ -1387,19 +1443,16 @@ var BrowserAIChatLanguageModel = class {
1387
1443
  accumulatedFenceContent += result.safeContent;
1388
1444
  }
1389
1445
  if (toolInputStartEmitted && currentToolCallId) {
1390
- const argsContent = extractArgumentsContent(
1391
- accumulatedFenceContent
1446
+ const delta = extractArgumentsDelta(
1447
+ accumulatedFenceContent,
1448
+ argumentsStreamState
1392
1449
  );
1393
- if (argsContent.length > streamedArgumentsLength) {
1394
- const delta = argsContent.slice(streamedArgumentsLength);
1395
- streamedArgumentsLength = argsContent.length;
1396
- if (delta.length > 0) {
1397
- controller.enqueue({
1398
- type: "tool-input-delta",
1399
- id: currentToolCallId,
1400
- delta
1401
- });
1402
- }
1450
+ if (delta.length > 0) {
1451
+ controller.enqueue({
1452
+ type: "tool-input-delta",
1453
+ id: currentToolCallId,
1454
+ delta
1455
+ });
1403
1456
  }
1404
1457
  }
1405
1458
  const parsed = parseJsonFunctionCalls(result.completeFence);
@@ -1415,7 +1468,7 @@ var BrowserAIChatLanguageModel = class {
1415
1468
  currentToolCallId = null;
1416
1469
  toolInputStartEmitted = false;
1417
1470
  accumulatedFenceContent = "";
1418
- streamedArgumentsLength = 0;
1471
+ argumentsStreamState = createArgumentsStreamState();
1419
1472
  insideFence = false;
1420
1473
  continue;
1421
1474
  }
@@ -1437,21 +1490,16 @@ var BrowserAIChatLanguageModel = class {
1437
1490
  });
1438
1491
  toolInputStartEmitted = true;
1439
1492
  }
1440
- const argsContent = extractArgumentsContent(
1441
- accumulatedFenceContent
1493
+ const delta = extractArgumentsDelta(
1494
+ accumulatedFenceContent,
1495
+ argumentsStreamState
1442
1496
  );
1443
- if (argsContent.length > streamedArgumentsLength) {
1444
- const delta = argsContent.slice(
1445
- streamedArgumentsLength
1446
- );
1447
- streamedArgumentsLength = argsContent.length;
1448
- if (delta.length > 0) {
1449
- controller.enqueue({
1450
- type: "tool-input-delta",
1451
- id: toolCallId,
1452
- delta
1453
- });
1454
- }
1497
+ if (delta.length > 0) {
1498
+ controller.enqueue({
1499
+ type: "tool-input-delta",
1500
+ id: toolCallId,
1501
+ delta
1502
+ });
1455
1503
  }
1456
1504
  } else {
1457
1505
  controller.enqueue({
@@ -1488,7 +1536,7 @@ var BrowserAIChatLanguageModel = class {
1488
1536
  currentToolCallId = null;
1489
1537
  toolInputStartEmitted = false;
1490
1538
  accumulatedFenceContent = "";
1491
- streamedArgumentsLength = 0;
1539
+ argumentsStreamState = createArgumentsStreamState();
1492
1540
  insideFence = false;
1493
1541
  continue;
1494
1542
  }
@@ -1506,21 +1554,16 @@ var BrowserAIChatLanguageModel = class {
1506
1554
  toolInputStartEmitted = true;
1507
1555
  }
1508
1556
  if (toolInputStartEmitted && currentToolCallId) {
1509
- const argsContent = extractArgumentsContent(
1510
- accumulatedFenceContent
1557
+ const delta = extractArgumentsDelta(
1558
+ accumulatedFenceContent,
1559
+ argumentsStreamState
1511
1560
  );
1512
- if (argsContent.length > streamedArgumentsLength) {
1513
- const delta = argsContent.slice(
1514
- streamedArgumentsLength
1515
- );
1516
- streamedArgumentsLength = argsContent.length;
1517
- if (delta.length > 0) {
1518
- controller.enqueue({
1519
- type: "tool-input-delta",
1520
- id: currentToolCallId,
1521
- delta
1522
- });
1523
- }
1561
+ if (delta.length > 0) {
1562
+ controller.enqueue({
1563
+ type: "tool-input-delta",
1564
+ id: currentToolCallId,
1565
+ delta
1566
+ });
1524
1567
  }
1525
1568
  }
1526
1569
  }