@yourgpt/copilot-sdk 2.1.5-alpha.4 → 2.1.5-alpha.5

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.
Files changed (102) hide show
  1. package/dist/{MessageTree-CSIHErPK.d.ts → MessageTree-Clhiv_k2.d.ts} +4 -3
  2. package/dist/{MessageTree-B0JGQOCi.d.cts → MessageTree-Dt9qfJ55.d.cts} +4 -3
  3. package/dist/{chunk-NUXLAZOE.cjs → chunk-3ZDRX7J2.cjs} +2 -2
  4. package/dist/{chunk-NUXLAZOE.cjs.map → chunk-3ZDRX7J2.cjs.map} +1 -1
  5. package/dist/{chunk-RKGRQRZU.js → chunk-533K2Z7C.js} +4 -4
  6. package/dist/{chunk-RKGRQRZU.js.map → chunk-533K2Z7C.js.map} +1 -1
  7. package/dist/chunk-5EGBIQYS.cjs +292 -0
  8. package/dist/chunk-5EGBIQYS.cjs.map +1 -0
  9. package/dist/chunk-5UGWLGFS.cjs +2039 -0
  10. package/dist/chunk-5UGWLGFS.cjs.map +1 -0
  11. package/dist/{chunk-3AONOZLY.js → chunk-AIVXGTWS.js} +2 -2
  12. package/dist/chunk-AIVXGTWS.js.map +1 -0
  13. package/dist/{chunk-LLM7AHMO.js → chunk-DDZLRCVX.js} +2 -2
  14. package/dist/{chunk-LLM7AHMO.js.map → chunk-DDZLRCVX.js.map} +1 -1
  15. package/dist/{chunk-FLZO2FO3.js → chunk-DH6EO6NW.js} +1334 -3048
  16. package/dist/chunk-DH6EO6NW.js.map +1 -0
  17. package/dist/{chunk-B4YDIMP3.cjs → chunk-KGYDGK3U.cjs} +82 -29
  18. package/dist/chunk-KGYDGK3U.cjs.map +1 -0
  19. package/dist/{chunk-XUR3IOPX.cjs → chunk-LHLVTGIP.cjs} +1336 -3100
  20. package/dist/chunk-LHLVTGIP.cjs.map +1 -0
  21. package/dist/{chunk-TPB7XED6.cjs → chunk-TPDMBDQX.cjs} +2 -2
  22. package/dist/chunk-TPDMBDQX.cjs.map +1 -0
  23. package/dist/chunk-TXQ37MAO.js +287 -0
  24. package/dist/chunk-TXQ37MAO.js.map +1 -0
  25. package/dist/{chunk-MDS23G2S.cjs → chunk-Y2A6AMGO.cjs} +10 -10
  26. package/dist/{chunk-MDS23G2S.cjs.map → chunk-Y2A6AMGO.cjs.map} +1 -1
  27. package/dist/{chunk-EEH3L64W.js → chunk-YLZCTR4O.js} +63 -10
  28. package/dist/chunk-YLZCTR4O.js.map +1 -0
  29. package/dist/chunk-ZAOTYA5L.js +1983 -0
  30. package/dist/chunk-ZAOTYA5L.js.map +1 -0
  31. package/dist/core/index.cjs +93 -93
  32. package/dist/core/index.d.cts +3 -3
  33. package/dist/core/index.d.ts +3 -3
  34. package/dist/core/index.js +5 -5
  35. package/dist/experimental/index.cjs +644 -0
  36. package/dist/experimental/index.cjs.map +1 -0
  37. package/dist/experimental/index.d.cts +924 -0
  38. package/dist/experimental/index.d.ts +924 -0
  39. package/dist/experimental/index.js +611 -0
  40. package/dist/experimental/index.js.map +1 -0
  41. package/dist/{index-D7169xuR.d.ts → index-D8zza1Q8.d.ts} +1 -1
  42. package/dist/{index-CzJB8Ddo.d.cts → index-DCVjTdIZ.d.cts} +1 -1
  43. package/dist/mcp/index.d.cts +3 -3
  44. package/dist/mcp/index.d.ts +3 -3
  45. package/dist/react/index.cjs +136 -123
  46. package/dist/react/index.d.cts +174 -8
  47. package/dist/react/index.d.ts +174 -8
  48. package/dist/react/index.js +7 -6
  49. package/dist/styles.css +45 -0
  50. package/dist/tools/anthropic/index.cjs +3 -3
  51. package/dist/tools/anthropic/index.d.cts +1 -1
  52. package/dist/tools/anthropic/index.d.ts +1 -1
  53. package/dist/tools/anthropic/index.js +2 -2
  54. package/dist/tools/brave/index.cjs +6 -6
  55. package/dist/tools/brave/index.d.cts +1 -1
  56. package/dist/tools/brave/index.d.ts +1 -1
  57. package/dist/tools/brave/index.js +3 -3
  58. package/dist/tools/exa/index.cjs +6 -6
  59. package/dist/tools/exa/index.d.cts +1 -1
  60. package/dist/tools/exa/index.d.ts +1 -1
  61. package/dist/tools/exa/index.js +3 -3
  62. package/dist/tools/google/index.cjs +6 -6
  63. package/dist/tools/google/index.d.cts +1 -1
  64. package/dist/tools/google/index.d.ts +1 -1
  65. package/dist/tools/google/index.js +4 -4
  66. package/dist/tools/openai/index.cjs +6 -6
  67. package/dist/tools/openai/index.d.cts +1 -1
  68. package/dist/tools/openai/index.d.ts +1 -1
  69. package/dist/tools/openai/index.js +3 -3
  70. package/dist/tools/searxng/index.cjs +6 -6
  71. package/dist/tools/searxng/index.d.cts +1 -1
  72. package/dist/tools/searxng/index.d.ts +1 -1
  73. package/dist/tools/searxng/index.js +3 -3
  74. package/dist/tools/serper/index.cjs +6 -6
  75. package/dist/tools/serper/index.d.cts +1 -1
  76. package/dist/tools/serper/index.d.ts +1 -1
  77. package/dist/tools/serper/index.js +3 -3
  78. package/dist/tools/tavily/index.cjs +6 -6
  79. package/dist/tools/tavily/index.d.cts +1 -1
  80. package/dist/tools/tavily/index.d.ts +1 -1
  81. package/dist/tools/tavily/index.js +3 -3
  82. package/dist/tools/web-search/index.cjs +7 -7
  83. package/dist/tools/web-search/index.d.cts +2 -2
  84. package/dist/tools/web-search/index.d.ts +2 -2
  85. package/dist/tools/web-search/index.js +4 -4
  86. package/dist/{tools-tmksfhUo.d.cts → tools-DcS6Aeao.d.cts} +7 -3
  87. package/dist/{tools-tmksfhUo.d.ts → tools-DcS6Aeao.d.ts} +7 -3
  88. package/dist/{types-BqwW3Baj.d.ts → types-BUYni9B8.d.ts} +1 -1
  89. package/dist/{types-BLw7mxtW.d.cts → types-Cvg4DUoc.d.cts} +1 -1
  90. package/dist/ui/index.cjs +345 -522
  91. package/dist/ui/index.cjs.map +1 -1
  92. package/dist/ui/index.d.cts +21 -3
  93. package/dist/ui/index.d.ts +21 -3
  94. package/dist/ui/index.js +188 -370
  95. package/dist/ui/index.js.map +1 -1
  96. package/package.json +6 -1
  97. package/dist/chunk-3AONOZLY.js.map +0 -1
  98. package/dist/chunk-B4YDIMP3.cjs.map +0 -1
  99. package/dist/chunk-EEH3L64W.js.map +0 -1
  100. package/dist/chunk-FLZO2FO3.js.map +0 -1
  101. package/dist/chunk-TPB7XED6.cjs.map +0 -1
  102. package/dist/chunk-XUR3IOPX.cjs.map +0 -1
@@ -1,34 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var chunkB4YDIMP3_cjs = require('./chunk-B4YDIMP3.cjs');
3
+ var chunkKGYDGK3U_cjs = require('./chunk-KGYDGK3U.cjs');
4
4
  var chunkJGPDQDY4_cjs = require('./chunk-JGPDQDY4.cjs');
5
5
  var chunkBJYA5NDL_cjs = require('./chunk-BJYA5NDL.cjs');
6
6
  var React2 = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
- var z = require('zod');
9
8
 
10
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
10
 
12
- function _interopNamespace(e) {
13
- if (e && e.__esModule) return e;
14
- var n = Object.create(null);
15
- if (e) {
16
- Object.keys(e).forEach(function (k) {
17
- if (k !== 'default') {
18
- var d = Object.getOwnPropertyDescriptor(e, k);
19
- Object.defineProperty(n, k, d.get ? d : {
20
- enumerable: true,
21
- get: function () { return e[k]; }
22
- });
23
- }
24
- });
25
- }
26
- n.default = e;
27
- return Object.freeze(n);
28
- }
29
-
30
11
  var React2__default = /*#__PURE__*/_interopDefault(React2);
31
- var z__namespace = /*#__PURE__*/_interopNamespace(z);
32
12
 
33
13
  // src/chat/types/tool.ts
34
14
  var initialAgentLoopState = {
@@ -39,88 +19,6 @@ var initialAgentLoopState = {
39
19
  isProcessing: false
40
20
  };
41
21
 
42
- // src/chat/interfaces/ChatState.ts
43
- var SimpleChatState = class {
44
- constructor() {
45
- this._messages = [];
46
- this._status = "ready";
47
- this._error = void 0;
48
- this.callbacks = /* @__PURE__ */ new Set();
49
- }
50
- get messages() {
51
- return this._messages;
52
- }
53
- set messages(value) {
54
- this._messages = value;
55
- this.notify();
56
- }
57
- get status() {
58
- return this._status;
59
- }
60
- set status(value) {
61
- this._status = value;
62
- this.notify();
63
- }
64
- get error() {
65
- return this._error;
66
- }
67
- set error(value) {
68
- this._error = value;
69
- this.notify();
70
- }
71
- pushMessage(message) {
72
- this._messages = [...this._messages, message];
73
- this.notify();
74
- }
75
- popMessage() {
76
- this._messages = this._messages.slice(0, -1);
77
- this.notify();
78
- }
79
- replaceMessage(index, message) {
80
- this._messages = [
81
- ...this._messages.slice(0, index),
82
- message,
83
- ...this._messages.slice(index + 1)
84
- ];
85
- this.notify();
86
- }
87
- updateLastMessage(updater) {
88
- if (this._messages.length === 0) return;
89
- const lastIndex = this._messages.length - 1;
90
- this.replaceMessage(lastIndex, updater(this._messages[lastIndex]));
91
- }
92
- updateMessageById(id, updater) {
93
- const index = this._messages.findIndex((m) => m.id === id);
94
- if (index === -1) return false;
95
- this.replaceMessage(index, updater(this._messages[index]));
96
- return true;
97
- }
98
- setMessages(messages) {
99
- this._messages = messages;
100
- this.notify();
101
- }
102
- clearMessages() {
103
- this._messages = [];
104
- this.notify();
105
- }
106
- subscribe(callback) {
107
- this.callbacks.add(callback);
108
- return () => this.callbacks.delete(callback);
109
- }
110
- getMessagesSnapshot() {
111
- return this._messages;
112
- }
113
- getStatusSnapshot() {
114
- return this._status;
115
- }
116
- getErrorSnapshot() {
117
- return this._error;
118
- }
119
- notify() {
120
- this.callbacks.forEach((cb) => cb());
121
- }
122
- };
123
-
124
22
  // src/chat/functions/stream/parseSSE.ts
125
23
  function parseSSELine(line) {
126
24
  if (!line || line.trim() === "") {
@@ -541,6 +439,88 @@ var HttpTransport = class {
541
439
  }
542
440
  };
543
441
 
442
+ // src/chat/interfaces/ChatState.ts
443
+ var SimpleChatState = class {
444
+ constructor() {
445
+ this._messages = [];
446
+ this._status = "ready";
447
+ this._error = void 0;
448
+ this.callbacks = /* @__PURE__ */ new Set();
449
+ }
450
+ get messages() {
451
+ return this._messages;
452
+ }
453
+ set messages(value) {
454
+ this._messages = value;
455
+ this.notify();
456
+ }
457
+ get status() {
458
+ return this._status;
459
+ }
460
+ set status(value) {
461
+ this._status = value;
462
+ this.notify();
463
+ }
464
+ get error() {
465
+ return this._error;
466
+ }
467
+ set error(value) {
468
+ this._error = value;
469
+ this.notify();
470
+ }
471
+ pushMessage(message) {
472
+ this._messages = [...this._messages, message];
473
+ this.notify();
474
+ }
475
+ popMessage() {
476
+ this._messages = this._messages.slice(0, -1);
477
+ this.notify();
478
+ }
479
+ replaceMessage(index, message) {
480
+ this._messages = [
481
+ ...this._messages.slice(0, index),
482
+ message,
483
+ ...this._messages.slice(index + 1)
484
+ ];
485
+ this.notify();
486
+ }
487
+ updateLastMessage(updater) {
488
+ if (this._messages.length === 0) return;
489
+ const lastIndex = this._messages.length - 1;
490
+ this.replaceMessage(lastIndex, updater(this._messages[lastIndex]));
491
+ }
492
+ updateMessageById(id, updater) {
493
+ const index = this._messages.findIndex((m) => m.id === id);
494
+ if (index === -1) return false;
495
+ this.replaceMessage(index, updater(this._messages[index]));
496
+ return true;
497
+ }
498
+ setMessages(messages) {
499
+ this._messages = messages;
500
+ this.notify();
501
+ }
502
+ clearMessages() {
503
+ this._messages = [];
504
+ this.notify();
505
+ }
506
+ subscribe(callback) {
507
+ this.callbacks.add(callback);
508
+ return () => this.callbacks.delete(callback);
509
+ }
510
+ getMessagesSnapshot() {
511
+ return this._messages;
512
+ }
513
+ getStatusSnapshot() {
514
+ return this._status;
515
+ }
516
+ getErrorSnapshot() {
517
+ return this._error;
518
+ }
519
+ notify() {
520
+ this.callbacks.forEach((cb) => cb());
521
+ }
522
+ };
523
+
544
524
  // src/chat/optimizations.ts
545
525
  var DEFAULT_CHARS_PER_TOKEN = 4;
546
526
  var DEFAULT_SAFETY_MARGIN = 1.2;
@@ -662,15 +642,15 @@ ${attachments}`,
662
642
  charsPerToken
663
643
  );
664
644
  }
665
- function estimateToolTokens(tool2, charsPerToken = DEFAULT_CHARS_PER_TOKEN) {
666
- return estimateTokens(JSON.stringify(tool2), charsPerToken);
645
+ function estimateToolTokens(tool, charsPerToken = DEFAULT_CHARS_PER_TOKEN) {
646
+ return estimateTokens(JSON.stringify(tool), charsPerToken);
667
647
  }
668
648
  function buildToolQuery(messages) {
669
649
  return messages.filter(
670
650
  (message) => message.role === "user" || message.role === "assistant"
671
651
  ).slice(-3).map((message) => message.content).filter(Boolean).join(" ");
672
652
  }
673
- function matchesSelector(tool2, selector, activeProfile) {
653
+ function matchesSelector(tool, selector, activeProfile) {
674
654
  const normalized = selector.trim().toLowerCase();
675
655
  if (!normalized) {
676
656
  return false;
@@ -678,40 +658,40 @@ function matchesSelector(tool2, selector, activeProfile) {
678
658
  if (normalized === "*" || normalized === "all") {
679
659
  return true;
680
660
  }
681
- if (normalized === tool2.name.toLowerCase()) {
661
+ if (normalized === tool.name.toLowerCase()) {
682
662
  return true;
683
663
  }
684
664
  if (normalized.startsWith("group:")) {
685
- return (tool2.group ?? "").toLowerCase() === normalized.slice(6);
665
+ return (tool.group ?? "").toLowerCase() === normalized.slice(6);
686
666
  }
687
667
  if (normalized.startsWith("category:")) {
688
- return (tool2.category ?? "").toLowerCase() === normalized.slice(9);
668
+ return (tool.category ?? "").toLowerCase() === normalized.slice(9);
689
669
  }
690
670
  if (normalized.startsWith("profile:")) {
691
- return (tool2.profiles ?? []).map((value) => value.toLowerCase()).includes(normalized.slice(8));
671
+ return (tool.profiles ?? []).map((value) => value.toLowerCase()).includes(normalized.slice(8));
692
672
  }
693
673
  if (activeProfile && normalized === activeProfile.toLowerCase()) {
694
- return (tool2.profiles ?? []).map((value) => value.toLowerCase()).includes(normalized);
674
+ return (tool.profiles ?? []).map((value) => value.toLowerCase()).includes(normalized);
695
675
  }
696
676
  return false;
697
677
  }
698
- function scoreTool(tool2, queryTokens, activeProfile) {
678
+ function scoreTool(tool, queryTokens, activeProfile) {
699
679
  const haystack = [
700
- tool2.name,
701
- tool2.description,
702
- tool2.category,
703
- tool2.group,
704
- ...tool2.profiles ?? [],
705
- ...tool2.searchKeywords ?? []
680
+ tool.name,
681
+ tool.description,
682
+ tool.category,
683
+ tool.group,
684
+ ...tool.profiles ?? [],
685
+ ...tool.searchKeywords ?? []
706
686
  ].filter(Boolean).join(" ").toLowerCase();
707
- let score = tool2.deferLoading ? 0 : 2;
708
- if (activeProfile && tool2.profiles?.includes(activeProfile)) {
687
+ let score = tool.deferLoading ? 0 : 2;
688
+ if (activeProfile && tool.profiles?.includes(activeProfile)) {
709
689
  score += 2;
710
690
  }
711
691
  for (const token of queryTokens) {
712
- if (tool2.name.toLowerCase() === token) {
692
+ if (tool.name.toLowerCase() === token) {
713
693
  score += 6;
714
- } else if (tool2.name.toLowerCase().includes(token)) {
694
+ } else if (tool.name.toLowerCase().includes(token)) {
715
695
  score += 4;
716
696
  } else if (haystack.includes(token)) {
717
697
  score += 2;
@@ -925,15 +905,15 @@ function buildToolDefinitions(selectedTools) {
925
905
  if (selectedTools.length === 0) {
926
906
  return void 0;
927
907
  }
928
- return selectedTools.map((tool2) => ({
929
- name: tool2.name,
930
- description: tool2.description,
931
- category: tool2.category,
932
- group: tool2.group,
933
- deferLoading: tool2.deferLoading,
934
- profiles: tool2.profiles,
935
- searchKeywords: tool2.searchKeywords,
936
- inputSchema: tool2.inputSchema
908
+ return selectedTools.map((tool) => ({
909
+ name: tool.name,
910
+ description: tool.description,
911
+ category: tool.category,
912
+ group: tool.group,
913
+ deferLoading: tool.deferLoading,
914
+ profiles: tool.profiles,
915
+ searchKeywords: tool.searchKeywords,
916
+ inputSchema: tool.inputSchema
937
917
  }));
938
918
  }
939
919
  function resolveTruncationConfig(params) {
@@ -963,21 +943,21 @@ function resolveTruncationConfig(params) {
963
943
  preserveErrors: merged.preserveErrors ?? true
964
944
  };
965
945
  }
966
- function buildToolResultContent(result, tool2, args) {
946
+ function buildToolResultContent(result, tool, args) {
967
947
  if (typeof result === "string") {
968
948
  return result;
969
949
  }
970
950
  const typedResult = result ?? null;
971
- const responseMode = typedResult?._aiResponseMode ?? tool2?.aiResponseMode ?? "full";
951
+ const responseMode = typedResult?._aiResponseMode ?? tool?.aiResponseMode ?? "full";
972
952
  if (typedResult?._aiContent) {
973
953
  return JSON.stringify(typedResult._aiContent);
974
954
  }
975
955
  let aiContext = typedResult?._aiContext;
976
- if (!aiContext && tool2?.aiContext) {
977
- aiContext = typeof tool2.aiContext === "function" ? tool2.aiContext(
956
+ if (!aiContext && tool?.aiContext) {
957
+ aiContext = typeof tool.aiContext === "function" ? tool.aiContext(
978
958
  typedResult ?? { success: true },
979
959
  args ?? {}
980
- ) : tool2.aiContext;
960
+ ) : tool.aiContext;
981
961
  }
982
962
  switch (responseMode) {
983
963
  case "none":
@@ -1006,9 +986,9 @@ Full data: ${JSON.stringify(dataOnly)}`;
1006
986
  }
1007
987
  }
1008
988
  }
1009
- function buildToolResultContentForPrompt(result, tool2, args, config) {
1010
- const text = buildToolResultContent(result, tool2, args);
1011
- const truncation = resolveTruncationConfig({ tool: tool2, config });
989
+ function buildToolResultContentForPrompt(result, tool, args, config) {
990
+ const text = buildToolResultContent(result, tool, args);
991
+ const truncation = resolveTruncationConfig({ tool, config });
1012
992
  if (!truncation.enabled) {
1013
993
  return text;
1014
994
  }
@@ -1114,7 +1094,7 @@ function fitToolsToBudget(params) {
1114
1094
  return tools;
1115
1095
  }
1116
1096
  const getToolTokens = () => tools.reduce(
1117
- (sum, tool2) => sum + estimateToolTokens(tool2, params.charsPerToken),
1097
+ (sum, tool) => sum + estimateToolTokens(tool, params.charsPerToken),
1118
1098
  0
1119
1099
  );
1120
1100
  while (tools.length > 0 && getToolTokens() > params.maxTokens) {
@@ -1152,7 +1132,7 @@ function calculateBuckets(params) {
1152
1132
  0
1153
1133
  );
1154
1134
  const toolDefinitionTokens = (params.requestTools ?? []).reduce(
1155
- (sum, tool2) => sum + estimateToolTokens(tool2, params.charsPerToken),
1135
+ (sum, tool) => sum + estimateToolTokens(tool, params.charsPerToken),
1156
1136
  0
1157
1137
  );
1158
1138
  const total = systemPromptTokens + historyTokens + toolResultsTokens + toolDefinitionTokens;
@@ -1391,7 +1371,7 @@ var ChatContextOptimizer = class {
1391
1371
  if (!tools.length) {
1392
1372
  return [];
1393
1373
  }
1394
- const available = tools.filter((tool2) => tool2.available !== false);
1374
+ const available = tools.filter((tool) => tool.available !== false);
1395
1375
  const profileConfig = this.config?.toolProfiles;
1396
1376
  if (!profileConfig?.enabled) {
1397
1377
  return available;
@@ -1402,22 +1382,22 @@ var ChatContextOptimizer = class {
1402
1382
  let filtered = available;
1403
1383
  if (profile?.include?.length) {
1404
1384
  filtered = filtered.filter(
1405
- (tool2) => profile.include.some(
1406
- (selector) => matchesSelector(tool2, selector, activeProfile)
1407
- ) || !!activeProfile && tool2.profiles?.includes(activeProfile)
1385
+ (tool) => profile.include.some(
1386
+ (selector) => matchesSelector(tool, selector, activeProfile)
1387
+ ) || !!activeProfile && tool.profiles?.includes(activeProfile)
1408
1388
  );
1409
1389
  } else if (activeProfile) {
1410
- filtered = filtered.filter((tool2) => {
1411
- if (tool2.profiles?.length) {
1412
- return tool2.profiles.includes(activeProfile);
1390
+ filtered = filtered.filter((tool) => {
1391
+ if (tool.profiles?.length) {
1392
+ return tool.profiles.includes(activeProfile);
1413
1393
  }
1414
1394
  return includeUnprofiled;
1415
1395
  });
1416
1396
  }
1417
1397
  if (profile?.exclude?.length) {
1418
1398
  filtered = filtered.filter(
1419
- (tool2) => !profile.exclude.some(
1420
- (selector) => matchesSelector(tool2, selector, activeProfile)
1399
+ (tool) => !profile.exclude.some(
1400
+ (selector) => matchesSelector(tool, selector, activeProfile)
1421
1401
  )
1422
1402
  );
1423
1403
  }
@@ -1461,7 +1441,7 @@ var ChatContextOptimizer = class {
1461
1441
  }
1462
1442
  }
1463
1443
  const toolDefMap = new Map(
1464
- allTools.map((tool2) => [tool2.name, tool2])
1444
+ allTools.map((tool) => [tool.name, tool])
1465
1445
  );
1466
1446
  return messages.map((message) => {
1467
1447
  if (message.role !== "tool") {
@@ -1474,20 +1454,20 @@ var ChatContextOptimizer = class {
1474
1454
  };
1475
1455
  }
1476
1456
  const toolCall = message.toolCallId ? toolCallMap.get(message.toolCallId) : void 0;
1477
- const tool2 = toolCall ? toolDefMap.get(toolCall.toolName) : void 0;
1457
+ const tool = toolCall ? toolDefMap.get(toolCall.toolName) : void 0;
1478
1458
  let content = message.content;
1479
1459
  try {
1480
1460
  const parsed = JSON.parse(message.content);
1481
1461
  content = buildToolResultContentForPrompt(
1482
1462
  parsed,
1483
- tool2,
1463
+ tool,
1484
1464
  toolCall?.args ?? {},
1485
1465
  this.config
1486
1466
  );
1487
1467
  } catch {
1488
1468
  content = buildToolResultContentForPrompt(
1489
1469
  message.content,
1490
- tool2,
1470
+ tool,
1491
1471
  toolCall?.args ?? {},
1492
1472
  this.config
1493
1473
  );
@@ -1610,10 +1590,20 @@ var AbstractChat = class {
1610
1590
  this.state.pushMessage(userMessage);
1611
1591
  this.state.status = "submitted";
1612
1592
  this.state.error = void 0;
1593
+ let preCreatedMessageId;
1594
+ if (this.config.streaming !== false) {
1595
+ const visibleMessages2 = this.state.messages;
1596
+ const currentLeafId = visibleMessages2.length > 0 ? visibleMessages2[visibleMessages2.length - 1].id : void 0;
1597
+ const preMsg = createEmptyAssistantMessage(void 0, {
1598
+ parentId: currentLeafId
1599
+ });
1600
+ this.state.pushMessage(preMsg);
1601
+ preCreatedMessageId = preMsg.id;
1602
+ }
1613
1603
  this.callbacks.onMessagesChange?.(this._allMessages());
1614
1604
  this.callbacks.onStatusChange?.("submitted");
1615
1605
  await Promise.resolve();
1616
- await this.processRequest();
1606
+ await this.processRequest({ preCreatedMessageId });
1617
1607
  return true;
1618
1608
  } catch (error) {
1619
1609
  this.handleError(error);
@@ -1733,6 +1723,44 @@ var AbstractChat = class {
1733
1723
  this.handleError(error);
1734
1724
  }
1735
1725
  }
1726
+ /**
1727
+ * Add tool result messages to history and stop — does NOT trigger a new LLM request.
1728
+ *
1729
+ * Use this instead of continueWithToolResults when you want to close out pending
1730
+ * tool_use blocks (so the history stays valid) without letting the AI continue.
1731
+ * Optionally appends a final assistant message (e.g. an iteration-limit notice).
1732
+ */
1733
+ async addToolResultMessages(toolResults, finalAssistantContent) {
1734
+ const visibleMessages = this.state.messages;
1735
+ let chainParentId = visibleMessages.length > 0 ? visibleMessages[visibleMessages.length - 1].id : void 0;
1736
+ for (const { toolCallId, result } of toolResults) {
1737
+ const messageContent = typeof result === "string" ? result : JSON.stringify(result);
1738
+ const toolMessageId = generateMessageId();
1739
+ const toolMessage = {
1740
+ id: toolMessageId,
1741
+ role: "tool",
1742
+ content: messageContent,
1743
+ toolCallId,
1744
+ createdAt: /* @__PURE__ */ new Date(),
1745
+ ...chainParentId !== void 0 ? { parentId: chainParentId } : {}
1746
+ };
1747
+ this.state.pushMessage(toolMessage);
1748
+ chainParentId = toolMessageId;
1749
+ }
1750
+ if (finalAssistantContent) {
1751
+ const assistantMsg = {
1752
+ id: generateMessageId(),
1753
+ role: "assistant",
1754
+ content: finalAssistantContent,
1755
+ createdAt: /* @__PURE__ */ new Date(),
1756
+ ...chainParentId !== void 0 ? { parentId: chainParentId } : {}
1757
+ };
1758
+ this.state.pushMessage(assistantMsg);
1759
+ }
1760
+ this.callbacks.onMessagesChange?.(this._allMessages());
1761
+ this.state.status = "ready";
1762
+ this.callbacks.onStatusChange?.("ready");
1763
+ }
1736
1764
  /**
1737
1765
  * Stop generation
1738
1766
  */
@@ -1837,10 +1865,10 @@ var AbstractChat = class {
1837
1865
  /**
1838
1866
  * Process a chat request
1839
1867
  */
1840
- async processRequest() {
1868
+ async processRequest(options) {
1841
1869
  const request = this.buildRequest();
1842
- let preCreatedMessageId;
1843
- if (this.config.streaming !== false) {
1870
+ let preCreatedMessageId = options?.preCreatedMessageId;
1871
+ if (this.config.streaming !== false && !preCreatedMessageId) {
1844
1872
  const visibleMessages = this.state.messages;
1845
1873
  const currentLeafId = visibleMessages.length > 0 ? visibleMessages[visibleMessages.length - 1].id : void 0;
1846
1874
  const preMsg = createEmptyAssistantMessage(void 0, {
@@ -1973,15 +2001,15 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
1973
2001
  threadId: this.config.threadId,
1974
2002
  systemPrompt,
1975
2003
  llm: this.config.llm,
1976
- tools: this.config.tools?.length ? this.config.tools.map((tool2) => ({
1977
- name: tool2.name,
1978
- description: tool2.description,
1979
- category: tool2.category,
1980
- group: tool2.group,
1981
- deferLoading: tool2.deferLoading,
1982
- profiles: tool2.profiles,
1983
- searchKeywords: tool2.searchKeywords,
1984
- inputSchema: tool2.inputSchema
2004
+ tools: this.config.tools?.length ? this.config.tools.map((tool) => ({
2005
+ name: tool.name,
2006
+ description: tool.description,
2007
+ category: tool.category,
2008
+ group: tool.group,
2009
+ deferLoading: tool.deferLoading,
2010
+ profiles: tool.profiles,
2011
+ searchKeywords: tool.searchKeywords,
2012
+ inputSchema: tool.inputSchema
1985
2013
  })) : void 0,
1986
2014
  __skills: this.inlineSkills.length ? this.inlineSkills : void 0
1987
2015
  };
@@ -2058,7 +2086,11 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
2058
2086
  }
2059
2087
  if (chunk.type === "message:start" && this.streamState === null) {
2060
2088
  this.debug("message:start after mid-stream end - creating new message");
2061
- const newMessage = createEmptyAssistantMessage();
2089
+ const currentLeaf = this.state.messages;
2090
+ const currentLeafId = currentLeaf.length > 0 ? currentLeaf[currentLeaf.length - 1].id : void 0;
2091
+ const newMessage = createEmptyAssistantMessage(void 0, {
2092
+ parentId: currentLeafId
2093
+ });
2062
2094
  this.state.pushMessage(newMessage);
2063
2095
  this.streamState = createStreamState(newMessage.id);
2064
2096
  this.callbacks.onMessageStart?.(newMessage.id);
@@ -2128,10 +2160,19 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
2128
2160
  break;
2129
2161
  }
2130
2162
  }
2163
+ const insertParentId = insertIdx > 0 ? currentMessages[insertIdx - 1].id : void 0;
2164
+ const linkedToInsert = messagesToInsert.map((msg, i) => ({
2165
+ ...msg,
2166
+ parentId: i === 0 ? insertParentId : messagesToInsert[i - 1].id
2167
+ }));
2168
+ const lastInsertedId = linkedToInsert[linkedToInsert.length - 1].id;
2169
+ const updatedCurrent = currentMessages.map(
2170
+ (m, idx) => idx === insertIdx ? { ...m, parentId: lastInsertedId } : m
2171
+ );
2131
2172
  this.state.setMessages([
2132
- ...currentMessages.slice(0, insertIdx),
2133
- ...messagesToInsert,
2134
- ...currentMessages.slice(insertIdx)
2173
+ ...updatedCurrent.slice(0, insertIdx),
2174
+ ...linkedToInsert,
2175
+ ...updatedCurrent.slice(insertIdx)
2135
2176
  ]);
2136
2177
  }
2137
2178
  }
@@ -2196,6 +2237,10 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
2196
2237
  ...existing.childrenIds !== void 0 ? { childrenIds: existing.childrenIds } : {}
2197
2238
  })
2198
2239
  );
2240
+ this.callbacks.onStreamChunk?.({
2241
+ ...chunk,
2242
+ messageId: assistantMessage.id
2243
+ });
2199
2244
  if (chunk.type === "message:delta") {
2200
2245
  this.callbacks.onMessageDelta?.(assistantMessage.id, chunk.content);
2201
2246
  }
@@ -2257,12 +2302,26 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
2257
2302
  (message) => message.id === this.streamState.messageId
2258
2303
  ) : -1;
2259
2304
  if (currentStreamIndex === -1) {
2260
- this.state.setMessages([...currentMessages, ...messagesToInsert]);
2305
+ const appendParentId = currentMessages.length > 0 ? currentMessages[currentMessages.length - 1].id : void 0;
2306
+ const linkedToInsert = messagesToInsert.map((msg, i) => ({
2307
+ ...msg,
2308
+ parentId: i === 0 ? appendParentId : messagesToInsert[i - 1].id
2309
+ }));
2310
+ this.state.setMessages([...currentMessages, ...linkedToInsert]);
2261
2311
  } else {
2312
+ const insertParentId = currentStreamIndex > 0 ? currentMessages[currentStreamIndex - 1].id : void 0;
2313
+ const linkedToInsert = messagesToInsert.map((msg, i) => ({
2314
+ ...msg,
2315
+ parentId: i === 0 ? insertParentId : messagesToInsert[i - 1].id
2316
+ }));
2317
+ const lastInsertedId = linkedToInsert[linkedToInsert.length - 1].id;
2318
+ const updatedCurrent = currentMessages.map(
2319
+ (m, idx) => idx === currentStreamIndex ? { ...m, parentId: lastInsertedId } : m
2320
+ );
2262
2321
  this.state.setMessages([
2263
- ...currentMessages.slice(0, currentStreamIndex),
2264
- ...messagesToInsert,
2265
- ...currentMessages.slice(currentStreamIndex)
2322
+ ...updatedCurrent.slice(0, currentStreamIndex),
2323
+ ...linkedToInsert,
2324
+ ...updatedCurrent.slice(currentStreamIndex)
2266
2325
  ]);
2267
2326
  }
2268
2327
  }
@@ -2419,7 +2478,7 @@ ${this.dynamicContext}`.trim() : this.config.systemPrompt;
2419
2478
  }
2420
2479
  get log() {
2421
2480
  if (!this._log) {
2422
- this._log = chunkB4YDIMP3_cjs.createLogger("streaming", () => this.config.debug ?? false);
2481
+ this._log = chunkKGYDGK3U_cjs.createLogger("streaming", () => this.config.debug ?? false);
2423
2482
  }
2424
2483
  return this._log;
2425
2484
  }
@@ -2502,8 +2561,8 @@ var AbstractAgentLoop = class {
2502
2561
  this._maxIterations = config.maxIterations ?? 20;
2503
2562
  this._maxExecutionHistory = config.maxExecutionHistory ?? 100;
2504
2563
  if (config.tools) {
2505
- for (const tool2 of config.tools) {
2506
- this.registerTool(tool2);
2564
+ for (const tool of config.tools) {
2565
+ this.registerTool(tool);
2507
2566
  }
2508
2567
  }
2509
2568
  }
@@ -2592,15 +2651,15 @@ var AbstractAgentLoop = class {
2592
2651
  * Register a tool (reference counted for React StrictMode compatibility)
2593
2652
  * Tools are never fully removed - ref counting ensures StrictMode works correctly
2594
2653
  */
2595
- registerTool(tool2) {
2596
- const existing = this.registeredTools.get(tool2.name);
2654
+ registerTool(tool) {
2655
+ const existing = this.registeredTools.get(tool.name);
2597
2656
  if (existing) {
2598
- existing.tool = tool2;
2657
+ existing.tool = tool;
2599
2658
  existing.refCount++;
2600
2659
  existing.active = true;
2601
2660
  } else {
2602
- this.registeredTools.set(tool2.name, {
2603
- tool: tool2,
2661
+ this.registeredTools.set(tool.name, {
2662
+ tool,
2604
2663
  refCount: 1,
2605
2664
  active: true
2606
2665
  });
@@ -2665,7 +2724,7 @@ var AbstractAgentLoop = class {
2665
2724
  * Execute a single tool
2666
2725
  */
2667
2726
  async executeSingleTool(toolCall) {
2668
- const tool2 = this.getTool(toolCall.name);
2727
+ const tool = this.getTool(toolCall.name);
2669
2728
  const execution = {
2670
2729
  id: toolCall.id,
2671
2730
  toolCallId: toolCall.id,
@@ -2674,11 +2733,11 @@ var AbstractAgentLoop = class {
2674
2733
  status: "pending",
2675
2734
  approvalStatus: "none",
2676
2735
  startedAt: /* @__PURE__ */ new Date(),
2677
- hidden: tool2?.hidden
2736
+ hidden: tool?.hidden
2678
2737
  };
2679
2738
  this.addToolExecution(execution);
2680
2739
  this.callbacks.onToolStart?.(execution);
2681
- if (!tool2) {
2740
+ if (!tool) {
2682
2741
  const errorResult = {
2683
2742
  toolCallId: toolCall.id,
2684
2743
  success: false,
@@ -2692,9 +2751,9 @@ var AbstractAgentLoop = class {
2692
2751
  return errorResult;
2693
2752
  }
2694
2753
  let approvalData;
2695
- if (tool2.needsApproval && !this.config.autoApprove) {
2696
- const approvalTitle = typeof tool2.approvalTitle === "function" ? tool2.approvalTitle(toolCall.args) : tool2.approvalTitle;
2697
- const approvalMessage = typeof tool2.approvalMessage === "function" ? tool2.approvalMessage(toolCall.args) : tool2.approvalMessage;
2754
+ if (tool.needsApproval && !this.config.autoApprove) {
2755
+ const approvalTitle = typeof tool.approvalTitle === "function" ? tool.approvalTitle(toolCall.args) : tool.approvalTitle;
2756
+ const approvalMessage = typeof tool.approvalMessage === "function" ? tool.approvalMessage(toolCall.args) : tool.approvalMessage;
2698
2757
  execution.approvalStatus = "required";
2699
2758
  execution.approvalTitle = approvalTitle;
2700
2759
  execution.approvalMessage = approvalMessage;
@@ -2723,13 +2782,13 @@ var AbstractAgentLoop = class {
2723
2782
  }
2724
2783
  this.updateToolExecution(toolCall.id, { status: "executing" });
2725
2784
  try {
2726
- if (!tool2.handler) {
2785
+ if (!tool.handler) {
2727
2786
  throw new Error(`Tool "${toolCall.name}" has no handler`);
2728
2787
  }
2729
2788
  if (this._isCancelled || this.abortController?.signal.aborted) {
2730
2789
  throw new Error("Tool execution cancelled");
2731
2790
  }
2732
- const result = await tool2.handler(toolCall.args, {
2791
+ const result = await tool.handler(toolCall.args, {
2733
2792
  signal: this.abortController?.signal,
2734
2793
  data: { toolCallId: toolCall.id },
2735
2794
  approvalData
@@ -2952,736 +3011,745 @@ var AbstractAgentLoop = class {
2952
3011
  }
2953
3012
  };
2954
3013
 
2955
- // src/chat/ChatWithTools.ts
2956
- var ChatWithTools = class {
2957
- constructor(config, callbacks = {}) {
2958
- this.config = config;
2959
- this.callbacks = callbacks;
2960
- this.agentLoop = new AbstractAgentLoop(
2961
- {
2962
- maxIterations: config.maxIterations ?? 20,
2963
- tools: config.tools
2964
- },
2965
- {
2966
- onExecutionsChange: (executions) => {
2967
- callbacks.onToolExecutionsChange?.(executions);
2968
- },
2969
- onApprovalRequired: (execution) => {
2970
- callbacks.onApprovalRequired?.(execution);
2971
- }
3014
+ // src/chat/branching/MessageTree.ts
3015
+ var _MessageTree = class _MessageTree {
3016
+ constructor(messages) {
3017
+ /** All messages by ID */
3018
+ this.nodeMap = /* @__PURE__ */ new Map();
3019
+ /** parentKey → ordered list of child IDs (insertion order = oldest-first) */
3020
+ this.childrenOf = /* @__PURE__ */ new Map();
3021
+ /** parentKey currently-active child ID */
3022
+ this.activeChildMap = /* @__PURE__ */ new Map();
3023
+ /** Current leaf message ID (tip of the active path) */
3024
+ this._currentLeafId = null;
3025
+ /** Cached visible messages — invalidated on every mutation */
3026
+ this._visibleCache = null;
3027
+ if (messages?.length) {
3028
+ this._buildFromMessages(messages);
3029
+ }
3030
+ }
3031
+ // ============================================
3032
+ // Static Migration Helpers
3033
+ // ============================================
3034
+ /**
3035
+ * Convert a legacy flat array (no parentId) to a tree-linked array.
3036
+ *
3037
+ * Rules:
3038
+ * - Tool messages get parentId = the owning assistant message's id
3039
+ * (matched via toolCallId → toolCall.id), chained in sequence.
3040
+ * - All other messages get parentId = the previous message in the linear
3041
+ * chain (including tool messages, so the next non-tool after tool results
3042
+ * is a child of the last tool result, not a sibling).
3043
+ *
3044
+ * Returns a new array with parentId/childrenIds filled in.
3045
+ * Does NOT mutate the original messages.
3046
+ */
3047
+ static fromFlatArray(messages) {
3048
+ if (messages.length === 0) return messages;
3049
+ const alreadyLinked = messages.some((m) => m.parentId !== void 0);
3050
+ if (alreadyLinked) return messages;
3051
+ const result = [];
3052
+ let prevId = null;
3053
+ const assistantById = /* @__PURE__ */ new Map();
3054
+ for (const msg of messages) {
3055
+ if (msg.role === "assistant") {
3056
+ assistantById.set(msg.id, msg);
2972
3057
  }
2973
- );
2974
- this.chat = new AbstractChat({
2975
- runtimeUrl: config.runtimeUrl,
2976
- llm: config.llm,
2977
- systemPrompt: config.systemPrompt,
2978
- streaming: config.streaming,
2979
- headers: config.headers,
2980
- body: config.body,
2981
- optimization: config.optimization,
2982
- threadId: config.threadId,
2983
- debug: config.debug,
2984
- initialMessages: config.initialMessages,
2985
- state: config.state,
2986
- transport: config.transport,
2987
- callbacks: {
2988
- onMessagesChange: callbacks.onMessagesChange,
2989
- onStatusChange: callbacks.onStatusChange,
2990
- onError: callbacks.onError,
2991
- onMessageStart: callbacks.onMessageStart,
2992
- onMessageDelta: callbacks.onMessageDelta,
2993
- onMessageFinish: callbacks.onMessageFinish,
2994
- onToolCalls: callbacks.onToolCalls,
2995
- onFinish: callbacks.onFinish,
2996
- onContextUsageChange: callbacks.onContextUsageChange,
2997
- // Server-side tool callbacks - track in agentLoop for UI display
2998
- // IMPORTANT: Only track tools that are NOT registered client-side
2999
- // Client-side tools are tracked via executeToolCalls() path
3000
- onServerToolStart: (info) => {
3001
- const existingExecution = this.agentLoop.toolExecutions.find(
3002
- (e) => e.id === info.id
3003
- );
3004
- if (existingExecution) {
3005
- if (info.hidden !== void 0 && existingExecution.hidden !== info.hidden) {
3006
- this.debug(
3007
- "Updating hidden flag for existing execution:",
3008
- info.name,
3009
- info.hidden
3010
- );
3011
- this.agentLoop.updateToolExecution(info.id, {
3012
- hidden: info.hidden
3013
- });
3014
- }
3015
- return;
3016
- }
3017
- const isClientTool = this.agentLoop.tools.some(
3018
- (t) => t.name === info.name && t.location === "client"
3019
- );
3020
- if (isClientTool) {
3021
- this.debug("Skipping server tracking for client tool:", info.name);
3022
- return;
3023
- }
3024
- this.debug("Server tool started:", info.name, {
3025
- hidden: info.hidden,
3026
- id: info.id
3027
- });
3028
- this.agentLoop.addServerToolExecution(info);
3029
- },
3030
- onServerToolArgs: (info) => {
3031
- const isClientTool = this.agentLoop.tools.some(
3032
- (t) => t.name === info.name && t.location === "client"
3033
- );
3034
- if (isClientTool) return;
3035
- this.debug("Server tool args:", info.name, info.args);
3036
- this.agentLoop.updateServerToolArgs(info.id, info.args ?? {});
3037
- },
3038
- onServerToolEnd: (info) => {
3039
- const isClientTool = this.agentLoop.tools.some(
3040
- (t) => t.name === info.name && t.location === "client"
3041
- );
3042
- if (isClientTool) return;
3043
- this.debug("Server tool ended:", info.name, {
3044
- error: info.error,
3045
- hasResult: !!info.result
3046
- });
3047
- this.agentLoop.completeServerToolExecution(info);
3048
- }
3049
- }
3050
- });
3051
- this.wireEvents();
3052
- }
3053
- /**
3054
- * Wire up internal events between chat and agent loop
3055
- */
3056
- wireEvents() {
3057
- this.debug("Wiring up toolCalls event handler");
3058
- this.chat.on("toolCalls", async (event) => {
3059
- const toolCalls = event.toolCalls;
3060
- if (!toolCalls?.length) {
3061
- return;
3062
- }
3063
- this.debug("Tool calls received:", toolCalls.length);
3064
- const toolCallInfos = toolCalls.map((tc) => {
3065
- const tcAny = tc;
3066
- const name = tcAny.function?.name ?? tcAny.name ?? "";
3067
- let args = {};
3068
- if (tcAny.function?.arguments) {
3069
- try {
3070
- args = JSON.parse(tcAny.function.arguments);
3071
- } catch {
3072
- args = {};
3058
+ }
3059
+ const lastToolIdByAssistant = /* @__PURE__ */ new Map();
3060
+ for (const msg of messages) {
3061
+ if (msg.role === "tool" && msg.toolCallId) {
3062
+ let ownerAssistantId = null;
3063
+ for (const [, assistant] of assistantById) {
3064
+ if (assistant.toolCalls?.some((tc) => tc.id === msg.toolCallId)) {
3065
+ ownerAssistantId = assistant.id;
3066
+ break;
3073
3067
  }
3074
- } else if (tcAny.args) {
3075
- args = tcAny.args;
3076
3068
  }
3077
- return { id: tc.id, name, args };
3078
- });
3079
- try {
3080
- const results = await this.agentLoop.executeToolCalls(toolCallInfos);
3081
- this.debug("Tool results:", results);
3082
- if (results.length > 0) {
3083
- const toolResults = results.map((r) => ({
3084
- toolCallId: r.toolCallId,
3085
- result: r.success ? r.result : { success: false, error: r.error }
3086
- }));
3087
- await this.chat.continueWithToolResults(toolResults);
3088
- } else if (this.agentLoop.maxIterationsReached && toolCallInfos.length > 0) {
3089
- this.debug("Max iterations reached, adding blocked tool results");
3090
- const errorMessage = this.config.maxIterationsMessage || "Tool execution paused: iteration limit reached. User can say 'continue' to resume.";
3091
- const blockedResults = toolCallInfos.map((tc) => ({
3092
- toolCallId: tc.id,
3093
- result: {
3094
- success: false,
3095
- error: errorMessage
3096
- }
3097
- }));
3098
- await this.chat.continueWithToolResults(blockedResults);
3069
+ const chainParent = ownerAssistantId ? lastToolIdByAssistant.get(ownerAssistantId) ?? ownerAssistantId : prevId ?? null;
3070
+ result.push({
3071
+ ...msg,
3072
+ parentId: chainParent,
3073
+ childrenIds: []
3074
+ });
3075
+ if (ownerAssistantId) {
3076
+ lastToolIdByAssistant.set(ownerAssistantId, msg.id);
3099
3077
  }
3100
- } catch (error) {
3101
- this.debug("Error executing tools:", error);
3102
- console.error("[ChatWithTools] Tool execution error:", error);
3078
+ prevId = msg.id;
3079
+ } else {
3080
+ result.push({
3081
+ ...msg,
3082
+ parentId: prevId,
3083
+ childrenIds: []
3084
+ });
3085
+ prevId = msg.id;
3103
3086
  }
3104
- });
3087
+ }
3088
+ const childrenMap = /* @__PURE__ */ new Map();
3089
+ for (const msg of result) {
3090
+ const parentKey = msg.parentId == null ? _MessageTree.ROOT_KEY : msg.parentId;
3091
+ if (!childrenMap.has(parentKey)) {
3092
+ childrenMap.set(parentKey, []);
3093
+ }
3094
+ childrenMap.get(parentKey).push(msg.id);
3095
+ }
3096
+ return result.map((msg) => ({
3097
+ ...msg,
3098
+ childrenIds: childrenMap.get(msg.id) ?? []
3099
+ }));
3105
3100
  }
3106
3101
  // ============================================
3107
- // Chat Getters
3102
+ // Core Queries
3108
3103
  // ============================================
3109
- get messages() {
3110
- return this.chat.messages;
3111
- }
3112
- get status() {
3113
- return this.chat.status;
3114
- }
3115
- get error() {
3116
- return this.chat.error;
3104
+ /**
3105
+ * Returns the visible path (root → current leaf) — what the UI renders
3106
+ * and what gets sent to the API.
3107
+ *
3108
+ * Backward-compat: if NO message has parentId set (all undefined),
3109
+ * falls back to insertion order (legacy linear mode).
3110
+ */
3111
+ getVisibleMessages() {
3112
+ if (this._visibleCache !== null) return this._visibleCache;
3113
+ if (this.nodeMap.size === 0) {
3114
+ this._visibleCache = [];
3115
+ return this._visibleCache;
3116
+ }
3117
+ const hasTreeStructure = Array.from(this.nodeMap.values()).some(
3118
+ (m) => m.parentId !== void 0
3119
+ );
3120
+ this._visibleCache = hasTreeStructure ? this._getActivePath().map((id) => this.nodeMap.get(id)) : Array.from(this.nodeMap.values());
3121
+ return this._visibleCache;
3117
3122
  }
3118
- get isStreaming() {
3119
- return this.chat.isStreaming;
3123
+ _invalidateCache() {
3124
+ this._visibleCache = null;
3120
3125
  }
3121
3126
  /**
3122
- * Whether any operation is in progress (chat or tools)
3123
- * Use this to show loading indicators and disable send button
3127
+ * Returns ALL messages across every branch (for persistence / ThreadManager).
3124
3128
  */
3125
- get isLoading() {
3126
- const chatBusy = this.status === "submitted" || this.status === "streaming";
3127
- const toolsBusy = this.agentLoop.isProcessing;
3128
- const hasPendingApprovals = this.agentLoop.pendingApprovalExecutions.length > 0;
3129
- return chatBusy || toolsBusy || hasPendingApprovals;
3129
+ getAllMessages() {
3130
+ return Array.from(this.nodeMap.values());
3130
3131
  }
3131
3132
  /**
3132
- * Check if a request is currently in progress (excludes pending approvals)
3133
- * Use this to prevent sending new messages
3133
+ * Branch navigation info for the UI navigator.
3134
+ * Returns null if the message has no siblings (only child).
3134
3135
  */
3135
- get isBusy() {
3136
- const chatBusy = this.status === "submitted" || this.status === "streaming";
3137
- const toolsBusy = this.agentLoop.isProcessing;
3138
- return chatBusy || toolsBusy;
3139
- }
3140
- // ============================================
3141
- // Tool Execution Getters
3142
- // ============================================
3143
- get toolExecutions() {
3144
- return this.agentLoop.toolExecutions;
3145
- }
3146
- get tools() {
3147
- return this.agentLoop.tools;
3148
- }
3149
- get iteration() {
3150
- return this.agentLoop.iteration;
3136
+ getBranchInfo(messageId) {
3137
+ const msg = this.nodeMap.get(messageId);
3138
+ if (!msg) return null;
3139
+ const parentKey = this._parentKey(msg.parentId);
3140
+ const siblings = this.childrenOf.get(parentKey) ?? [];
3141
+ if (siblings.length <= 1) return null;
3142
+ const siblingIndex = siblings.indexOf(messageId);
3143
+ return {
3144
+ siblingIndex,
3145
+ totalSiblings: siblings.length,
3146
+ siblingIds: [...siblings],
3147
+ hasPrevious: siblingIndex > 0,
3148
+ hasNext: siblingIndex < siblings.length - 1
3149
+ };
3151
3150
  }
3152
- get maxIterations() {
3153
- return this.agentLoop.maxIterations;
3151
+ get currentLeafId() {
3152
+ return this._currentLeafId;
3154
3153
  }
3155
- get isProcessing() {
3156
- return this.agentLoop.isProcessing;
3154
+ get hasBranches() {
3155
+ for (const children of this.childrenOf.values()) {
3156
+ if (children.length > 1) return true;
3157
+ }
3158
+ return false;
3157
3159
  }
3158
3160
  // ============================================
3159
- // Chat Actions
3161
+ // Mutations
3160
3162
  // ============================================
3161
3163
  /**
3162
- * Send a message
3163
- * Returns false if a request is already in progress
3164
- *
3165
- * @param options.editMessageId - Edit flow: new message branches from the
3166
- * same parent as this message ID
3164
+ * Insert a new message.
3165
+ * - Updates childrenOf and nodeMap.
3166
+ * - New branch becomes active (activeChildMap updated).
3167
+ * - Updates current leaf.
3167
3168
  */
3168
- async sendMessage(content, attachments, options) {
3169
- if (this.isLoading) {
3170
- this.debug("sendMessage blocked - request already in progress");
3171
- return false;
3169
+ addMessage(message) {
3170
+ this.nodeMap.set(message.id, message);
3171
+ const parentKey = this._parentKey(message.parentId);
3172
+ if (!this.childrenOf.has(parentKey)) {
3173
+ this.childrenOf.set(parentKey, []);
3172
3174
  }
3173
- this.agentLoop.resetIterations();
3174
- return await this.chat.sendMessage(content, attachments, options);
3175
- }
3176
- /**
3177
- * Stop generation and cancel any running tools
3178
- */
3179
- stop() {
3180
- this.agentLoop.cancel();
3181
- this.chat.stop();
3182
- this.debug("Stopped - cancelled tools and aborted stream");
3183
- }
3184
- /**
3185
- * Clear all messages
3186
- */
3187
- clearMessages() {
3188
- this.chat.clearMessages();
3189
- this.agentLoop.clearToolExecutions();
3190
- }
3191
- /**
3192
- * Set messages directly
3193
- */
3194
- setMessages(messages) {
3195
- this.chat.setMessages(messages);
3196
- }
3197
- /**
3198
- * Regenerate last response
3199
- */
3200
- async regenerate(messageId) {
3201
- await this.chat.regenerate(messageId);
3202
- }
3203
- /**
3204
- * Set tools available for the LLM
3205
- */
3206
- setTools(tools) {
3207
- this.chat.setTools(tools);
3208
- }
3209
- /**
3210
- * Update prompt/tool optimization controls.
3211
- */
3212
- setOptimizationConfig(config) {
3213
- this.config.optimization = config;
3214
- this.chat.setOptimizationConfig(config);
3215
- }
3216
- /**
3217
- * Set the active tool profile used for request-time tool selection.
3218
- */
3219
- setToolProfile(profile) {
3220
- this.chat.setToolProfile(profile);
3221
- }
3222
- /**
3223
- * Get the most recent prompt context usage snapshot.
3224
- */
3225
- getContextUsage() {
3226
- return this.chat.getContextUsage();
3227
- }
3228
- /**
3229
- * Set dynamic context (from useAIContext hook)
3230
- */
3231
- setContext(context) {
3232
- this.chat.setContext(context);
3233
- }
3234
- /**
3235
- * Set system prompt dynamically
3236
- */
3237
- setSystemPrompt(prompt) {
3238
- this.chat.setSystemPrompt(prompt);
3239
- }
3240
- /**
3241
- * Set headers configuration
3242
- * Can be static headers or a getter function for dynamic resolution
3243
- */
3244
- setHeaders(headers) {
3245
- this.chat.setHeaders(headers);
3246
- }
3247
- /**
3248
- * Set URL configuration
3249
- * Can be static URL or a getter function for dynamic resolution
3250
- */
3251
- setUrl(url) {
3252
- this.chat.setUrl(url);
3253
- }
3254
- /**
3255
- * Set body configuration
3256
- * Additional properties merged into every request body
3257
- */
3258
- setBody(body) {
3259
- this.chat.setBody(body);
3260
- }
3261
- setRequestMessageTransform(fn) {
3262
- this.chat.setRequestMessageTransform(fn);
3263
- }
3264
- /**
3265
- * Set inline skills (forwarded to underlying chat instance)
3266
- */
3267
- setInlineSkills(skills) {
3268
- this.chat.setInlineSkills(skills);
3269
- }
3270
- // ============================================
3271
- // Tool Registration
3272
- // ============================================
3273
- /**
3274
- * Register a tool
3275
- */
3276
- registerTool(tool2) {
3277
- this.agentLoop.registerTool(tool2);
3278
- this.chat.setTools(this.agentLoop.tools);
3175
+ const siblings = this.childrenOf.get(parentKey);
3176
+ if (!siblings.includes(message.id)) {
3177
+ siblings.push(message.id);
3178
+ }
3179
+ this.activeChildMap.set(parentKey, message.id);
3180
+ this._currentLeafId = this._walkToLeaf(message.id);
3181
+ this._invalidateCache();
3182
+ return message;
3279
3183
  }
3280
3184
  /**
3281
- * Unregister a tool
3185
+ * Navigate: make messageId the active child at its parent fork,
3186
+ * then walk to its leaf and update currentLeafId.
3282
3187
  */
3283
- unregisterTool(name) {
3284
- this.agentLoop.unregisterTool(name);
3285
- this.chat.setTools(this.agentLoop.tools);
3188
+ switchBranch(messageId) {
3189
+ const msg = this.nodeMap.get(messageId);
3190
+ if (!msg) return;
3191
+ const parentKey = this._parentKey(msg.parentId);
3192
+ this.activeChildMap.set(parentKey, messageId);
3193
+ this._currentLeafId = this._walkToLeaf(messageId);
3194
+ this._invalidateCache();
3286
3195
  }
3287
- // ============================================
3288
- // Tool Approval
3289
- // ============================================
3290
3196
  /**
3291
- * Approve a tool execution with optional extra data
3197
+ * Update message content in-place (streaming updates).
3198
+ * No tree structure change.
3292
3199
  */
3293
- approveToolExecution(id, extraData, permissionLevel) {
3294
- this.agentLoop.approveToolExecution(id, extraData, permissionLevel);
3200
+ updateMessage(id, updater) {
3201
+ const existing = this.nodeMap.get(id);
3202
+ if (!existing) return false;
3203
+ this.nodeMap.set(id, updater(existing));
3204
+ this._invalidateCache();
3205
+ return true;
3295
3206
  }
3296
3207
  /**
3297
- * Reject a tool execution
3208
+ * Set current leaf explicitly.
3209
+ * Used by regenerate() to rewind the active path before pushing a new message.
3298
3210
  */
3299
- rejectToolExecution(id, reason, permissionLevel) {
3300
- this.agentLoop.rejectToolExecution(id, reason, permissionLevel);
3211
+ setCurrentLeaf(leafId) {
3212
+ this._currentLeafId = leafId;
3213
+ if (leafId === null) return;
3214
+ const msg = this.nodeMap.get(leafId);
3215
+ if (!msg) return;
3216
+ let current = msg;
3217
+ while (current) {
3218
+ const parentKey = this._parentKey(current.parentId);
3219
+ this.activeChildMap.set(parentKey, current.id);
3220
+ if (current.parentId == null || current.parentId === void 0) break;
3221
+ current = this.nodeMap.get(current.parentId);
3222
+ }
3223
+ this._invalidateCache();
3301
3224
  }
3302
3225
  /**
3303
- * Clear tool executions
3226
+ * Rebuild entire tree from a message array.
3227
+ * Used by setMessages().
3304
3228
  */
3305
- clearToolExecutions() {
3306
- this.agentLoop.clearToolExecutions();
3229
+ reset(messages) {
3230
+ this.nodeMap.clear();
3231
+ this.childrenOf.clear();
3232
+ this.activeChildMap.clear();
3233
+ this._currentLeafId = null;
3234
+ this._invalidateCache();
3235
+ if (messages.length > 0) {
3236
+ this._buildFromMessages(messages);
3237
+ }
3307
3238
  }
3308
3239
  // ============================================
3309
- // Event Subscriptions (for framework adapters)
3240
+ // Private Helpers
3310
3241
  // ============================================
3311
- /**
3312
- * Subscribe to chat events
3313
- */
3314
- on(event, handler) {
3315
- return this.chat.on(event, handler);
3242
+ _buildFromMessages(messages) {
3243
+ const linked = messages.some((m) => m.parentId !== void 0) ? messages : _MessageTree.fromFlatArray(messages);
3244
+ for (const msg of linked) {
3245
+ this.nodeMap.set(msg.id, msg);
3246
+ const parentKey = this._parentKey(msg.parentId);
3247
+ if (!this.childrenOf.has(parentKey)) {
3248
+ this.childrenOf.set(parentKey, []);
3249
+ }
3250
+ const siblings = this.childrenOf.get(parentKey);
3251
+ if (!siblings.includes(msg.id)) {
3252
+ siblings.push(msg.id);
3253
+ }
3254
+ }
3255
+ for (const [parentKey, children] of this.childrenOf) {
3256
+ if (children.length > 0) {
3257
+ this.activeChildMap.set(parentKey, children[children.length - 1]);
3258
+ }
3259
+ }
3260
+ const path = this._getActivePath();
3261
+ this._currentLeafId = path.length > 0 ? path[path.length - 1] : null;
3316
3262
  }
3317
- // ============================================
3318
- // Cleanup
3319
- // ============================================
3320
- /**
3321
- * Whether this instance has been disposed
3322
- */
3323
- get disposed() {
3324
- return this.chat.disposed;
3263
+ _parentKey(parentId) {
3264
+ if (parentId == null || parentId === void 0) {
3265
+ return _MessageTree.ROOT_KEY;
3266
+ }
3267
+ return parentId;
3325
3268
  }
3326
3269
  /**
3327
- * Revive a disposed instance (for React StrictMode compatibility)
3328
- * This allows reusing an instance after dispose() was called,
3329
- * preserving registered tools and state
3270
+ * Walk forward from a message along active children to find the leaf.
3330
3271
  */
3331
- revive() {
3332
- this.chat.revive();
3333
- this.agentLoop.revive();
3272
+ _walkToLeaf(fromId) {
3273
+ let current = fromId;
3274
+ while (true) {
3275
+ const children = this.childrenOf.get(current);
3276
+ if (!children || children.length === 0) break;
3277
+ const activeChild = this.activeChildMap.get(current);
3278
+ if (!activeChild) break;
3279
+ if (!this.nodeMap.has(activeChild)) break;
3280
+ current = activeChild;
3281
+ }
3282
+ return current;
3334
3283
  }
3335
3284
  /**
3336
- * Dispose and cleanup
3285
+ * Walk the active path from root to the current leaf.
3337
3286
  */
3338
- dispose() {
3339
- this.chat.dispose();
3340
- this.agentLoop.dispose();
3341
- }
3342
- // ============================================
3343
- // Private
3344
- // ============================================
3345
- debug(message, ...args) {
3346
- chunkB4YDIMP3_cjs.createLogger("tools", () => this.config.debug ?? false)(
3347
- message,
3348
- args.length === 1 ? args[0] : args.length > 1 ? args : void 0
3349
- );
3287
+ _getActivePath() {
3288
+ const path = [];
3289
+ const visited = /* @__PURE__ */ new Set();
3290
+ const rootChildren = this.childrenOf.get(_MessageTree.ROOT_KEY) ?? [];
3291
+ if (rootChildren.length === 0) return path;
3292
+ let activeId = this.activeChildMap.get(_MessageTree.ROOT_KEY);
3293
+ if (!activeId) {
3294
+ activeId = rootChildren[rootChildren.length - 1];
3295
+ }
3296
+ let current = activeId;
3297
+ while (current && !visited.has(current)) {
3298
+ if (!this.nodeMap.has(current)) break;
3299
+ visited.add(current);
3300
+ path.push(current);
3301
+ const activeChild = this.activeChildMap.get(current);
3302
+ if (!activeChild || !this.nodeMap.has(activeChild)) break;
3303
+ current = activeChild;
3304
+ }
3305
+ return path;
3350
3306
  }
3351
3307
  };
3308
+ /** Sentinel key used for root-level messages (parentId === null) */
3309
+ _MessageTree.ROOT_KEY = "__root__";
3310
+ var MessageTree = _MessageTree;
3352
3311
 
3353
- // src/chat/branching/MessageTree.ts
3354
- var _MessageTree = class _MessageTree {
3355
- constructor(messages) {
3356
- /** All messages by ID */
3357
- this.nodeMap = /* @__PURE__ */ new Map();
3358
- /** parentKey ordered list of child IDs (insertion order = oldest-first) */
3359
- this.childrenOf = /* @__PURE__ */ new Map();
3360
- /** parentKey currently-active child ID */
3361
- this.activeChildMap = /* @__PURE__ */ new Map();
3362
- /** Current leaf message ID (tip of the active path) */
3363
- this._currentLeafId = null;
3364
- /** Cached visible messages — invalidated on every mutation */
3365
- this._visibleCache = null;
3366
- if (messages?.length) {
3367
- this._buildFromMessages(messages);
3368
- }
3312
+ // src/chat/ChatWithTools.ts
3313
+ var ChatWithTools = class {
3314
+ constructor(config, callbacks = {}) {
3315
+ this.config = config;
3316
+ this.callbacks = callbacks;
3317
+ this.agentLoop = new AbstractAgentLoop(
3318
+ {
3319
+ maxIterations: config.maxIterations ?? 20,
3320
+ tools: config.tools
3321
+ },
3322
+ {
3323
+ onExecutionsChange: (executions) => {
3324
+ callbacks.onToolExecutionsChange?.(executions);
3325
+ },
3326
+ onApprovalRequired: (execution) => {
3327
+ callbacks.onApprovalRequired?.(execution);
3328
+ }
3329
+ }
3330
+ );
3331
+ this.chat = new AbstractChat({
3332
+ runtimeUrl: config.runtimeUrl,
3333
+ llm: config.llm,
3334
+ systemPrompt: config.systemPrompt,
3335
+ streaming: config.streaming,
3336
+ headers: config.headers,
3337
+ body: config.body,
3338
+ optimization: config.optimization,
3339
+ threadId: config.threadId,
3340
+ debug: config.debug,
3341
+ initialMessages: config.initialMessages,
3342
+ state: config.state,
3343
+ transport: config.transport,
3344
+ callbacks: {
3345
+ onMessagesChange: callbacks.onMessagesChange,
3346
+ onStatusChange: callbacks.onStatusChange,
3347
+ onError: callbacks.onError,
3348
+ onMessageStart: callbacks.onMessageStart,
3349
+ onMessageDelta: callbacks.onMessageDelta,
3350
+ onMessageFinish: callbacks.onMessageFinish,
3351
+ onToolCalls: callbacks.onToolCalls,
3352
+ onFinish: callbacks.onFinish,
3353
+ onContextUsageChange: callbacks.onContextUsageChange,
3354
+ // Server-side tool callbacks - track in agentLoop for UI display
3355
+ // IMPORTANT: Only track tools that are NOT registered client-side
3356
+ // Client-side tools are tracked via executeToolCalls() path
3357
+ onServerToolStart: (info) => {
3358
+ const existingExecution = this.agentLoop.toolExecutions.find(
3359
+ (e) => e.id === info.id
3360
+ );
3361
+ if (existingExecution) {
3362
+ if (info.hidden !== void 0 && existingExecution.hidden !== info.hidden) {
3363
+ this.debug(
3364
+ "Updating hidden flag for existing execution:",
3365
+ info.name,
3366
+ info.hidden
3367
+ );
3368
+ this.agentLoop.updateToolExecution(info.id, {
3369
+ hidden: info.hidden
3370
+ });
3371
+ }
3372
+ return;
3373
+ }
3374
+ const isClientTool = this.agentLoop.tools.some(
3375
+ (t) => t.name === info.name && t.location === "client"
3376
+ );
3377
+ if (isClientTool) {
3378
+ this.debug("Skipping server tracking for client tool:", info.name);
3379
+ return;
3380
+ }
3381
+ this.debug("Server tool started:", info.name, {
3382
+ hidden: info.hidden,
3383
+ id: info.id
3384
+ });
3385
+ this.agentLoop.addServerToolExecution(info);
3386
+ },
3387
+ onServerToolArgs: (info) => {
3388
+ const isClientTool = this.agentLoop.tools.some(
3389
+ (t) => t.name === info.name && t.location === "client"
3390
+ );
3391
+ if (isClientTool) return;
3392
+ this.debug("Server tool args:", info.name, info.args);
3393
+ this.agentLoop.updateServerToolArgs(info.id, info.args ?? {});
3394
+ },
3395
+ onServerToolEnd: (info) => {
3396
+ const isClientTool = this.agentLoop.tools.some(
3397
+ (t) => t.name === info.name && t.location === "client"
3398
+ );
3399
+ if (isClientTool) return;
3400
+ this.debug("Server tool ended:", info.name, {
3401
+ error: info.error,
3402
+ hasResult: !!info.result
3403
+ });
3404
+ this.agentLoop.completeServerToolExecution(info);
3405
+ }
3406
+ }
3407
+ });
3408
+ this.wireEvents();
3369
3409
  }
3370
- // ============================================
3371
- // Static Migration Helpers
3372
- // ============================================
3373
3410
  /**
3374
- * Convert a legacy flat array (no parentId) to a tree-linked array.
3375
- *
3376
- * Rules:
3377
- * - Tool messages get parentId = the owning assistant message's id
3378
- * (matched via toolCallId → toolCall.id).
3379
- * - All other messages get parentId of the previous non-tool message
3380
- * (or null for the first message).
3381
- *
3382
- * Returns a new array with parentId/childrenIds filled in.
3383
- * Does NOT mutate the original messages.
3411
+ * Wire up internal events between chat and agent loop
3384
3412
  */
3385
- static fromFlatArray(messages) {
3386
- if (messages.length === 0) return messages;
3387
- const alreadyLinked = messages.some((m) => m.parentId !== void 0);
3388
- if (alreadyLinked) return messages;
3389
- const result = [];
3390
- let prevNonToolId = null;
3391
- const assistantById = /* @__PURE__ */ new Map();
3392
- for (const msg of messages) {
3393
- if (msg.role === "assistant") {
3394
- assistantById.set(msg.id, msg);
3413
+ wireEvents() {
3414
+ this.debug("Wiring up toolCalls event handler");
3415
+ this.chat.on("toolCalls", async (event) => {
3416
+ const toolCalls = event.toolCalls;
3417
+ if (!toolCalls?.length) {
3418
+ return;
3395
3419
  }
3396
- }
3397
- for (const msg of messages) {
3398
- if (msg.role === "tool" && msg.toolCallId) {
3399
- let ownerAssistantId = null;
3400
- for (const [, assistant] of assistantById) {
3401
- if (assistant.toolCalls?.some((tc) => tc.id === msg.toolCallId)) {
3402
- ownerAssistantId = assistant.id;
3403
- break;
3420
+ this.debug("Tool calls received:", toolCalls.length);
3421
+ const toolCallInfos = toolCalls.map((tc) => {
3422
+ const tcAny = tc;
3423
+ const name = tcAny.function?.name ?? tcAny.name ?? "";
3424
+ let args = {};
3425
+ if (tcAny.function?.arguments) {
3426
+ try {
3427
+ args = JSON.parse(tcAny.function.arguments);
3428
+ } catch {
3429
+ args = {};
3404
3430
  }
3431
+ } else if (tcAny.args) {
3432
+ args = tcAny.args;
3405
3433
  }
3406
- result.push({
3407
- ...msg,
3408
- parentId: ownerAssistantId ?? prevNonToolId,
3409
- childrenIds: []
3410
- });
3411
- } else {
3412
- result.push({
3413
- ...msg,
3414
- parentId: prevNonToolId,
3415
- childrenIds: []
3416
- });
3417
- prevNonToolId = msg.id;
3418
- }
3419
- }
3420
- const childrenMap = /* @__PURE__ */ new Map();
3421
- for (const msg of result) {
3422
- const parentKey = msg.parentId == null ? _MessageTree.ROOT_KEY : msg.parentId;
3423
- if (!childrenMap.has(parentKey)) {
3424
- childrenMap.set(parentKey, []);
3434
+ return { id: tc.id, name, args };
3435
+ });
3436
+ try {
3437
+ const results = await this.agentLoop.executeToolCalls(toolCallInfos);
3438
+ this.debug("Tool results:", results);
3439
+ if (results.length > 0) {
3440
+ const toolResults = results.map((r) => ({
3441
+ toolCallId: r.toolCallId,
3442
+ result: r.success ? r.result : { success: false, error: r.error }
3443
+ }));
3444
+ await this.chat.continueWithToolResults(toolResults);
3445
+ } else if (this.agentLoop.maxIterationsReached && toolCallInfos.length > 0) {
3446
+ this.debug(
3447
+ "Max iterations reached, stopping loop without new LLM request"
3448
+ );
3449
+ const errorMessage = this.config.maxIterationsMessage || "Tool execution paused: iteration limit reached. User can say 'continue' to resume.";
3450
+ const blockedResults = toolCallInfos.map((tc) => ({
3451
+ toolCallId: tc.id,
3452
+ result: {
3453
+ success: false,
3454
+ error: errorMessage
3455
+ }
3456
+ }));
3457
+ await this.chat.addToolResultMessages(blockedResults, errorMessage);
3458
+ }
3459
+ } catch (error) {
3460
+ this.debug("Error executing tools:", error);
3461
+ console.error("[ChatWithTools] Tool execution error:", error);
3425
3462
  }
3426
- childrenMap.get(parentKey).push(msg.id);
3427
- }
3428
- return result.map((msg) => ({
3429
- ...msg,
3430
- childrenIds: childrenMap.get(msg.id) ?? []
3431
- }));
3463
+ });
3432
3464
  }
3433
3465
  // ============================================
3434
- // Core Queries
3466
+ // Chat Getters
3435
3467
  // ============================================
3436
- /**
3437
- * Returns the visible path (root → current leaf) — what the UI renders
3438
- * and what gets sent to the API.
3439
- *
3440
- * Backward-compat: if NO message has parentId set (all undefined),
3441
- * falls back to insertion order (legacy linear mode).
3442
- */
3443
- getVisibleMessages() {
3444
- if (this._visibleCache !== null) return this._visibleCache;
3445
- if (this.nodeMap.size === 0) {
3446
- this._visibleCache = [];
3447
- return this._visibleCache;
3448
- }
3449
- const hasTreeStructure = Array.from(this.nodeMap.values()).some(
3450
- (m) => m.parentId !== void 0
3451
- );
3452
- this._visibleCache = hasTreeStructure ? this._getActivePath().map((id) => this.nodeMap.get(id)) : Array.from(this.nodeMap.values());
3453
- return this._visibleCache;
3468
+ get messages() {
3469
+ return this.chat.messages;
3454
3470
  }
3455
- _invalidateCache() {
3456
- this._visibleCache = null;
3471
+ get status() {
3472
+ return this.chat.status;
3473
+ }
3474
+ get error() {
3475
+ return this.chat.error;
3476
+ }
3477
+ get isStreaming() {
3478
+ return this.chat.isStreaming;
3457
3479
  }
3458
3480
  /**
3459
- * Returns ALL messages across every branch (for persistence / ThreadManager).
3481
+ * Whether any operation is in progress (chat or tools)
3482
+ * Use this to show loading indicators and disable send button
3460
3483
  */
3461
- getAllMessages() {
3462
- return Array.from(this.nodeMap.values());
3484
+ get isLoading() {
3485
+ const chatBusy = this.status === "submitted" || this.status === "streaming";
3486
+ const toolsBusy = this.agentLoop.isProcessing;
3487
+ const hasPendingApprovals = this.agentLoop.pendingApprovalExecutions.length > 0;
3488
+ return chatBusy || toolsBusy || hasPendingApprovals;
3463
3489
  }
3464
3490
  /**
3465
- * Branch navigation info for the UI navigator.
3466
- * Returns null if the message has no siblings (only child).
3491
+ * Check if a request is currently in progress (excludes pending approvals)
3492
+ * Use this to prevent sending new messages
3467
3493
  */
3468
- getBranchInfo(messageId) {
3469
- const msg = this.nodeMap.get(messageId);
3470
- if (!msg) return null;
3471
- const parentKey = this._parentKey(msg.parentId);
3472
- const siblings = this.childrenOf.get(parentKey) ?? [];
3473
- if (siblings.length <= 1) return null;
3474
- const siblingIndex = siblings.indexOf(messageId);
3475
- return {
3476
- siblingIndex,
3477
- totalSiblings: siblings.length,
3478
- siblingIds: [...siblings],
3479
- hasPrevious: siblingIndex > 0,
3480
- hasNext: siblingIndex < siblings.length - 1
3481
- };
3494
+ get isBusy() {
3495
+ const chatBusy = this.status === "submitted" || this.status === "streaming";
3496
+ const toolsBusy = this.agentLoop.isProcessing;
3497
+ return chatBusy || toolsBusy;
3482
3498
  }
3483
- get currentLeafId() {
3484
- return this._currentLeafId;
3499
+ // ============================================
3500
+ // Tool Execution Getters
3501
+ // ============================================
3502
+ get toolExecutions() {
3503
+ return this.agentLoop.toolExecutions;
3485
3504
  }
3486
- get hasBranches() {
3487
- for (const children of this.childrenOf.values()) {
3488
- if (children.length > 1) return true;
3489
- }
3490
- return false;
3505
+ get tools() {
3506
+ return this.agentLoop.tools;
3507
+ }
3508
+ get iteration() {
3509
+ return this.agentLoop.iteration;
3510
+ }
3511
+ get maxIterations() {
3512
+ return this.agentLoop.maxIterations;
3513
+ }
3514
+ get isProcessing() {
3515
+ return this.agentLoop.isProcessing;
3491
3516
  }
3492
3517
  // ============================================
3493
- // Mutations
3518
+ // Chat Actions
3494
3519
  // ============================================
3495
3520
  /**
3496
- * Insert a new message.
3497
- * - Updates childrenOf and nodeMap.
3498
- * - New branch becomes active (activeChildMap updated).
3499
- * - Updates current leaf.
3521
+ * Send a message
3522
+ * Returns false if a request is already in progress
3523
+ *
3524
+ * @param options.editMessageId - Edit flow: new message branches from the
3525
+ * same parent as this message ID
3500
3526
  */
3501
- addMessage(message) {
3502
- this.nodeMap.set(message.id, message);
3503
- const parentKey = this._parentKey(message.parentId);
3504
- if (!this.childrenOf.has(parentKey)) {
3505
- this.childrenOf.set(parentKey, []);
3506
- }
3507
- const siblings = this.childrenOf.get(parentKey);
3508
- if (!siblings.includes(message.id)) {
3509
- siblings.push(message.id);
3527
+ async sendMessage(content, attachments, options) {
3528
+ if (this.isLoading) {
3529
+ this.debug("sendMessage blocked - request already in progress");
3530
+ return false;
3510
3531
  }
3511
- this.activeChildMap.set(parentKey, message.id);
3512
- this._currentLeafId = this._walkToLeaf(message.id);
3513
- this._invalidateCache();
3514
- return message;
3532
+ this.agentLoop.resetIterations();
3533
+ return await this.chat.sendMessage(content, attachments, options);
3515
3534
  }
3516
3535
  /**
3517
- * Navigate: make messageId the active child at its parent fork,
3518
- * then walk to its leaf and update currentLeafId.
3536
+ * Stop generation and cancel any running tools
3519
3537
  */
3520
- switchBranch(messageId) {
3521
- const msg = this.nodeMap.get(messageId);
3522
- if (!msg) return;
3523
- const parentKey = this._parentKey(msg.parentId);
3524
- this.activeChildMap.set(parentKey, messageId);
3525
- this._currentLeafId = this._walkToLeaf(messageId);
3526
- this._invalidateCache();
3538
+ stop() {
3539
+ this.agentLoop.cancel();
3540
+ this.chat.stop();
3541
+ this.debug("Stopped - cancelled tools and aborted stream");
3527
3542
  }
3528
3543
  /**
3529
- * Update message content in-place (streaming updates).
3530
- * No tree structure change.
3544
+ * Clear all messages
3531
3545
  */
3532
- updateMessage(id, updater) {
3533
- const existing = this.nodeMap.get(id);
3534
- if (!existing) return false;
3535
- this.nodeMap.set(id, updater(existing));
3536
- this._invalidateCache();
3537
- return true;
3546
+ clearMessages() {
3547
+ this.chat.clearMessages();
3548
+ this.agentLoop.clearToolExecutions();
3538
3549
  }
3539
3550
  /**
3540
- * Set current leaf explicitly.
3541
- * Used by regenerate() to rewind the active path before pushing a new message.
3551
+ * Set messages directly
3542
3552
  */
3543
- setCurrentLeaf(leafId) {
3544
- this._currentLeafId = leafId;
3545
- if (leafId === null) return;
3546
- const msg = this.nodeMap.get(leafId);
3547
- if (!msg) return;
3548
- let current = msg;
3549
- while (current) {
3550
- const parentKey = this._parentKey(current.parentId);
3551
- this.activeChildMap.set(parentKey, current.id);
3552
- if (current.parentId == null || current.parentId === void 0) break;
3553
- current = this.nodeMap.get(current.parentId);
3554
- }
3555
- this._invalidateCache();
3553
+ setMessages(messages) {
3554
+ this.chat.setMessages(messages);
3556
3555
  }
3557
3556
  /**
3558
- * Rebuild entire tree from a message array.
3559
- * Used by setMessages().
3557
+ * Regenerate last response
3560
3558
  */
3561
- reset(messages) {
3562
- this.nodeMap.clear();
3563
- this.childrenOf.clear();
3564
- this.activeChildMap.clear();
3565
- this._currentLeafId = null;
3566
- this._invalidateCache();
3567
- if (messages.length > 0) {
3568
- this._buildFromMessages(messages);
3569
- }
3570
- }
3571
- // ============================================
3572
- // Private Helpers
3573
- // ============================================
3574
- _buildFromMessages(messages) {
3575
- const linked = messages.some((m) => m.parentId !== void 0) ? messages : _MessageTree.fromFlatArray(messages);
3576
- for (const msg of linked) {
3577
- this.nodeMap.set(msg.id, msg);
3578
- const parentKey = this._parentKey(msg.parentId);
3579
- if (!this.childrenOf.has(parentKey)) {
3580
- this.childrenOf.set(parentKey, []);
3581
- }
3582
- const siblings = this.childrenOf.get(parentKey);
3583
- if (!siblings.includes(msg.id)) {
3584
- siblings.push(msg.id);
3585
- }
3586
- }
3587
- for (const [parentKey, children] of this.childrenOf) {
3588
- if (children.length > 0) {
3589
- this.activeChildMap.set(parentKey, children[children.length - 1]);
3590
- }
3591
- }
3592
- const path = this._getActivePath();
3593
- this._currentLeafId = path.length > 0 ? path[path.length - 1] : null;
3559
+ async regenerate(messageId) {
3560
+ await this.chat.regenerate(messageId);
3594
3561
  }
3595
- _parentKey(parentId) {
3596
- if (parentId == null || parentId === void 0) {
3597
- return _MessageTree.ROOT_KEY;
3598
- }
3599
- return parentId;
3562
+ /**
3563
+ * Set tools available for the LLM
3564
+ */
3565
+ setTools(tools) {
3566
+ this.chat.setTools(tools);
3600
3567
  }
3601
3568
  /**
3602
- * Walk forward from a message along active children to find the leaf.
3569
+ * Update prompt/tool optimization controls.
3603
3570
  */
3604
- _walkToLeaf(fromId) {
3605
- let current = fromId;
3606
- while (true) {
3607
- const children = this.childrenOf.get(current);
3608
- if (!children || children.length === 0) break;
3609
- const activeChild = this.activeChildMap.get(current);
3610
- if (!activeChild) break;
3611
- if (!this.nodeMap.has(activeChild)) break;
3612
- current = activeChild;
3613
- }
3614
- return current;
3571
+ setOptimizationConfig(config) {
3572
+ this.config.optimization = config;
3573
+ this.chat.setOptimizationConfig(config);
3615
3574
  }
3616
3575
  /**
3617
- * Walk the active path from root to the current leaf.
3576
+ * Set the active tool profile used for request-time tool selection.
3618
3577
  */
3619
- _getActivePath() {
3620
- const path = [];
3621
- const visited = /* @__PURE__ */ new Set();
3622
- const rootChildren = this.childrenOf.get(_MessageTree.ROOT_KEY) ?? [];
3623
- if (rootChildren.length === 0) return path;
3624
- let activeId = this.activeChildMap.get(_MessageTree.ROOT_KEY);
3625
- if (!activeId) {
3626
- activeId = rootChildren[rootChildren.length - 1];
3627
- }
3628
- let current = activeId;
3629
- while (current && !visited.has(current)) {
3630
- if (!this.nodeMap.has(current)) break;
3631
- visited.add(current);
3632
- path.push(current);
3633
- const activeChild = this.activeChildMap.get(current);
3634
- if (!activeChild || !this.nodeMap.has(activeChild)) break;
3635
- current = activeChild;
3636
- }
3637
- return path;
3578
+ setToolProfile(profile) {
3579
+ this.chat.setToolProfile(profile);
3638
3580
  }
3639
- };
3640
- /** Sentinel key used for root-level messages (parentId === null) */
3641
- _MessageTree.ROOT_KEY = "__root__";
3642
- var MessageTree = _MessageTree;
3643
-
3644
- // src/react/internal/ReactChatState.ts
3645
- var ReactChatState = class {
3646
- constructor(initialMessages) {
3647
- this._status = "ready";
3648
- this._error = void 0;
3649
- // Callbacks for React subscriptions (useSyncExternalStore)
3650
- this.subscribers = /* @__PURE__ */ new Set();
3651
- // ============================================
3652
- // Subscription (for useSyncExternalStore)
3653
- // ============================================
3654
- /**
3655
- * Subscribe to state changes.
3656
- * Returns an unsubscribe function.
3657
- *
3658
- * @example
3659
- * ```tsx
3660
- * const messages = useSyncExternalStore(
3661
- * state.subscribe,
3662
- * () => state.messages
3663
- * );
3664
- * ```
3665
- */
3666
- this.subscribe = (callback) => {
3667
- this.subscribers.add(callback);
3668
- return () => {
3669
- this.subscribers.delete(callback);
3670
- };
3671
- };
3672
- this.tree = new MessageTree(initialMessages);
3581
+ /**
3582
+ * Get the most recent prompt context usage snapshot.
3583
+ */
3584
+ getContextUsage() {
3585
+ return this.chat.getContextUsage();
3673
3586
  }
3674
- // ============================================
3675
- // Getters — visible path only
3676
- // ============================================
3677
3587
  /**
3678
- * Returns the VISIBLE PATH (active branch) — what the UI renders
3679
- * and what gets sent to the API.
3680
- *
3681
- * For all messages across all branches, use getAllMessages().
3588
+ * Set dynamic context (from useAIContext hook)
3682
3589
  */
3683
- get messages() {
3684
- return this.tree.getVisibleMessages();
3590
+ setContext(context) {
3591
+ this.chat.setContext(context);
3592
+ }
3593
+ /**
3594
+ * Set system prompt dynamically
3595
+ */
3596
+ setSystemPrompt(prompt) {
3597
+ this.chat.setSystemPrompt(prompt);
3598
+ }
3599
+ /**
3600
+ * Set headers configuration
3601
+ * Can be static headers or a getter function for dynamic resolution
3602
+ */
3603
+ setHeaders(headers) {
3604
+ this.chat.setHeaders(headers);
3605
+ }
3606
+ /**
3607
+ * Set URL configuration
3608
+ * Can be static URL or a getter function for dynamic resolution
3609
+ */
3610
+ setUrl(url) {
3611
+ this.chat.setUrl(url);
3612
+ }
3613
+ /**
3614
+ * Set body configuration
3615
+ * Additional properties merged into every request body
3616
+ */
3617
+ setBody(body) {
3618
+ this.chat.setBody(body);
3619
+ }
3620
+ setRequestMessageTransform(fn) {
3621
+ this.chat.setRequestMessageTransform(fn);
3622
+ }
3623
+ /**
3624
+ * Set inline skills (forwarded to underlying chat instance)
3625
+ */
3626
+ setInlineSkills(skills) {
3627
+ this.chat.setInlineSkills(skills);
3628
+ }
3629
+ // ============================================
3630
+ // Tool Registration
3631
+ // ============================================
3632
+ /**
3633
+ * Register a tool
3634
+ */
3635
+ registerTool(tool) {
3636
+ this.agentLoop.registerTool(tool);
3637
+ this.chat.setTools(this.agentLoop.tools);
3638
+ }
3639
+ /**
3640
+ * Unregister a tool
3641
+ */
3642
+ unregisterTool(name) {
3643
+ this.agentLoop.unregisterTool(name);
3644
+ this.chat.setTools(this.agentLoop.tools);
3645
+ }
3646
+ // ============================================
3647
+ // Tool Approval
3648
+ // ============================================
3649
+ /**
3650
+ * Approve a tool execution with optional extra data
3651
+ */
3652
+ approveToolExecution(id, extraData, permissionLevel) {
3653
+ this.agentLoop.approveToolExecution(id, extraData, permissionLevel);
3654
+ }
3655
+ /**
3656
+ * Reject a tool execution
3657
+ */
3658
+ rejectToolExecution(id, reason, permissionLevel) {
3659
+ this.agentLoop.rejectToolExecution(id, reason, permissionLevel);
3660
+ }
3661
+ /**
3662
+ * Clear tool executions
3663
+ */
3664
+ clearToolExecutions() {
3665
+ this.agentLoop.clearToolExecutions();
3666
+ }
3667
+ // ============================================
3668
+ // Event Subscriptions (for framework adapters)
3669
+ // ============================================
3670
+ /**
3671
+ * Subscribe to chat events
3672
+ */
3673
+ on(event, handler) {
3674
+ return this.chat.on(event, handler);
3675
+ }
3676
+ // ============================================
3677
+ // Cleanup
3678
+ // ============================================
3679
+ /**
3680
+ * Whether this instance has been disposed
3681
+ */
3682
+ get disposed() {
3683
+ return this.chat.disposed;
3684
+ }
3685
+ /**
3686
+ * Revive a disposed instance (for React StrictMode compatibility)
3687
+ * This allows reusing an instance after dispose() was called,
3688
+ * preserving registered tools and state
3689
+ */
3690
+ revive() {
3691
+ this.chat.revive();
3692
+ this.agentLoop.revive();
3693
+ }
3694
+ /**
3695
+ * Dispose and cleanup
3696
+ */
3697
+ dispose() {
3698
+ this.chat.dispose();
3699
+ this.agentLoop.dispose();
3700
+ }
3701
+ // ============================================
3702
+ // Private
3703
+ // ============================================
3704
+ debug(message, ...args) {
3705
+ chunkKGYDGK3U_cjs.createLogger("tools", () => this.config.debug ?? false)(
3706
+ message,
3707
+ args.length === 1 ? args[0] : args.length > 1 ? args : void 0
3708
+ );
3709
+ }
3710
+ };
3711
+
3712
+ // src/react/internal/ReactChatState.ts
3713
+ var ReactChatState = class {
3714
+ constructor(initialMessages) {
3715
+ this._status = "ready";
3716
+ this._error = void 0;
3717
+ // Callbacks for React subscriptions (useSyncExternalStore)
3718
+ this.subscribers = /* @__PURE__ */ new Set();
3719
+ // ============================================
3720
+ // Subscription (for useSyncExternalStore)
3721
+ // ============================================
3722
+ /**
3723
+ * Subscribe to state changes.
3724
+ * Returns an unsubscribe function.
3725
+ *
3726
+ * @example
3727
+ * ```tsx
3728
+ * const messages = useSyncExternalStore(
3729
+ * state.subscribe,
3730
+ * () => state.messages
3731
+ * );
3732
+ * ```
3733
+ */
3734
+ this.subscribe = (callback) => {
3735
+ this.subscribers.add(callback);
3736
+ return () => {
3737
+ this.subscribers.delete(callback);
3738
+ };
3739
+ };
3740
+ this.tree = new MessageTree(initialMessages);
3741
+ }
3742
+ // ============================================
3743
+ // Getters — visible path only
3744
+ // ============================================
3745
+ /**
3746
+ * Returns the VISIBLE PATH (active branch) — what the UI renders
3747
+ * and what gets sent to the API.
3748
+ *
3749
+ * For all messages across all branches, use getAllMessages().
3750
+ */
3751
+ get messages() {
3752
+ return this.tree.getVisibleMessages();
3685
3753
  }
3686
3754
  get status() {
3687
3755
  return this._status;
@@ -3807,149 +3875,21 @@ var ReactChatState = class {
3807
3875
  function createReactChatState(initialMessages) {
3808
3876
  return new ReactChatState(initialMessages);
3809
3877
  }
3810
-
3811
- // src/react/internal/ReactChatWithTools.ts
3812
- var ReactChatWithTools = class extends ChatWithTools {
3813
- constructor(config, callbacks = {}) {
3814
- const reactState = new ReactChatState(config.initialMessages);
3815
- super({ ...config, state: reactState }, callbacks);
3816
- /**
3817
- * Subscribe to state changes (for useSyncExternalStore)
3818
- */
3819
- this.subscribe = (callback) => {
3820
- return this.reactState.subscribe(callback);
3821
- };
3822
- this.reactState = reactState;
3823
- }
3824
- // ============================================
3825
- // Branching API — pass-throughs to ReactChatState
3826
- // ============================================
3827
- /**
3828
- * Navigate to a sibling branch.
3829
- */
3830
- switchBranch(messageId) {
3831
- this.reactState.switchBranch(messageId);
3832
- }
3833
- /**
3834
- * Get branch navigation info for a message.
3835
- */
3836
- getBranchInfo(messageId) {
3837
- return this.reactState.getBranchInfo(messageId);
3838
- }
3839
- /**
3840
- * Get all messages across all branches (for persistence).
3841
- */
3842
- getAllMessages() {
3843
- return this.reactState.getAllMessages();
3844
- }
3845
- /**
3846
- * Whether any message has siblings (branching has occurred).
3847
- */
3848
- get hasBranches() {
3849
- return this.reactState.hasBranches;
3850
- }
3851
- /**
3852
- * Dispose and cleanup
3853
- */
3854
- dispose() {
3855
- super.dispose();
3856
- this.reactState.dispose();
3857
- }
3858
- /**
3859
- * Revive a disposed instance (for React StrictMode compatibility)
3860
- */
3861
- revive() {
3862
- super.revive();
3863
- this.reactState.revive();
3864
- }
3865
- };
3866
-
3867
- // src/react/utils/context-tree.ts
3868
- function addNode(tree, node, parentId) {
3869
- const newNode = {
3870
- ...node,
3871
- children: node.children || []
3872
- };
3873
- if (!parentId) {
3874
- return [...tree, newNode];
3875
- }
3876
- return tree.map((n) => {
3877
- if (n.id === parentId) {
3878
- return { ...n, children: [...n.children, newNode] };
3879
- }
3880
- if (n.children.length > 0) {
3881
- return { ...n, children: addNode(n.children, node, parentId) };
3882
- }
3883
- return n;
3884
- });
3885
- }
3886
- function removeNode(tree, id) {
3887
- return tree.reduce((result, node) => {
3888
- if (node.id !== id) {
3889
- const newNode = { ...node, children: removeNode(node.children, id) };
3890
- result.push(newNode);
3891
- }
3892
- return result;
3893
- }, []);
3894
- }
3895
- function getIndentPrefix(index, level) {
3896
- if (level === 0) {
3897
- return `${index + 1}.`;
3898
- } else if (level === 1) {
3899
- return `${String.fromCharCode(65 + index)}.`;
3900
- } else if (level === 2) {
3901
- return `${String.fromCharCode(97 + index)}.`;
3902
- } else {
3903
- return "-";
3904
- }
3905
- }
3906
- function printNode(node, prefix = "", indentLevel = 0) {
3907
- const indent = " ".repeat(indentLevel);
3908
- const prefixLength = prefix.length + indent.length;
3909
- const subsequentIndent = " ".repeat(prefixLength);
3910
- const lines = node.value.split("\n");
3911
- const firstLine = `${indent}${prefix}${lines[0]}`;
3912
- const subsequentLines = lines.slice(1).map((line) => `${subsequentIndent}${line}`).join("\n");
3913
- let output = `${firstLine}
3914
- `;
3915
- if (subsequentLines) {
3916
- output += `${subsequentLines}
3917
- `;
3918
- }
3919
- node.children.forEach((child, index) => {
3920
- const childPrefix = `${" ".repeat(prefix.length)}${getIndentPrefix(index, indentLevel + 1)} `;
3921
- output += printNode(child, childPrefix, indentLevel + 1);
3922
- });
3923
- return output;
3924
- }
3925
- function printTree(tree) {
3926
- if (tree.length === 0) {
3927
- return "";
3928
- }
3929
- let output = "";
3930
- tree.forEach((node, index) => {
3931
- if (index > 0) {
3932
- output += "\n";
3933
- }
3934
- output += printNode(node, `${getIndentPrefix(index, 0)} `);
3935
- });
3936
- return output.trim();
3937
- }
3938
- function useMCPClient(config) {
3939
- const {
3940
- autoConnect = true,
3941
- onConnectionStateChange,
3942
- onToolsChange,
3943
- onElicitationRequest,
3944
- onError,
3945
- onNotification,
3946
- ...clientConfig
3947
- } = config;
3948
- const clientRef = React2.useRef(null);
3949
- const mountedRef = React2.useRef(true);
3950
- const [state, setState] = React2.useState({
3951
- connectionState: "disconnected",
3952
- tools: []
3878
+ function useMCPClient(config) {
3879
+ const {
3880
+ autoConnect = true,
3881
+ onConnectionStateChange,
3882
+ onToolsChange,
3883
+ onElicitationRequest,
3884
+ onError,
3885
+ onNotification,
3886
+ ...clientConfig
3887
+ } = config;
3888
+ const clientRef = React2.useRef(null);
3889
+ const mountedRef = React2.useRef(true);
3890
+ const [state, setState] = React2.useState({
3891
+ connectionState: "disconnected",
3892
+ tools: []
3953
3893
  });
3954
3894
  const getClient = React2.useCallback(() => {
3955
3895
  if (!clientRef.current) {
@@ -4082,78 +4022,132 @@ function useMCPClient(config) {
4082
4022
  };
4083
4023
  }
4084
4024
 
4085
- // src/react/hooks/useMCPTools.ts
4086
- function useMCPTools(config) {
4087
- const {
4088
- prefixToolNames = true,
4089
- autoRegister = true,
4090
- hidden = false,
4091
- source = "mcp",
4092
- ...clientConfig
4093
- } = config;
4094
- const { registerTool, unregisterTool } = useCopilot();
4095
- const registeredToolsRef = React2.useRef([]);
4096
- const mcpClient = useMCPClient(clientConfig);
4097
- const toolAdapter = React2.useMemo(
4098
- () => new chunkJGPDQDY4_cjs.MCPToolAdapter(clientConfig.name),
4099
- [clientConfig.name]
4100
- );
4101
- const toolDefinitions = React2.useMemo(() => {
4102
- if (!mcpClient.isConnected || mcpClient.state.tools.length === 0) {
4103
- return [];
4025
+ // src/react/internal/ReactChatWithTools.ts
4026
+ var ReactChatWithTools = class extends ChatWithTools {
4027
+ constructor(config, callbacks = {}) {
4028
+ const reactState = new ReactChatState(config.initialMessages);
4029
+ super({ ...config, state: reactState }, callbacks);
4030
+ /**
4031
+ * Subscribe to state changes (for useSyncExternalStore)
4032
+ */
4033
+ this.subscribe = (callback) => {
4034
+ return this.reactState.subscribe(callback);
4035
+ };
4036
+ this.reactState = reactState;
4037
+ }
4038
+ // ============================================
4039
+ // Branching API — pass-throughs to ReactChatState
4040
+ // ============================================
4041
+ /**
4042
+ * Navigate to a sibling branch.
4043
+ */
4044
+ switchBranch(messageId) {
4045
+ this.reactState.switchBranch(messageId);
4046
+ }
4047
+ /**
4048
+ * Get branch navigation info for a message.
4049
+ */
4050
+ getBranchInfo(messageId) {
4051
+ return this.reactState.getBranchInfo(messageId);
4052
+ }
4053
+ /**
4054
+ * Get all messages across all branches (for persistence).
4055
+ */
4056
+ getAllMessages() {
4057
+ return this.reactState.getAllMessages();
4058
+ }
4059
+ /**
4060
+ * Whether any message has siblings (branching has occurred).
4061
+ */
4062
+ get hasBranches() {
4063
+ return this.reactState.hasBranches;
4064
+ }
4065
+ /**
4066
+ * Dispose and cleanup
4067
+ */
4068
+ dispose() {
4069
+ super.dispose();
4070
+ this.reactState.dispose();
4071
+ }
4072
+ /**
4073
+ * Revive a disposed instance (for React StrictMode compatibility)
4074
+ */
4075
+ revive() {
4076
+ super.revive();
4077
+ this.reactState.revive();
4078
+ }
4079
+ };
4080
+
4081
+ // src/react/utils/context-tree.ts
4082
+ function addNode(tree, node, parentId) {
4083
+ const newNode = {
4084
+ ...node,
4085
+ children: node.children || []
4086
+ };
4087
+ if (!parentId) {
4088
+ return [...tree, newNode];
4089
+ }
4090
+ return tree.map((n) => {
4091
+ if (n.id === parentId) {
4092
+ return { ...n, children: [...n.children, newNode] };
4104
4093
  }
4105
- return mcpClient.state.tools.map(
4106
- (tool2) => toolAdapter.toToolDefinition(tool2, {
4107
- prefix: prefixToolNames,
4108
- asServerTool: true,
4109
- // MCP tools execute remotely
4110
- callTool: mcpClient.callTool,
4111
- hidden,
4112
- // Hide from chat UI
4113
- source
4114
- // Tool source for UI differentiation
4115
- })
4116
- );
4117
- }, [
4118
- mcpClient.isConnected,
4119
- mcpClient.state.tools,
4120
- mcpClient.callTool,
4121
- toolAdapter,
4122
- prefixToolNames,
4123
- hidden,
4124
- source
4125
- ]);
4126
- React2.useEffect(() => {
4127
- if (!autoRegister) {
4128
- return;
4094
+ if (n.children.length > 0) {
4095
+ return { ...n, children: addNode(n.children, node, parentId) };
4129
4096
  }
4130
- for (const toolName of registeredToolsRef.current) {
4131
- unregisterTool(toolName);
4097
+ return n;
4098
+ });
4099
+ }
4100
+ function removeNode(tree, id) {
4101
+ return tree.reduce((result, node) => {
4102
+ if (node.id !== id) {
4103
+ const newNode = { ...node, children: removeNode(node.children, id) };
4104
+ result.push(newNode);
4132
4105
  }
4133
- registeredToolsRef.current = [];
4134
- if (mcpClient.isConnected && toolDefinitions.length > 0) {
4135
- for (const tool2 of toolDefinitions) {
4136
- registerTool(tool2);
4137
- registeredToolsRef.current.push(tool2.name);
4138
- }
4106
+ return result;
4107
+ }, []);
4108
+ }
4109
+ function getIndentPrefix(index, level) {
4110
+ if (level === 0) {
4111
+ return `${index + 1}.`;
4112
+ } else if (level === 1) {
4113
+ return `${String.fromCharCode(65 + index)}.`;
4114
+ } else if (level === 2) {
4115
+ return `${String.fromCharCode(97 + index)}.`;
4116
+ } else {
4117
+ return "-";
4118
+ }
4119
+ }
4120
+ function printNode(node, prefix = "", indentLevel = 0) {
4121
+ const indent = " ".repeat(indentLevel);
4122
+ const prefixLength = prefix.length + indent.length;
4123
+ const subsequentIndent = " ".repeat(prefixLength);
4124
+ const lines = node.value.split("\n");
4125
+ const firstLine = `${indent}${prefix}${lines[0]}`;
4126
+ const subsequentLines = lines.slice(1).map((line) => `${subsequentIndent}${line}`).join("\n");
4127
+ let output = `${firstLine}
4128
+ `;
4129
+ if (subsequentLines) {
4130
+ output += `${subsequentLines}
4131
+ `;
4132
+ }
4133
+ node.children.forEach((child, index) => {
4134
+ const childPrefix = `${" ".repeat(prefix.length)}${getIndentPrefix(index, indentLevel + 1)} `;
4135
+ output += printNode(child, childPrefix, indentLevel + 1);
4136
+ });
4137
+ return output;
4138
+ }
4139
+ function printTree(tree) {
4140
+ if (tree.length === 0) {
4141
+ return "";
4142
+ }
4143
+ let output = "";
4144
+ tree.forEach((node, index) => {
4145
+ if (index > 0) {
4146
+ output += "\n";
4139
4147
  }
4140
- return () => {
4141
- for (const toolName of registeredToolsRef.current) {
4142
- unregisterTool(toolName);
4143
- }
4144
- registeredToolsRef.current = [];
4145
- };
4146
- }, [
4147
- autoRegister,
4148
- mcpClient.isConnected,
4149
- toolDefinitions,
4150
- registerTool,
4151
- unregisterTool
4152
- ]);
4153
- return {
4154
- ...mcpClient,
4155
- toolDefinitions
4156
- };
4148
+ output += printNode(node, `${getIndentPrefix(index, 0)} `);
4149
+ });
4150
+ return output.trim();
4157
4151
  }
4158
4152
  var defaultTokenUsage = {
4159
4153
  current: 0,
@@ -4857,12 +4851,12 @@ function useTool(config, dependencies = []) {
4857
4851
  configRef.current = config;
4858
4852
  const inputSchema = React2.useMemo(() => {
4859
4853
  if (isZodSchema(config.inputSchema)) {
4860
- return chunkB4YDIMP3_cjs.zodToJsonSchema(config.inputSchema);
4854
+ return chunkKGYDGK3U_cjs.zodToJsonSchema(config.inputSchema);
4861
4855
  }
4862
4856
  return config.inputSchema;
4863
4857
  }, [config.inputSchema]);
4864
4858
  React2.useEffect(() => {
4865
- const tool2 = {
4859
+ const tool = {
4866
4860
  name: config.name,
4867
4861
  description: config.description,
4868
4862
  location: "client",
@@ -4888,7 +4882,7 @@ function useTool(config, dependencies = []) {
4888
4882
  aiResponseMode: config.aiResponseMode,
4889
4883
  aiContext: config.aiContext
4890
4884
  };
4891
- registerTool(tool2);
4885
+ registerTool(tool);
4892
4886
  return () => {
4893
4887
  unregisterTool(config.name);
4894
4888
  };
@@ -5182,6 +5176,35 @@ ${cs.rollingSummary}`,
5182
5176
  }, []);
5183
5177
  return null;
5184
5178
  }
5179
+ var _MessageMetaStore = class _MessageMetaStore {
5180
+ constructor() {
5181
+ this.store = /* @__PURE__ */ new Map();
5182
+ this.listeners = /* @__PURE__ */ new Set();
5183
+ this.subscribe = (cb) => {
5184
+ this.listeners.add(cb);
5185
+ return () => this.listeners.delete(cb);
5186
+ };
5187
+ this.getSnapshot = () => this.store;
5188
+ this.getMeta = (messageId) => this.store.get(messageId) ?? _MessageMetaStore.EMPTY;
5189
+ this.setMeta = (messageId, meta) => {
5190
+ this.store.set(messageId, meta);
5191
+ this.listeners.forEach((cb) => cb());
5192
+ };
5193
+ this.updateMeta = (messageId, updater) => {
5194
+ const prev = this.store.get(messageId) ?? {};
5195
+ this.store.set(messageId, updater(prev));
5196
+ this.listeners.forEach((cb) => cb());
5197
+ };
5198
+ this.clear = () => {
5199
+ this.store.clear();
5200
+ this.listeners.forEach((cb) => cb());
5201
+ };
5202
+ }
5203
+ };
5204
+ // Stable empty object — returned for unknown messageIds so useSyncExternalStore
5205
+ // sees the same reference and doesn't trigger infinite re-renders.
5206
+ _MessageMetaStore.EMPTY = {};
5207
+ var MessageMetaStore = _MessageMetaStore;
5185
5208
  var CopilotContext = React2.createContext(null);
5186
5209
  function useCopilot() {
5187
5210
  const context = React2.useContext(CopilotContext);
@@ -5210,9 +5233,18 @@ function CopilotProvider({
5210
5233
  messageHistory,
5211
5234
  skills
5212
5235
  }) {
5236
+ const streamListenersRef = React2.useRef(/* @__PURE__ */ new Set());
5237
+ const subscribeToStreamEvents = React2.useCallback(
5238
+ (handler) => {
5239
+ streamListenersRef.current.add(handler);
5240
+ return () => streamListenersRef.current.delete(handler);
5241
+ },
5242
+ []
5243
+ );
5244
+ const messageMetaStoreRef = React2.useRef(new MessageMetaStore());
5213
5245
  const debugLog = React2.useCallback(
5214
5246
  (action, data) => {
5215
- chunkB4YDIMP3_cjs.createLogger("provider", () => debug ?? false)(action, data);
5247
+ chunkKGYDGK3U_cjs.createLogger("provider", () => debug ?? false)(action, data);
5216
5248
  },
5217
5249
  [debug]
5218
5250
  );
@@ -5224,6 +5256,7 @@ function CopilotProvider({
5224
5256
  }
5225
5257
  }, [toolsConfig]);
5226
5258
  const [toolExecutions, setToolExecutions] = React2.useState([]);
5259
+ const [agentIteration, setAgentIteration] = React2.useState(0);
5227
5260
  const chatRef = React2.useRef(null);
5228
5261
  if (chatRef.current !== null && chatRef.current.disposed) {
5229
5262
  chatRef.current.revive();
@@ -5261,6 +5294,7 @@ function CopilotProvider({
5261
5294
  onToolExecutionsChange: (executions) => {
5262
5295
  debugLog("Tool executions changed:", executions.length);
5263
5296
  setToolExecutions(executions);
5297
+ setAgentIteration(chatRef.current?.iteration ?? 0);
5264
5298
  },
5265
5299
  onApprovalRequired: (execution) => {
5266
5300
  debugLog("Tool approval required:", execution.name);
@@ -5270,6 +5304,13 @@ function CopilotProvider({
5270
5304
  },
5271
5305
  onError: (error2) => {
5272
5306
  if (error2) onError?.(error2);
5307
+ },
5308
+ onStreamChunk: (chunk) => {
5309
+ if (streamListenersRef.current.size > 0) {
5310
+ for (const handler of streamListenersRef.current) {
5311
+ handler(chunk);
5312
+ }
5313
+ }
5273
5314
  }
5274
5315
  }
5275
5316
  );
@@ -5323,8 +5364,8 @@ function CopilotProvider({
5323
5364
  );
5324
5365
  const error = errorFromChat ?? null;
5325
5366
  const isLoading = status === "streaming" || status === "submitted";
5326
- const registerTool = React2.useCallback((tool2) => {
5327
- chatRef.current?.registerTool(tool2);
5367
+ const registerTool = React2.useCallback((tool) => {
5368
+ chatRef.current?.registerTool(tool);
5328
5369
  }, []);
5329
5370
  const unregisterTool = React2.useCallback((name) => {
5330
5371
  chatRef.current?.unregisterTool(name);
@@ -5381,2005 +5422,41 @@ function CopilotProvider({
5381
5422
  chatRef.current?.setContext(contextString);
5382
5423
  setContextChars(contextString.length);
5383
5424
  debugLog("Context added:", id);
5384
- return id;
5385
- },
5386
- [debugLog]
5387
- );
5388
- const removeContext = React2.useCallback(
5389
- (id) => {
5390
- contextTreeRef.current = removeNode(contextTreeRef.current, id);
5391
- const contextString = printTree(contextTreeRef.current);
5392
- chatRef.current?.setContext(contextString);
5393
- setContextChars(contextString.length);
5394
- debugLog("Context removed:", id);
5395
- },
5396
- [debugLog]
5397
- );
5398
- const setSystemPrompt = React2.useCallback(
5399
- (prompt) => {
5400
- chatRef.current?.setSystemPrompt(prompt);
5401
- debugLog("System prompt updated via function");
5402
- },
5403
- [debugLog]
5404
- );
5405
- const setInlineSkills = React2.useCallback(
5406
- (skills2) => {
5407
- chatRef.current?.setInlineSkills(skills2);
5408
- debugLog("Inline skills updated", { count: skills2.length });
5409
- },
5410
- [debugLog]
5411
- );
5412
- const sendMessage = React2.useCallback(
5413
- async (content, attachments) => {
5414
- debugLog("Sending message:", content);
5415
- await chatRef.current?.sendMessage(content, attachments);
5416
- },
5417
- [debugLog]
5418
- );
5419
- const stop = React2.useCallback(() => {
5420
- chatRef.current?.stop();
5421
- }, []);
5422
- const clearMessages = React2.useCallback(() => {
5423
- chatRef.current?.clearMessages();
5424
- }, []);
5425
- const setMessages = React2.useCallback((messages2) => {
5426
- chatRef.current?.setMessages(messages2);
5427
- }, []);
5428
- const regenerate = React2.useCallback(async (messageId) => {
5429
- await chatRef.current?.regenerate(messageId);
5430
- }, []);
5431
- const switchBranch = React2.useCallback((messageId) => {
5432
- chatRef.current?.switchBranch(messageId);
5433
- }, []);
5434
- const getBranchInfo = React2.useCallback(
5435
- (messageId) => chatRef.current?.getBranchInfo(messageId) ?? null,
5436
- []
5437
- );
5438
- const editMessage = React2.useCallback(
5439
- async (messageId, newContent) => {
5440
- await chatRef.current?.sendMessage(newContent, void 0, {
5441
- editMessageId: messageId
5442
- });
5443
- },
5444
- []
5445
- );
5446
- const getHasBranchesSnapshot = React2.useCallback(
5447
- () => chatRef.current.hasBranches,
5448
- []
5449
- );
5450
- const hasBranches = React2.useSyncExternalStore(
5451
- chatRef.current.subscribe,
5452
- getHasBranchesSnapshot,
5453
- () => false
5454
- );
5455
- const getAllMessages = React2.useCallback(
5456
- () => chatRef.current?.getAllMessages?.() ?? [],
5457
- []
5458
- );
5459
- React2.useEffect(() => {
5460
- if (onMessagesChange && messages.length > 0) {
5461
- const allUIMessages = chatRef.current?.getAllMessages?.() ?? messages;
5462
- const coreMessages = allUIMessages.map((m) => ({
5463
- id: m.id,
5464
- role: m.role,
5465
- content: m.content,
5466
- created_at: m.createdAt,
5467
- tool_calls: m.toolCalls,
5468
- tool_call_id: m.toolCallId,
5469
- parent_id: m.parentId,
5470
- children_ids: m.childrenIds,
5471
- metadata: {
5472
- attachments: m.attachments,
5473
- thinking: m.thinking
5474
- }
5475
- }));
5476
- onMessagesChange(coreMessages);
5477
- }
5478
- }, [messages, onMessagesChange]);
5479
- React2.useEffect(() => {
5480
- if (error && onError) {
5481
- onError(error);
5482
- }
5483
- }, [error, onError]);
5484
- React2.useEffect(() => {
5485
- return () => {
5486
- chatRef.current?.dispose();
5487
- };
5488
- }, []);
5489
- const contextValue = React2.useMemo(
5490
- () => ({
5491
- // Chat state
5492
- messages,
5493
- status,
5494
- error,
5495
- isLoading,
5496
- // Chat actions
5497
- sendMessage,
5498
- stop,
5499
- clearMessages,
5500
- setMessages,
5501
- regenerate,
5502
- // Branching
5503
- switchBranch,
5504
- getBranchInfo,
5505
- editMessage,
5506
- hasBranches,
5507
- getAllMessages,
5508
- // Tool execution
5509
- registerTool,
5510
- unregisterTool,
5511
- registeredTools,
5512
- toolExecutions,
5513
- pendingApprovals,
5514
- approveToolExecution,
5515
- rejectToolExecution,
5516
- // Actions
5517
- registerAction,
5518
- unregisterAction,
5519
- registeredActions,
5520
- // AI Context
5521
- addContext,
5522
- removeContext,
5523
- contextChars,
5524
- contextUsage,
5525
- // System Prompt
5526
- setSystemPrompt,
5527
- // Skills
5528
- setInlineSkills,
5529
- // Config
5530
- threadId,
5531
- runtimeUrl,
5532
- toolsConfig
5533
- }),
5534
- [
5535
- messages,
5536
- status,
5537
- error,
5538
- isLoading,
5539
- sendMessage,
5540
- stop,
5541
- clearMessages,
5542
- setMessages,
5543
- regenerate,
5544
- switchBranch,
5545
- getBranchInfo,
5546
- editMessage,
5547
- hasBranches,
5548
- getAllMessages,
5549
- registerTool,
5550
- unregisterTool,
5551
- registeredTools,
5552
- toolExecutions,
5553
- pendingApprovals,
5554
- approveToolExecution,
5555
- rejectToolExecution,
5556
- registerAction,
5557
- unregisterAction,
5558
- registeredActions,
5559
- addContext,
5560
- removeContext,
5561
- contextChars,
5562
- contextUsage,
5563
- setSystemPrompt,
5564
- setInlineSkills,
5565
- threadId,
5566
- runtimeUrl,
5567
- toolsConfig
5568
- ]
5569
- );
5570
- const messageHistoryContextValue = React2__default.default.useMemo(
5571
- () => ({
5572
- config: { ...defaultMessageHistoryConfig, ...messageHistory },
5573
- tokenUsage: {
5574
- current: 0,
5575
- max: messageHistory?.maxContextTokens ?? 128e3,
5576
- percentage: 0,
5577
- isApproaching: false
5578
- },
5579
- compactionState: {
5580
- rollingSummary: null,
5581
- lastCompactionAt: null,
5582
- compactionCount: 0,
5583
- totalTokensSaved: 0,
5584
- workingMemory: [],
5585
- displayMessageCount: 0,
5586
- llmMessageCount: 0
5587
- }
5588
- }),
5589
- [messageHistory]
5590
- );
5591
- return /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryContext.Provider, { value: messageHistoryContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(CopilotContext.Provider, { value: contextValue, children: [
5592
- mcpServers?.map((config) => /* @__PURE__ */ jsxRuntime.jsx(MCPConnection, { config }, config.name)),
5593
- messageHistory?.strategy && messageHistory.strategy !== "none" && /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryBridge, { chatRef }),
5594
- skills ? /* @__PURE__ */ jsxRuntime.jsx(SkillProvider, { skills, children }) : children
5595
- ] }) });
5596
- }
5597
- function useAIActions(actions) {
5598
- const { registerAction, unregisterAction } = useCopilot();
5599
- React2.useEffect(() => {
5600
- for (const action of actions) {
5601
- registerAction(action);
5602
- }
5603
- return () => {
5604
- for (const action of actions) {
5605
- unregisterAction(action.name);
5606
- }
5607
- };
5608
- }, [actions, registerAction, unregisterAction]);
5609
- }
5610
- function useAIAction(action) {
5611
- useAIActions([action]);
5612
- }
5613
- function useAITools(options = {}) {
5614
- const {
5615
- screenshot = false,
5616
- console: consoleCapture = false,
5617
- network = false,
5618
- requireConsent = true,
5619
- screenshotOptions,
5620
- consoleOptions,
5621
- networkOptions,
5622
- onConsentRequest,
5623
- autoStart = true
5624
- } = options;
5625
- const [isEnabled] = React2.useState(screenshot || consoleCapture || network);
5626
- const [activeCaptures, setActiveCaptures] = React2.useState({
5627
- console: false,
5628
- network: false
5629
- });
5630
- const [pendingConsent, setPendingConsent] = React2.useState(null);
5631
- const consentResolverRef = React2.useRef(null);
5632
- const rememberedConsentRef = React2.useRef(/* @__PURE__ */ new Set());
5633
- React2.useEffect(() => {
5634
- if (!autoStart || !isEnabled) return;
5635
- if (consoleCapture && !chunkB4YDIMP3_cjs.isConsoleCaptureActive()) {
5636
- chunkB4YDIMP3_cjs.startConsoleCapture(consoleOptions);
5637
- setActiveCaptures((prev) => ({ ...prev, console: true }));
5638
- }
5639
- if (network && !chunkB4YDIMP3_cjs.isNetworkCaptureActive()) {
5640
- chunkB4YDIMP3_cjs.startNetworkCapture(networkOptions);
5641
- setActiveCaptures((prev) => ({ ...prev, network: true }));
5642
- }
5643
- return () => {
5644
- chunkB4YDIMP3_cjs.stopConsoleCapture();
5645
- chunkB4YDIMP3_cjs.stopNetworkCapture();
5646
- };
5647
- }, [
5648
- autoStart,
5649
- isEnabled,
5650
- consoleCapture,
5651
- network,
5652
- consoleOptions,
5653
- networkOptions
5654
- ]);
5655
- const captureScreenshotFn = React2.useCallback(
5656
- async (opts) => {
5657
- if (!screenshot) {
5658
- throw new Error("Screenshot capture is not enabled");
5659
- }
5660
- if (!chunkB4YDIMP3_cjs.isScreenshotSupported()) {
5661
- throw new Error(
5662
- "Screenshot capture is not supported in this environment"
5663
- );
5664
- }
5665
- return chunkB4YDIMP3_cjs.captureScreenshot({ ...screenshotOptions, ...opts });
5666
- },
5667
- [screenshot, screenshotOptions]
5668
- );
5669
- const getConsoleLogsFn = React2.useCallback(
5670
- (opts) => {
5671
- if (!consoleCapture) {
5672
- return { logs: [], totalCaptured: 0 };
5673
- }
5674
- return chunkB4YDIMP3_cjs.getConsoleLogs({ ...consoleOptions, ...opts });
5675
- },
5676
- [consoleCapture, consoleOptions]
5677
- );
5678
- const getNetworkRequestsFn = React2.useCallback(
5679
- (opts) => {
5680
- if (!network) {
5681
- return { requests: [], totalCaptured: 0 };
5682
- }
5683
- return chunkB4YDIMP3_cjs.getNetworkRequests({ ...networkOptions, ...opts });
5684
- },
5685
- [network, networkOptions]
5686
- );
5687
- const requestConsent = React2.useCallback(
5688
- async (tools, reason = "") => {
5689
- const enabledTools = tools.filter((tool2) => {
5690
- if (tool2 === "screenshot") return screenshot;
5691
- if (tool2 === "console") return consoleCapture;
5692
- if (tool2 === "network") return network;
5693
- return false;
5694
- });
5695
- if (enabledTools.length === 0) {
5696
- return { approved: [], denied: [] };
5697
- }
5698
- if (!requireConsent) {
5699
- return { approved: enabledTools, denied: [] };
5700
- }
5701
- const needsConsent = enabledTools.filter(
5702
- (tool2) => !rememberedConsentRef.current.has(tool2)
5703
- );
5704
- if (needsConsent.length === 0) {
5705
- return { approved: enabledTools, denied: [] };
5706
- }
5707
- const request = {
5708
- tools: needsConsent,
5709
- reason,
5710
- keywords: []
5711
- };
5712
- if (onConsentRequest) {
5713
- const response = await onConsentRequest(request);
5714
- if (response.remember) {
5715
- response.approved.forEach(
5716
- (tool2) => rememberedConsentRef.current.add(tool2)
5717
- );
5718
- }
5719
- return response;
5720
- }
5721
- return new Promise((resolve) => {
5722
- setPendingConsent(request);
5723
- consentResolverRef.current = (response) => {
5724
- if (response.remember) {
5725
- response.approved.forEach(
5726
- (tool2) => rememberedConsentRef.current.add(tool2)
5727
- );
5728
- }
5729
- resolve(response);
5730
- };
5731
- });
5732
- },
5733
- [screenshot, consoleCapture, network, requireConsent, onConsentRequest]
5734
- );
5735
- const respondToConsent = React2.useCallback((response) => {
5736
- if (consentResolverRef.current) {
5737
- consentResolverRef.current(response);
5738
- consentResolverRef.current = null;
5739
- }
5740
- setPendingConsent(null);
5741
- }, []);
5742
- const captureContext = React2.useCallback(
5743
- async (tools) => {
5744
- const toolsToCapture = tools || ["screenshot", "console", "network"];
5745
- const context = {
5746
- timestamp: Date.now()
5747
- };
5748
- const captures = [];
5749
- if (toolsToCapture.includes("screenshot") && screenshot) {
5750
- captures.push(
5751
- captureScreenshotFn().then((result) => {
5752
- context.screenshot = result;
5753
- }).catch(() => {
5754
- })
5755
- );
5756
- }
5757
- if (toolsToCapture.includes("console") && consoleCapture) {
5758
- context.consoleLogs = getConsoleLogsFn();
5759
- }
5760
- if (toolsToCapture.includes("network") && network) {
5761
- context.networkRequests = getNetworkRequestsFn();
5762
- }
5763
- await Promise.all(captures);
5764
- return context;
5765
- },
5766
- [
5767
- screenshot,
5768
- consoleCapture,
5769
- network,
5770
- captureScreenshotFn,
5771
- getConsoleLogsFn,
5772
- getNetworkRequestsFn
5773
- ]
5774
- );
5775
- const startCapturing = React2.useCallback(() => {
5776
- if (consoleCapture && !chunkB4YDIMP3_cjs.isConsoleCaptureActive()) {
5777
- chunkB4YDIMP3_cjs.startConsoleCapture(consoleOptions);
5778
- setActiveCaptures((prev) => ({ ...prev, console: true }));
5779
- }
5780
- if (network && !chunkB4YDIMP3_cjs.isNetworkCaptureActive()) {
5781
- chunkB4YDIMP3_cjs.startNetworkCapture(networkOptions);
5782
- setActiveCaptures((prev) => ({ ...prev, network: true }));
5783
- }
5784
- }, [consoleCapture, network, consoleOptions, networkOptions]);
5785
- const stopCapturing = React2.useCallback(() => {
5786
- chunkB4YDIMP3_cjs.stopConsoleCapture();
5787
- chunkB4YDIMP3_cjs.stopNetworkCapture();
5788
- setActiveCaptures({ console: false, network: false });
5789
- }, []);
5790
- const clearCaptured = React2.useCallback(() => {
5791
- chunkB4YDIMP3_cjs.clearConsoleLogs();
5792
- chunkB4YDIMP3_cjs.clearNetworkRequests();
5793
- }, []);
5794
- const formatForAI = React2.useCallback((context) => {
5795
- const parts = [];
5796
- if (context.screenshot) {
5797
- parts.push(
5798
- `Screenshot captured (${context.screenshot.width}x${context.screenshot.height}, ${context.screenshot.format})`
5799
- );
5800
- }
5801
- if (context.consoleLogs && context.consoleLogs.logs.length > 0) {
5802
- parts.push(chunkB4YDIMP3_cjs.formatLogsForAI(context.consoleLogs.logs));
5803
- }
5804
- if (context.networkRequests && context.networkRequests.requests.length > 0) {
5805
- parts.push(chunkB4YDIMP3_cjs.formatRequestsForAI(context.networkRequests.requests));
5806
- }
5807
- return parts.length > 0 ? parts.join("\n\n---\n\n") : "No context captured.";
5808
- }, []);
5809
- const detectIntentFn = React2.useCallback(
5810
- (message) => {
5811
- const result = chunkB4YDIMP3_cjs.detectIntent(message);
5812
- result.suggestedTools = result.suggestedTools.filter((tool2) => {
5813
- if (tool2 === "screenshot") return screenshot;
5814
- if (tool2 === "console") return consoleCapture;
5815
- if (tool2 === "network") return network;
5816
- return false;
5817
- });
5818
- return result;
5819
- },
5820
- [screenshot, consoleCapture, network]
5821
- );
5822
- return React2.useMemo(
5823
- () => ({
5824
- isEnabled,
5825
- activeCaptures,
5826
- captureScreenshot: captureScreenshotFn,
5827
- getConsoleLogs: getConsoleLogsFn,
5828
- getNetworkRequests: getNetworkRequestsFn,
5829
- captureContext,
5830
- detectIntent: detectIntentFn,
5831
- requestConsent,
5832
- startCapturing,
5833
- stopCapturing,
5834
- clearCaptured,
5835
- formatForAI,
5836
- pendingConsent,
5837
- respondToConsent
5838
- }),
5839
- [
5840
- isEnabled,
5841
- activeCaptures,
5842
- captureScreenshotFn,
5843
- getConsoleLogsFn,
5844
- getNetworkRequestsFn,
5845
- captureContext,
5846
- detectIntentFn,
5847
- requestConsent,
5848
- startCapturing,
5849
- stopCapturing,
5850
- clearCaptured,
5851
- formatForAI,
5852
- pendingConsent,
5853
- respondToConsent
5854
- ]
5855
- );
5856
- }
5857
- function convertZodSchema(schema, _toolName) {
5858
- try {
5859
- const zodWithJsonSchema = z__namespace;
5860
- if (typeof zodWithJsonSchema.toJSONSchema === "function") {
5861
- const jsonSchema = zodWithJsonSchema.toJSONSchema(
5862
- schema
5863
- );
5864
- if (jsonSchema.type === "object") {
5865
- return {
5866
- type: "object",
5867
- properties: jsonSchema.properties || {},
5868
- required: jsonSchema.required
5869
- };
5870
- }
5871
- }
5872
- } catch {
5873
- }
5874
- return chunkB4YDIMP3_cjs.zodObjectToInputSchema(schema);
5875
- }
5876
- function useToolWithSchema(config, dependencies = []) {
5877
- const { registerTool, unregisterTool } = useCopilot();
5878
- const configRef = React2.useRef(config);
5879
- configRef.current = config;
5880
- const inputSchema = React2.useMemo(() => {
5881
- try {
5882
- return convertZodSchema(config.schema, config.name);
5883
- } catch (error) {
5884
- console.warn(
5885
- `[useToolWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
5886
- error
5887
- );
5888
- return {
5889
- type: "object",
5890
- properties: {}
5891
- };
5892
- }
5893
- }, [config.schema, config.name]);
5894
- React2.useEffect(() => {
5895
- const tool2 = {
5896
- name: config.name,
5897
- description: config.description,
5898
- location: "client",
5899
- inputSchema,
5900
- handler: async (params, context) => {
5901
- return configRef.current.handler(params, context);
5902
- },
5903
- render: config.render,
5904
- available: config.available ?? true
5905
- };
5906
- registerTool(tool2);
5907
- return () => {
5908
- unregisterTool(config.name);
5909
- };
5910
- }, [config.name, inputSchema, ...dependencies]);
5911
- }
5912
- function useToolsWithSchema(tools, dependencies = []) {
5913
- const { registerTool, unregisterTool } = useCopilot();
5914
- const toolsRef = React2.useRef(tools);
5915
- toolsRef.current = tools;
5916
- React2.useEffect(() => {
5917
- const toolNames = [];
5918
- for (const config of tools) {
5919
- let inputSchema;
5920
- try {
5921
- inputSchema = convertZodSchema(config.schema, config.name);
5922
- } catch (error) {
5923
- console.warn(
5924
- `[useToolsWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
5925
- error
5926
- );
5927
- inputSchema = { type: "object", properties: {} };
5928
- }
5929
- const tool2 = {
5930
- name: config.name,
5931
- description: config.description,
5932
- location: "client",
5933
- inputSchema,
5934
- handler: async (params, context) => {
5935
- const currentConfig = toolsRef.current.find(
5936
- (t) => t.name === config.name
5937
- );
5938
- if (currentConfig) {
5939
- return currentConfig.handler(params, context);
5940
- }
5941
- return { success: false, error: "Tool handler not found" };
5942
- },
5943
- available: config.available ?? true
5944
- };
5945
- registerTool(tool2);
5946
- toolNames.push(config.name);
5947
- }
5948
- return () => {
5949
- for (const name of toolNames) {
5950
- unregisterTool(name);
5951
- }
5952
- };
5953
- }, [tools.map((t) => t.name).join(","), ...dependencies]);
5954
- }
5955
- var CopilotContext2 = React2.createContext(null);
5956
- function useCopilotContext() {
5957
- const context = React2.useContext(CopilotContext2);
5958
- if (!context) {
5959
- throw new Error("useCopilotContext must be used within a CopilotProvider");
5960
- }
5961
- return context;
5962
- }
5963
-
5964
- // src/react/hooks/useToolExecutor.ts
5965
- function useToolExecutor() {
5966
- const {
5967
- registeredTools,
5968
- config,
5969
- chat,
5970
- addToolExecution,
5971
- updateToolExecution
5972
- } = useCopilotContext();
5973
- const toolsRef = React2.useRef(registeredTools);
5974
- toolsRef.current = registeredTools;
5975
- const executeTool = React2.useCallback(
5976
- async (toolCall) => {
5977
- const tool2 = toolsRef.current.find((t) => t.name === toolCall.name);
5978
- if (!tool2) {
5979
- return {
5980
- success: false,
5981
- error: `Unknown tool: ${toolCall.name}`
5982
- };
5983
- }
5984
- if (!tool2.handler) {
5985
- return {
5986
- success: false,
5987
- error: `Tool "${toolCall.name}" has no handler`
5988
- };
5989
- }
5990
- const execution = {
5991
- id: toolCall.id,
5992
- name: toolCall.name,
5993
- args: toolCall.input,
5994
- status: "executing",
5995
- timestamp: Date.now(),
5996
- approvalStatus: "none",
5997
- hidden: tool2.hidden
5998
- };
5999
- addToolExecution?.(execution);
6000
- try {
6001
- const startTime = Date.now();
6002
- const result = await tool2.handler(toolCall.input);
6003
- const duration = Date.now() - startTime;
6004
- updateToolExecution?.(toolCall.id, {
6005
- status: result.success ? "completed" : "error",
6006
- result,
6007
- error: result.error,
6008
- duration
6009
- });
6010
- return result;
6011
- } catch (error) {
6012
- const errorMessage = error instanceof Error ? error.message : "Tool execution failed";
6013
- updateToolExecution?.(toolCall.id, {
6014
- status: "error",
6015
- error: errorMessage
6016
- });
6017
- return {
6018
- success: false,
6019
- error: errorMessage
6020
- };
6021
- }
6022
- },
6023
- [addToolExecution, updateToolExecution]
6024
- );
6025
- const sendToolResult = React2.useCallback(
6026
- async (toolCallId, result) => {
6027
- const runtimeUrl = config.runtimeUrl || config.cloud?.endpoint;
6028
- if (!runtimeUrl) {
6029
- console.warn(
6030
- "[useToolExecutor] No runtime URL configured, cannot send tool result"
6031
- );
6032
- return;
6033
- }
6034
- const baseUrl = runtimeUrl.replace(/\/chat\/?$/, "");
6035
- try {
6036
- const response = await fetch(`${baseUrl}/tool-result`, {
6037
- method: "POST",
6038
- headers: {
6039
- "Content-Type": "application/json"
6040
- },
6041
- body: JSON.stringify({
6042
- threadId: chat.threadId || "default",
6043
- toolCallId,
6044
- result
6045
- })
6046
- });
6047
- if (!response.ok) {
6048
- console.error(
6049
- "[useToolExecutor] Failed to send tool result:",
6050
- await response.text()
6051
- );
6052
- }
6053
- } catch (error) {
6054
- console.error("[useToolExecutor] Error sending tool result:", error);
6055
- }
6056
- },
6057
- [config.runtimeUrl, config.cloud?.endpoint, chat.threadId]
6058
- );
6059
- const getTool = React2.useCallback((name) => {
6060
- return toolsRef.current.find((t) => t.name === name);
6061
- }, []);
6062
- const hasTool = React2.useCallback((name) => {
6063
- return toolsRef.current.some((t) => t.name === name);
6064
- }, []);
6065
- return {
6066
- executeTool,
6067
- sendToolResult,
6068
- getTool,
6069
- hasTool
6070
- };
6071
- }
6072
- function useSuggestions(options = {}) {
6073
- const {
6074
- count = 3,
6075
- context,
6076
- suggestions: staticSuggestions,
6077
- autoRefresh = true
6078
- } = options;
6079
- const { chat, actions, config } = useCopilotContext();
6080
- const [suggestions, setSuggestions] = React2.useState([]);
6081
- const [isLoading, setIsLoading] = React2.useState(false);
6082
- const normalizedStatic = React2.useMemo(
6083
- () => staticSuggestions?.map((s) => typeof s === "string" ? { text: s } : s),
6084
- [staticSuggestions]
6085
- );
6086
- const refresh = React2.useCallback(async () => {
6087
- if (normalizedStatic) {
6088
- setSuggestions(normalizedStatic.slice(0, count));
6089
- return;
6090
- }
6091
- if (!config.cloud) {
6092
- return;
6093
- }
6094
- setIsLoading(true);
6095
- try {
6096
- const endpoint = config.cloud.endpoint || "https://api.yourgpt.ai/v1";
6097
- const response = await fetch(`${endpoint}/suggestions`, {
6098
- method: "POST",
6099
- headers: {
6100
- "Content-Type": "application/json",
6101
- Authorization: `Bearer ${config.cloud.apiKey}`
6102
- },
6103
- body: JSON.stringify({
6104
- botId: config.cloud.botId,
6105
- count,
6106
- context,
6107
- messages: chat.messages.slice(-5)
6108
- // Last 5 messages for context
6109
- })
6110
- });
6111
- if (response.ok) {
6112
- const data = await response.json();
6113
- setSuggestions(
6114
- data.suggestions.map(
6115
- (s) => typeof s === "string" ? { text: s } : s
6116
- )
6117
- );
6118
- }
6119
- } catch (error) {
6120
- console.error("Failed to fetch suggestions:", error);
6121
- } finally {
6122
- setIsLoading(false);
6123
- }
6124
- }, [config.cloud, count, context, chat.messages, normalizedStatic]);
6125
- const select = React2.useCallback(
6126
- (suggestion) => {
6127
- const text = typeof suggestion === "string" ? suggestion : suggestion.text;
6128
- actions.sendMessage(text);
6129
- },
6130
- [actions]
6131
- );
6132
- React2.useEffect(() => {
6133
- if (autoRefresh && chat.messages.length === 0) {
6134
- refresh();
6135
- }
6136
- }, [autoRefresh, chat.messages.length, refresh]);
6137
- return {
6138
- suggestions: normalizedStatic?.slice(0, count) || suggestions,
6139
- isLoading,
6140
- refresh,
6141
- select
6142
- };
6143
- }
6144
- function useAgent(options) {
6145
- const { name, initialState = {}, onStateChange } = options;
6146
- const { config } = useCopilotContext();
6147
- const [state, setStateInternal] = React2.useState(initialState);
6148
- const [isRunning, setIsRunning] = React2.useState(false);
6149
- const [nodeName, setNodeName] = React2.useState(null);
6150
- const [error, setError] = React2.useState(null);
6151
- const abortControllerRef = React2.useRef(null);
6152
- const getEndpoint = React2.useCallback(() => {
6153
- if (config.cloud) {
6154
- return `${config.cloud.endpoint || "https://api.yourgpt.ai/v1"}/agents/${name}`;
6155
- }
6156
- return `${config.runtimeUrl || "/api"}/agents/${name}`;
6157
- }, [config, name]);
6158
- const start = React2.useCallback(
6159
- async (input) => {
6160
- setIsRunning(true);
6161
- setError(null);
6162
- abortControllerRef.current = new AbortController();
6163
- try {
6164
- const endpoint = getEndpoint();
6165
- const headers = {
6166
- "Content-Type": "application/json"
6167
- };
6168
- if (config.cloud?.apiKey) {
6169
- headers["Authorization"] = `Bearer ${config.cloud.apiKey}`;
6170
- }
6171
- const response = await fetch(`${endpoint}/start`, {
6172
- method: "POST",
6173
- headers,
6174
- body: JSON.stringify({
6175
- input: typeof input === "string" ? { message: input } : input,
6176
- state
6177
- }),
6178
- signal: abortControllerRef.current.signal
6179
- });
6180
- if (!response.ok) {
6181
- throw new Error(`Agent error: ${response.status}`);
6182
- }
6183
- for await (const event of chunkB4YDIMP3_cjs.streamSSE(response)) {
6184
- handleAgentEvent(event);
6185
- }
6186
- } catch (err) {
6187
- if (err.name !== "AbortError") {
6188
- setError(err instanceof Error ? err : new Error("Unknown error"));
6189
- }
6190
- } finally {
6191
- setIsRunning(false);
6192
- abortControllerRef.current = null;
6193
- }
6194
- },
6195
- [config, getEndpoint, state]
6196
- );
6197
- const handleAgentEvent = React2.useCallback(
6198
- (event) => {
6199
- if (event.type === "error") {
6200
- setError(new Error(event.message));
6201
- return;
6202
- }
6203
- if ("state" in event && event.state) {
6204
- setStateInternal(event.state);
6205
- onStateChange?.(event.state);
6206
- }
6207
- if ("nodeName" in event && event.nodeName) {
6208
- setNodeName(event.nodeName);
6209
- }
6210
- },
6211
- [onStateChange]
6212
- );
6213
- const stop = React2.useCallback(() => {
6214
- abortControllerRef.current?.abort();
6215
- }, []);
6216
- const setState = React2.useCallback(
6217
- (partialState) => {
6218
- setStateInternal((prev) => {
6219
- const newState = { ...prev, ...partialState };
6220
- onStateChange?.(newState);
6221
- return newState;
6222
- });
6223
- },
6224
- [onStateChange]
6225
- );
6226
- React2.useEffect(() => {
6227
- return () => {
6228
- abortControllerRef.current?.abort();
6229
- };
6230
- }, []);
6231
- return {
6232
- state,
6233
- isRunning,
6234
- nodeName,
6235
- start,
6236
- stop,
6237
- setState,
6238
- error
6239
- };
6240
- }
6241
-
6242
- // src/react/utils/knowledge-base.ts
6243
- var KNOWLEDGE_BASE_API = "https://api.yourgpt.ai/chatbot/v1/searchIndexDocument";
6244
- async function searchKnowledgeBase(query, config) {
6245
- try {
6246
- const response = await fetch(KNOWLEDGE_BASE_API, {
6247
- method: "POST",
6248
- headers: {
6249
- accept: "*/*",
6250
- "content-type": "application/json",
6251
- authorization: `Bearer ${config.token}`
6252
- },
6253
- body: JSON.stringify({
6254
- project_uid: config.projectUid,
6255
- query,
6256
- page: 1,
6257
- limit: String(config.limit || 10),
6258
- app_id: config.appId || "1"
6259
- })
6260
- });
6261
- if (!response.ok) {
6262
- return {
6263
- success: false,
6264
- results: [],
6265
- error: `API error: ${response.status} ${response.statusText}`
6266
- };
6267
- }
6268
- const data = await response.json();
6269
- const results = (data.data || data.results || []).map((item) => ({
6270
- id: item.id || item._id || String(Math.random()),
6271
- title: item.title || item.name || void 0,
6272
- content: item.content || item.text || item.snippet || "",
6273
- score: item.score || item.relevance || void 0,
6274
- url: item.url || item.source_url || void 0,
6275
- metadata: item.metadata || {}
6276
- }));
6277
- return {
6278
- success: true,
6279
- results,
6280
- total: data.total || results.length,
6281
- page: data.page || 1
6282
- };
6283
- } catch (error) {
6284
- return {
6285
- success: false,
6286
- results: [],
6287
- error: error instanceof Error ? error.message : "Unknown error"
6288
- };
6289
- }
6290
- }
6291
- function formatKnowledgeResultsForAI(results) {
6292
- if (results.length === 0) {
6293
- return "No relevant documents found in the knowledge base.";
6294
- }
6295
- return results.map((result, index) => {
6296
- const parts = [`[${index + 1}]`];
6297
- if (result.title) parts.push(`**${result.title}**`);
6298
- parts.push(result.content);
6299
- if (result.url) parts.push(`Source: ${result.url}`);
6300
- return parts.join("\n");
6301
- }).join("\n\n---\n\n");
6302
- }
6303
-
6304
- // src/react/hooks/useKnowledgeBase.ts
6305
- function useKnowledgeBase(config) {
6306
- const { registerTool, unregisterTool } = useCopilot();
6307
- const configRef = React2.useRef(config);
6308
- configRef.current = config;
6309
- const handleSearch = React2.useCallback(
6310
- async (params) => {
6311
- const query = params.query;
6312
- if (!query) {
6313
- return {
6314
- success: false,
6315
- error: "Query is required"
6316
- };
6317
- }
6318
- const currentConfig = configRef.current;
6319
- const kbConfig = {
6320
- projectUid: currentConfig.projectUid,
6321
- token: currentConfig.token,
6322
- appId: currentConfig.appId,
6323
- limit: currentConfig.limit || 5
6324
- };
6325
- const response = await searchKnowledgeBase(
6326
- query,
6327
- kbConfig
6328
- );
6329
- if (!response.success) {
6330
- return {
6331
- success: false,
6332
- error: response.error || "Knowledge base search failed"
6333
- };
6334
- }
6335
- const formattedResults = formatKnowledgeResultsForAI(response.results);
6336
- return {
6337
- success: true,
6338
- message: formattedResults,
6339
- data: {
6340
- resultCount: response.results.length,
6341
- total: response.total
6342
- }
6343
- };
6344
- },
6345
- []
6346
- );
6347
- React2.useEffect(() => {
6348
- if (config.enabled === false) {
6349
- return;
6350
- }
6351
- registerTool({
6352
- name: "search_knowledge",
6353
- description: "Search the knowledge base for relevant information about the product, documentation, or company. Use this to answer questions about features, pricing, policies, guides, or any factual information.",
6354
- location: "client",
6355
- inputSchema: {
6356
- type: "object",
6357
- properties: {
6358
- query: {
6359
- type: "string",
6360
- description: "The search query to find relevant information in the knowledge base"
6361
- }
6362
- },
6363
- required: ["query"]
6364
- },
6365
- handler: handleSearch
6366
- });
6367
- return () => {
6368
- unregisterTool("search_knowledge");
6369
- };
6370
- }, [
6371
- config.enabled,
6372
- config.projectUid,
6373
- config.token,
6374
- registerTool,
6375
- unregisterTool,
6376
- handleSearch
6377
- ]);
6378
- }
6379
- var DEFAULT_CAPABILITIES = {
6380
- supportsVision: false,
6381
- supportsTools: true,
6382
- supportsThinking: false,
6383
- supportsStreaming: true,
6384
- supportsPDF: false,
6385
- supportsAudio: false,
6386
- supportsVideo: false,
6387
- maxTokens: 8192,
6388
- supportedImageTypes: [],
6389
- supportsJsonMode: false,
6390
- supportsSystemMessages: true
6391
- };
6392
- function useCapabilities() {
6393
- const { config } = useCopilotContext();
6394
- const [capabilities, setCapabilities] = React2.useState(DEFAULT_CAPABILITIES);
6395
- const [provider, setProvider] = React2.useState("unknown");
6396
- const [model, setModel] = React2.useState("unknown");
6397
- const [supportedModels, setSupportedModels] = React2.useState([]);
6398
- const [isLoading, setIsLoading] = React2.useState(true);
6399
- const [error, setError] = React2.useState(null);
6400
- const capabilitiesUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/chat\/?$/, "/capabilities") : null;
6401
- const fetchCapabilities = React2.useCallback(async () => {
6402
- if (!capabilitiesUrl) {
6403
- setIsLoading(false);
6404
- return;
6405
- }
6406
- try {
6407
- setIsLoading(true);
6408
- setError(null);
6409
- const response = await fetch(capabilitiesUrl);
6410
- if (!response.ok) {
6411
- throw new Error(`Failed to fetch capabilities: ${response.status}`);
6412
- }
6413
- const data = await response.json();
6414
- setCapabilities(data.capabilities);
6415
- setProvider(data.provider);
6416
- setModel(data.model);
6417
- setSupportedModels(data.supportedModels);
6418
- } catch (err) {
6419
- setError(err instanceof Error ? err : new Error("Unknown error"));
6420
- } finally {
6421
- setIsLoading(false);
6422
- }
6423
- }, [capabilitiesUrl]);
6424
- React2.useEffect(() => {
6425
- fetchCapabilities();
6426
- }, [fetchCapabilities]);
6427
- return {
6428
- /** Current model capabilities */
6429
- capabilities,
6430
- /** Current provider name */
6431
- provider,
6432
- /** Current model ID */
6433
- model,
6434
- /** List of supported models for current provider */
6435
- supportedModels,
6436
- /** Whether capabilities are being loaded */
6437
- isLoading,
6438
- /** Error if fetch failed */
6439
- error,
6440
- /** Refetch capabilities */
6441
- refetch: fetchCapabilities
6442
- };
6443
- }
6444
- function useFeatureSupport(feature) {
6445
- const { capabilities } = useCapabilities();
6446
- return capabilities[feature] ?? false;
6447
- }
6448
- function useSupportedMediaTypes() {
6449
- const { capabilities } = useCapabilities();
6450
- return {
6451
- /** Supported image MIME types */
6452
- imageTypes: capabilities.supportedImageTypes || [],
6453
- /** Supported audio MIME types */
6454
- audioTypes: capabilities.supportedAudioTypes || [],
6455
- /** Supported video MIME types */
6456
- videoTypes: capabilities.supportedVideoTypes || [],
6457
- /** Whether any image types are supported */
6458
- hasImageSupport: (capabilities.supportedImageTypes?.length ?? 0) > 0,
6459
- /** Whether any audio types are supported */
6460
- hasAudioSupport: (capabilities.supportedAudioTypes?.length ?? 0) > 0,
6461
- /** Whether any video types are supported */
6462
- hasVideoSupport: (capabilities.supportedVideoTypes?.length ?? 0) > 0
6463
- };
6464
- }
6465
- function useDevLogger() {
6466
- const ctx = useCopilotContext();
6467
- return React2.useMemo(() => {
6468
- const toolExecutions = (ctx.agentLoop?.toolExecutions || []).map(
6469
- (exec) => ({
6470
- id: exec.id,
6471
- name: exec.name,
6472
- status: exec.status,
6473
- approvalStatus: exec.approvalStatus || "not_required"
6474
- })
6475
- );
6476
- const pendingApprovalsCount = ctx.pendingApprovals?.length || 0;
6477
- const registeredTools = (ctx.registeredTools || []).map((tool2) => ({
6478
- name: tool2.name,
6479
- location: tool2.location || "client"
6480
- }));
6481
- const registeredActions = (ctx.registeredActions || []).map((action) => ({
6482
- name: action.name
6483
- }));
6484
- const storedPermissions = (ctx.storedPermissions || []).map((p) => ({
6485
- toolName: p.toolName,
6486
- level: p.level
6487
- }));
6488
- return {
6489
- chat: {
6490
- isLoading: ctx.chat?.isLoading || false,
6491
- messageCount: ctx.chat?.messages?.length || 0,
6492
- threadId: ctx.chat?.threadId || "none",
6493
- error: ctx.chat?.error?.message || null
6494
- },
6495
- tools: {
6496
- isEnabled: !!ctx.toolsConfig,
6497
- isCapturing: ctx.tools?.isCapturing || false,
6498
- pendingConsent: !!ctx.tools?.pendingConsent
6499
- },
6500
- agentLoop: {
6501
- toolExecutions,
6502
- pendingApprovals: pendingApprovalsCount,
6503
- iteration: ctx.agentLoop?.iteration || 0,
6504
- maxIterations: ctx.agentLoop?.maxIterations || 10
6505
- },
6506
- registered: {
6507
- tools: registeredTools,
6508
- actions: registeredActions,
6509
- contextCount: ctx.contextTree?.length || 0
6510
- },
6511
- permissions: {
6512
- stored: storedPermissions,
6513
- loaded: ctx.permissionsLoaded || false
6514
- },
6515
- config: {
6516
- runtimeUrl: ctx.config?.runtimeUrl || ctx.config?.cloud?.endpoint || ""
6517
- }
6518
- };
6519
- }, [
6520
- ctx.chat,
6521
- ctx.tools,
6522
- ctx.toolsConfig,
6523
- ctx.agentLoop,
6524
- ctx.pendingApprovals,
6525
- ctx.registeredTools,
6526
- ctx.registeredActions,
6527
- ctx.contextTree,
6528
- ctx.storedPermissions,
6529
- ctx.permissionsLoaded,
6530
- ctx.config
6531
- ]);
6532
- }
6533
-
6534
- // src/react/internal/ReactThreadManagerState.ts
6535
- var ReactThreadManagerState = class {
6536
- constructor(initialThreads) {
6537
- this._threads = [];
6538
- this._currentThreadId = null;
6539
- this._currentThread = null;
6540
- this._loadStatus = "idle";
6541
- this._error = void 0;
6542
- // Callbacks for React subscriptions (useSyncExternalStore)
6543
- this.subscribers = /* @__PURE__ */ new Set();
6544
- // ============================================
6545
- // Subscription (for useSyncExternalStore)
6546
- // ============================================
6547
- /**
6548
- * Subscribe to state changes.
6549
- * Returns an unsubscribe function.
6550
- *
6551
- * @example
6552
- * ```tsx
6553
- * const threads = useSyncExternalStore(
6554
- * state.subscribe,
6555
- * () => state.threads
6556
- * );
6557
- * ```
6558
- */
6559
- this.subscribe = (callback) => {
6560
- this.subscribers.add(callback);
6561
- return () => {
6562
- this.subscribers.delete(callback);
6563
- };
6564
- };
6565
- if (initialThreads) {
6566
- this._threads = initialThreads;
6567
- }
6568
- }
6569
- // ============================================
6570
- // Getters
6571
- // ============================================
6572
- get threads() {
6573
- return this._threads;
6574
- }
6575
- get currentThreadId() {
6576
- return this._currentThreadId;
6577
- }
6578
- get currentThread() {
6579
- return this._currentThread;
6580
- }
6581
- get loadStatus() {
6582
- return this._loadStatus;
6583
- }
6584
- get error() {
6585
- return this._error;
6586
- }
6587
- // ============================================
6588
- // Setters (trigger reactivity)
6589
- // ============================================
6590
- set threads(value) {
6591
- this._threads = value;
6592
- this.notify();
6593
- }
6594
- // ============================================
6595
- // Mutations
6596
- // ============================================
6597
- setThreads(threads) {
6598
- this._threads = threads;
6599
- this.notify();
6600
- }
6601
- setCurrentThread(thread) {
6602
- this._currentThread = thread;
6603
- this._currentThreadId = thread?.id ?? null;
6604
- this.notify();
6605
- }
6606
- setCurrentThreadId(id) {
6607
- this._currentThreadId = id;
6608
- this.notify();
6609
- }
6610
- addThread(thread) {
6611
- this._threads = [thread, ...this._threads];
6612
- this.notify();
6613
- }
6614
- updateThread(id, updates) {
6615
- this._threads = this._threads.map(
6616
- (t) => t.id === id ? { ...t, ...updates } : t
6617
- );
6618
- if (updates.updatedAt) {
6619
- this._threads = [...this._threads].sort(
6620
- (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
6621
- );
6622
- }
6623
- if (this._currentThread?.id === id) {
6624
- this._currentThread = { ...this._currentThread, ...updates };
6625
- }
6626
- this.notify();
6627
- }
6628
- removeThread(id) {
6629
- this._threads = this._threads.filter((t) => t.id !== id);
6630
- if (this._currentThreadId === id) {
6631
- this._currentThreadId = null;
6632
- this._currentThread = null;
6633
- }
6634
- this.notify();
6635
- }
6636
- setLoadStatus(status) {
6637
- this._loadStatus = status;
6638
- this.notify();
6639
- }
6640
- setError(error) {
6641
- this._error = error;
6642
- this.notify();
6643
- }
6644
- // ============================================
6645
- // Snapshots (for useSyncExternalStore)
6646
- // ============================================
6647
- getThreadsSnapshot() {
6648
- return this._threads;
6649
- }
6650
- getCurrentThreadSnapshot() {
6651
- return this._currentThread;
6652
- }
6653
- getLoadStatusSnapshot() {
6654
- return this._loadStatus;
6655
- }
6656
- getErrorSnapshot() {
6657
- return this._error;
6658
- }
6659
- // ============================================
6660
- // Private Methods
6661
- // ============================================
6662
- notify() {
6663
- this.subscribers.forEach((cb) => cb());
6664
- }
6665
- /**
6666
- * Cleanup subscriptions
6667
- */
6668
- dispose() {
6669
- this.subscribers.clear();
6670
- }
6671
- };
6672
- function createReactThreadManagerState(initialThreads) {
6673
- return new ReactThreadManagerState(initialThreads);
6674
- }
6675
-
6676
- // src/react/internal/ReactThreadManager.ts
6677
- var _ReactThreadManager = class _ReactThreadManager extends chunkB4YDIMP3_cjs.ThreadManager {
6678
- constructor(config = {}, callbacks = {}) {
6679
- const reactState = new ReactThreadManagerState();
6680
- super({ ...config, state: reactState }, callbacks);
6681
- // ============================================
6682
- // Subscription Methods (for useSyncExternalStore)
6683
- // ============================================
6684
- /**
6685
- * Subscribe to state changes
6686
- * Use with useSyncExternalStore
6687
- */
6688
- this.subscribe = (callback) => {
6689
- return this.state.subscribe(callback);
6690
- };
6691
- // ============================================
6692
- // Snapshot Getters (for useSyncExternalStore)
6693
- // ============================================
6694
- /**
6695
- * Get threads snapshot
6696
- */
6697
- this.getThreadsSnapshot = () => {
6698
- return this.state.getThreadsSnapshot();
6699
- };
6700
- /**
6701
- * Get current thread snapshot
6702
- */
6703
- this.getCurrentThreadSnapshot = () => {
6704
- return this.state.getCurrentThreadSnapshot();
6705
- };
6706
- /**
6707
- * Get current thread ID snapshot
6708
- */
6709
- this.getCurrentThreadIdSnapshot = () => {
6710
- return this.state.currentThreadId;
6711
- };
6712
- /**
6713
- * Get load status snapshot
6714
- */
6715
- this.getLoadStatusSnapshot = () => {
6716
- return this.state.getLoadStatusSnapshot();
6717
- };
6718
- /**
6719
- * Get error snapshot
6720
- */
6721
- this.getErrorSnapshot = () => {
6722
- return this.state.getErrorSnapshot();
6723
- };
6724
- /**
6725
- * Get isLoading snapshot
6726
- */
6727
- this.getIsLoadingSnapshot = () => {
6728
- return this.state.getLoadStatusSnapshot() === "loading";
6729
- };
6730
- /**
6731
- * Get threads snapshot for server (always empty for hydration consistency)
6732
- */
6733
- this.getThreadsServerSnapshot = () => {
6734
- return _ReactThreadManager.EMPTY_THREADS;
6735
- };
6736
- /**
6737
- * Get current thread snapshot for server (always null)
6738
- */
6739
- this.getCurrentThreadServerSnapshot = () => {
6740
- return null;
6741
- };
6742
- /**
6743
- * Get current thread ID snapshot for server (always null)
6744
- */
6745
- this.getCurrentThreadIdServerSnapshot = () => {
6746
- return null;
6747
- };
6748
- /**
6749
- * Get load status snapshot for server (always "idle")
6750
- */
6751
- this.getLoadStatusServerSnapshot = () => {
6752
- return _ReactThreadManager.IDLE_STATUS;
6753
- };
6754
- /**
6755
- * Get error snapshot for server (always undefined)
6756
- */
6757
- this.getErrorServerSnapshot = () => {
6758
- return void 0;
6759
- };
6760
- /**
6761
- * Get isLoading snapshot for server (always false)
6762
- */
6763
- this.getIsLoadingServerSnapshot = () => {
6764
- return false;
6765
- };
6766
- }
6767
- // ============================================
6768
- // Cleanup
6769
- // ============================================
6770
- /**
6771
- * Dispose of the manager
6772
- */
6773
- async dispose() {
6774
- this.state.dispose();
6775
- await super.dispose();
6776
- }
6777
- };
6778
- // ============================================
6779
- // Server Snapshots (for SSR - stable cached values)
6780
- // ============================================
6781
- // Cached values for server snapshots (must be stable references)
6782
- _ReactThreadManager.EMPTY_THREADS = [];
6783
- _ReactThreadManager.IDLE_STATUS = "idle";
6784
- var ReactThreadManager = _ReactThreadManager;
6785
- function createReactThreadManager(config, callbacks) {
6786
- return new ReactThreadManager(config, callbacks);
6787
- }
6788
-
6789
- // src/react/hooks/useThreadManager.ts
6790
- var defaultManager = null;
6791
- function getDefaultManager() {
6792
- if (!defaultManager) {
6793
- defaultManager = createReactThreadManager();
6794
- }
6795
- return defaultManager;
6796
- }
6797
- var internalManager = null;
6798
- function getInternalManager(config) {
6799
- if (!internalManager) {
6800
- internalManager = createReactThreadManager(
6801
- {
6802
- adapter: config.adapter,
6803
- saveDebounce: config.saveDebounce,
6804
- autoLoad: config.autoLoad,
6805
- autoRestoreLastThread: config.autoRestoreLastThread
6806
- },
6807
- config.callbacks
6808
- );
6809
- }
6810
- return internalManager;
6811
- }
6812
- function useThreadManager(config) {
6813
- const manager = React2.useMemo(() => {
6814
- if (!config) {
6815
- return getDefaultManager();
6816
- }
6817
- if (!config.adapter) {
6818
- return getInternalManager(config);
6819
- }
6820
- return createReactThreadManager(
6821
- {
6822
- adapter: config.adapter,
6823
- saveDebounce: config.saveDebounce,
6824
- autoLoad: config.autoLoad,
6825
- autoRestoreLastThread: config.autoRestoreLastThread
6826
- },
6827
- config.callbacks
6828
- );
6829
- }, [
6830
- config?.adapter,
6831
- config?.saveDebounce,
6832
- config?.autoLoad,
6833
- config?.autoRestoreLastThread
6834
- // Note: callbacks are intentionally not in deps to avoid recreating manager
6835
- ]);
6836
- const threads = React2.useSyncExternalStore(
6837
- manager.subscribe,
6838
- manager.getThreadsSnapshot,
6839
- manager.getThreadsServerSnapshot
6840
- // SSR - always empty array
6841
- );
6842
- const currentThread = React2.useSyncExternalStore(
6843
- manager.subscribe,
6844
- manager.getCurrentThreadSnapshot,
6845
- manager.getCurrentThreadServerSnapshot
6846
- // SSR - always null
6847
- );
6848
- const currentThreadId = React2.useSyncExternalStore(
6849
- manager.subscribe,
6850
- manager.getCurrentThreadIdSnapshot,
6851
- manager.getCurrentThreadIdServerSnapshot
6852
- // SSR - always null
6853
- );
6854
- const loadStatus = React2.useSyncExternalStore(
6855
- manager.subscribe,
6856
- manager.getLoadStatusSnapshot,
6857
- manager.getLoadStatusServerSnapshot
6858
- // SSR - always "idle"
6859
- );
6860
- const error = React2.useSyncExternalStore(
6861
- manager.subscribe,
6862
- manager.getErrorSnapshot,
6863
- manager.getErrorServerSnapshot
6864
- // SSR - always undefined
6865
- );
6866
- const isLoading = React2.useSyncExternalStore(
6867
- manager.subscribe,
6868
- manager.getIsLoadingSnapshot,
6869
- manager.getIsLoadingServerSnapshot
6870
- // SSR - always false
6871
- );
6872
- React2.useEffect(() => {
6873
- return () => {
6874
- if (config?.adapter && manager !== defaultManager && manager !== internalManager) {
6875
- manager.dispose();
6876
- }
6877
- };
6878
- }, [manager, config]);
6879
- React2.useEffect(() => {
6880
- const handleBeforeUnload = () => {
6881
- if (manager.hasPendingChanges) {
6882
- manager.saveNow().catch(() => {
6883
- });
6884
- }
6885
- };
6886
- if (typeof window !== "undefined") {
6887
- window.addEventListener("beforeunload", handleBeforeUnload);
6888
- return () => {
6889
- window.removeEventListener("beforeunload", handleBeforeUnload);
6890
- };
6891
- }
6892
- }, [manager]);
6893
- const createThread = React2.useCallback(
6894
- (options) => manager.createThread(options),
6895
- [manager]
6896
- );
6897
- const switchThread = React2.useCallback(
6898
- (id) => manager.switchThread(id),
6899
- [manager]
6900
- );
6901
- const updateCurrentThread = React2.useCallback(
6902
- (updates) => manager.updateCurrentThread(updates),
6903
- [manager]
6904
- );
6905
- const deleteThread = React2.useCallback(
6906
- (id) => manager.deleteThread(id),
6907
- [manager]
6908
- );
6909
- const clearCurrentThread = React2.useCallback(
6910
- () => manager.clearCurrentThread(),
6911
- [manager]
6912
- );
6913
- const refreshThreads = React2.useCallback(() => manager.loadThreads(), [manager]);
6914
- const saveNow = React2.useCallback(() => manager.saveNow(), [manager]);
6915
- const clearAllThreads = React2.useCallback(
6916
- () => manager.clearAllThreads(),
6917
- [manager]
6918
- );
6919
- const messages = React2.useMemo(
6920
- () => currentThread?.messages ?? [],
6921
- [currentThread]
6922
- );
6923
- const setMessages = React2.useCallback(
6924
- (newMessages) => updateCurrentThread({ messages: newMessages }),
6925
- [updateCurrentThread]
6926
- );
6927
- const hasPendingChanges = manager.hasPendingChanges;
6928
- return {
6929
- // State
6930
- threads,
6931
- currentThread,
6932
- currentThreadId,
6933
- isLoading,
6934
- loadStatus,
6935
- error,
6936
- // Actions
6937
- createThread,
6938
- switchThread,
6939
- updateCurrentThread,
6940
- deleteThread,
6941
- clearCurrentThread,
6942
- refreshThreads,
6943
- saveNow,
6944
- clearAllThreads,
6945
- // Utilities
6946
- messages,
6947
- setMessages,
6948
- hasPendingChanges
6949
- };
6950
- }
6951
- function useMCPUIIntents(config = {}) {
6952
- const {
6953
- onToolCall,
6954
- onIntent,
6955
- onPrompt,
6956
- onNotify,
6957
- onLink,
6958
- requireConsent = { tool: false, link: true }
6959
- } = config;
6960
- const handleIntent = React2.useCallback(
6961
- async (intent, context) => {
6962
- switch (intent.type) {
6963
- case "tool": {
6964
- if (requireConsent.tool) ;
6965
- await onToolCall?.(intent.name, intent.arguments, context);
6966
- break;
6967
- }
6968
- case "intent": {
6969
- await onIntent?.(intent.action, intent.data, context);
6970
- break;
6971
- }
6972
- case "prompt": {
6973
- onPrompt?.(intent.text, context);
6974
- break;
6975
- }
6976
- case "notify": {
6977
- onNotify?.(intent.message, intent.level, context);
6978
- break;
6979
- }
6980
- case "link": {
6981
- const shouldContinue = onLink?.(intent.url, intent.newTab, context);
6982
- if (shouldContinue === false) {
6983
- break;
6984
- }
6985
- if (requireConsent.link) {
6986
- const isSafeUrl = intent.url.startsWith("https://") || intent.url.startsWith("http://localhost");
6987
- if (!isSafeUrl) {
6988
- console.warn(
6989
- "[MCP-UI] Blocked potentially unsafe link:",
6990
- intent.url
6991
- );
6992
- break;
6993
- }
6994
- }
6995
- if (typeof window !== "undefined") {
6996
- if (intent.newTab !== false) {
6997
- window.open(intent.url, "_blank", "noopener,noreferrer");
6998
- } else {
6999
- window.location.href = intent.url;
7000
- }
7001
- }
7002
- break;
7003
- }
7004
- default: {
7005
- console.warn(
7006
- "[MCP-UI] Unknown intent type:",
7007
- intent.type
7008
- );
7009
- }
7010
- }
7011
- },
7012
- [onToolCall, onIntent, onPrompt, onNotify, onLink, requireConsent]
7013
- );
7014
- return React2.useMemo(
7015
- () => ({
7016
- handleIntent
7017
- }),
7018
- [handleIntent]
7019
- );
7020
- }
7021
- function createMessageIntentHandler(sendMessage) {
7022
- return {
7023
- onIntent: async (action, data) => {
7024
- const dataStr = data ? ` with ${JSON.stringify(data)}` : "";
7025
- await sendMessage(`User action: ${action}${dataStr}`);
7026
- },
7027
- onPrompt: (text) => {
7028
- sendMessage(text);
7029
- },
7030
- onNotify: (message, level) => {
7031
- if (level === "error") {
7032
- sendMessage(`Error: ${message}`);
7033
- }
7034
- }
7035
- };
7036
- }
7037
- function createToolIntentHandler(callTool) {
7038
- return {
7039
- onToolCall: async (name, args) => {
7040
- await callTool(name, args);
7041
- }
7042
- };
7043
- }
7044
- function getLastResponseUsage(messages) {
7045
- for (let i = messages.length - 1; i >= 0; i--) {
7046
- const msg = messages[i];
7047
- if (msg.role === "assistant" && msg.metadata?.usage) {
7048
- const u = msg.metadata.usage;
7049
- const prompt = u.prompt_tokens ?? 0;
7050
- const completion = u.completion_tokens ?? 0;
7051
- return {
7052
- prompt_tokens: prompt,
7053
- completion_tokens: completion,
7054
- total_tokens: u.total_tokens ?? prompt + completion
7055
- };
7056
- }
7057
- }
7058
- return null;
7059
- }
7060
- function useContextStats() {
7061
- const { contextChars, contextUsage, registeredTools, messages } = useCopilot();
7062
- const toolCount = React2.useMemo(() => registeredTools.length, [registeredTools]);
7063
- const messageCount = React2.useMemo(
7064
- () => messages.filter((m) => m.role !== "system").length,
7065
- [messages]
7066
- );
7067
- const totalTokens = React2.useMemo(() => {
7068
- if (contextUsage) return contextUsage.total.tokens;
7069
- return Math.ceil(contextChars / 3.5);
7070
- }, [contextUsage, contextChars]);
7071
- const usagePercent = React2.useMemo(() => {
7072
- if (contextUsage) return contextUsage.total.percent;
7073
- return 0;
7074
- }, [contextUsage]);
7075
- const lastResponseUsage = React2.useMemo(
7076
- () => getLastResponseUsage(messages),
7077
- [messages]
7078
- );
7079
- return {
7080
- contextUsage,
7081
- totalTokens,
7082
- usagePercent,
7083
- contextChars,
7084
- toolCount,
7085
- messageCount,
7086
- lastResponseUsage
7087
- };
7088
- }
7089
- var DEV_CONTENT_WARN_THRESHOLD = 2e3;
7090
- function useSkill(skill) {
7091
- const { register, unregister } = useSkillContext();
7092
- if (process.env.NODE_ENV !== "production" && skill.source.type === "inline" && skill.source.content.length > DEV_CONTENT_WARN_THRESHOLD) {
7093
- console.warn(
7094
- `[copilot-sdk/skills] Inline skill "${skill.name}" has ${skill.source.content.length} characters. Inline skills are sent on every request \u2014 keep them under ${DEV_CONTENT_WARN_THRESHOLD} characters. Consider using a file or URL skill instead.`
7095
- );
7096
- }
7097
- React2.useEffect(() => {
7098
- if (skill.source.type !== "inline") {
7099
- console.warn(
7100
- `[copilot-sdk/skills] useSkill only supports inline skills client-side. Skill "${skill.name}" has source type "${skill.source.type}" and will be skipped.`
7101
- );
7102
- return;
7103
- }
7104
- const resolved = {
7105
- ...skill,
7106
- content: skill.source.content
7107
- };
7108
- register(resolved);
7109
- return () => {
7110
- unregister(skill.name);
7111
- };
7112
- }, [
7113
- skill.name,
7114
- skill.source.type === "inline" ? skill.source.content : "",
7115
- skill.strategy,
7116
- skill.description
7117
- ]);
7118
- }
7119
- function useSkillStatus() {
7120
- const { skills, registry } = useSkillContext();
7121
- const has = React2.useCallback(
7122
- (name) => registry.has(name),
7123
- // eslint-disable-next-line react-hooks/exhaustive-deps
7124
- [skills]
7125
- );
7126
- return {
7127
- skills,
7128
- count: skills.length,
7129
- has
7130
- };
7131
- }
7132
-
7133
- // src/react/utils/permission-storage.ts
7134
- var DEFAULT_KEY_PREFIX = "yourgpt-permissions";
7135
- function createPermissionStorage(config) {
7136
- switch (config.type) {
7137
- case "localStorage":
7138
- return createBrowserStorageAdapter(
7139
- typeof window !== "undefined" ? localStorage : null,
7140
- config.keyPrefix
7141
- );
7142
- case "sessionStorage":
7143
- return createBrowserStorageAdapter(
7144
- typeof window !== "undefined" ? sessionStorage : null,
7145
- config.keyPrefix
7146
- );
7147
- case "memory":
7148
- default:
7149
- return createMemoryStorageAdapter();
7150
- }
7151
- }
7152
- function createBrowserStorageAdapter(storage, keyPrefix = DEFAULT_KEY_PREFIX) {
7153
- const getStorageKey = () => keyPrefix;
7154
- const loadPermissions = () => {
7155
- if (!storage) return /* @__PURE__ */ new Map();
7156
- try {
7157
- const data = storage.getItem(getStorageKey());
7158
- if (!data) return /* @__PURE__ */ new Map();
7159
- const parsed = JSON.parse(data);
7160
- return new Map(parsed.map((p) => [p.toolName, p]));
7161
- } catch {
7162
- return /* @__PURE__ */ new Map();
7163
- }
7164
- };
7165
- const savePermissions = (permissions) => {
7166
- if (!storage) return;
7167
- try {
7168
- storage.setItem(
7169
- getStorageKey(),
7170
- JSON.stringify(Array.from(permissions.values()))
7171
- );
7172
- } catch (e) {
7173
- console.warn("[PermissionStorage] Failed to save permissions:", e);
7174
- }
7175
- };
7176
- return {
7177
- async get(toolName) {
7178
- const permissions = loadPermissions();
7179
- return permissions.get(toolName) || null;
7180
- },
7181
- async set(permission) {
7182
- const permissions = loadPermissions();
7183
- permissions.set(permission.toolName, permission);
7184
- savePermissions(permissions);
7185
- },
7186
- async remove(toolName) {
7187
- const permissions = loadPermissions();
7188
- permissions.delete(toolName);
7189
- savePermissions(permissions);
7190
- },
7191
- async getAll() {
7192
- const permissions = loadPermissions();
7193
- return Array.from(permissions.values());
7194
- },
7195
- async clear() {
7196
- if (!storage) return;
7197
- storage.removeItem(getStorageKey());
7198
- }
7199
- };
7200
- }
7201
- function createMemoryStorageAdapter() {
7202
- const permissions = /* @__PURE__ */ new Map();
7203
- return {
7204
- async get(toolName) {
7205
- return permissions.get(toolName) || null;
7206
- },
7207
- async set(permission) {
7208
- permissions.set(permission.toolName, permission);
7209
- },
7210
- async remove(toolName) {
7211
- permissions.delete(toolName);
7212
- },
7213
- async getAll() {
7214
- return Array.from(permissions.values());
7215
- },
7216
- async clear() {
7217
- permissions.clear();
7218
- }
7219
- };
7220
- }
7221
- function createSessionPermissionCache() {
7222
- return /* @__PURE__ */ new Map();
7223
- }
7224
-
7225
- // src/react/internal/ReactChat.ts
7226
- var ReactChat = class extends AbstractChat {
7227
- constructor(config) {
7228
- const reactState = new ReactChatState(config.initialMessages);
7229
- const init = {
7230
- runtimeUrl: config.runtimeUrl,
7231
- systemPrompt: config.systemPrompt,
7232
- llm: config.llm,
7233
- threadId: config.threadId,
7234
- streaming: config.streaming ?? true,
7235
- headers: config.headers,
7236
- initialMessages: config.initialMessages,
7237
- state: reactState,
7238
- callbacks: config.callbacks,
7239
- debug: config.debug
7240
- };
7241
- super(init);
7242
- // ============================================
7243
- // Subscribe (for useSyncExternalStore)
7244
- // ============================================
7245
- /**
7246
- * Subscribe to state changes.
7247
- * Returns an unsubscribe function.
7248
- *
7249
- * @example
7250
- * ```tsx
7251
- * const messages = useSyncExternalStore(
7252
- * chat.subscribe,
7253
- * () => chat.messages
7254
- * );
7255
- * ```
7256
- */
7257
- this.subscribe = (callback) => {
7258
- return this.reactState.subscribe(callback);
7259
- };
7260
- this.reactState = reactState;
7261
- }
7262
- // ============================================
7263
- // Event handling shortcuts
7264
- // ============================================
7265
- /**
7266
- * Subscribe to tool calls events
7267
- */
7268
- onToolCalls(handler) {
7269
- return this.on("toolCalls", handler);
7270
- }
7271
- /**
7272
- * Subscribe to done events
7273
- */
7274
- onDone(handler) {
7275
- return this.on("done", handler);
7276
- }
7277
- /**
7278
- * Subscribe to error events
7279
- */
7280
- onError(handler) {
7281
- return this.on("error", handler);
7282
- }
7283
- // ============================================
7284
- // Branching API — pass-throughs to ReactChatState
7285
- // ============================================
7286
- /**
7287
- * Navigate to a sibling branch (makes it the active path).
7288
- */
7289
- switchBranch(messageId) {
7290
- this.reactState.switchBranch(messageId);
7291
- }
7292
- /**
7293
- * Get branch navigation info for a message.
7294
- * Returns null if the message has no siblings.
7295
- */
7296
- getBranchInfo(messageId) {
7297
- return this.reactState.getBranchInfo(messageId);
7298
- }
7299
- /**
7300
- * Get all messages across all branches (for persistence).
7301
- */
7302
- getAllMessages() {
7303
- return this.reactState.getAllMessages();
7304
- }
7305
- /**
7306
- * Whether any message has siblings (branching has occurred).
7307
- */
7308
- get hasBranches() {
7309
- return this.reactState.hasBranches;
7310
- }
7311
- // ============================================
7312
- // Override dispose to clean up state
7313
- // ============================================
7314
- dispose() {
7315
- super.dispose();
7316
- this.reactState.dispose();
7317
- }
7318
- /**
7319
- * Revive a disposed instance (for React StrictMode compatibility)
7320
- */
7321
- revive() {
7322
- super.revive();
7323
- this.reactState.revive();
7324
- }
7325
- };
7326
- function createReactChat(config) {
7327
- return new ReactChat(config);
7328
- }
7329
- function useChat(config) {
7330
- const chatRef = React2.useRef(null);
7331
- const [input, setInput] = React2.useState("");
7332
- if (chatRef.current !== null && chatRef.current.disposed) {
7333
- chatRef.current.revive();
7334
- }
7335
- if (chatRef.current === null) {
7336
- chatRef.current = createReactChat({
7337
- runtimeUrl: config.runtimeUrl,
7338
- systemPrompt: config.systemPrompt,
7339
- llm: config.llm,
7340
- threadId: config.threadId,
7341
- streaming: config.streaming,
7342
- headers: config.headers,
7343
- initialMessages: config.initialMessages,
7344
- debug: config.debug,
7345
- callbacks: {
7346
- onMessagesChange: config.onMessagesChange,
7347
- onError: config.onError,
7348
- onFinish: config.onFinish,
7349
- onToolCalls: config.onToolCalls
7350
- }
7351
- });
7352
- }
7353
- const messages = React2.useSyncExternalStore(
7354
- chatRef.current.subscribe,
7355
- () => chatRef.current.messages,
7356
- () => chatRef.current.messages
7357
- // Server snapshot
5425
+ return id;
5426
+ },
5427
+ [debugLog]
7358
5428
  );
7359
- const status = React2.useSyncExternalStore(
7360
- chatRef.current.subscribe,
7361
- () => chatRef.current.status,
7362
- () => "ready"
7363
- // Server snapshot
5429
+ const removeContext = React2.useCallback(
5430
+ (id) => {
5431
+ contextTreeRef.current = removeNode(contextTreeRef.current, id);
5432
+ const contextString = printTree(contextTreeRef.current);
5433
+ chatRef.current?.setContext(contextString);
5434
+ setContextChars(contextString.length);
5435
+ debugLog("Context removed:", id);
5436
+ },
5437
+ [debugLog]
7364
5438
  );
7365
- const error = React2.useSyncExternalStore(
7366
- chatRef.current.subscribe,
7367
- () => chatRef.current.error,
7368
- () => void 0
7369
- // Server snapshot
5439
+ const setSystemPrompt = React2.useCallback(
5440
+ (prompt) => {
5441
+ chatRef.current?.setSystemPrompt(prompt);
5442
+ debugLog("System prompt updated via function");
5443
+ },
5444
+ [debugLog]
7370
5445
  );
7371
- const hasBranches = React2.useSyncExternalStore(
7372
- chatRef.current.subscribe,
7373
- () => chatRef.current.hasBranches,
7374
- () => false
5446
+ const setInlineSkills = React2.useCallback(
5447
+ (skills2) => {
5448
+ chatRef.current?.setInlineSkills(skills2);
5449
+ debugLog("Inline skills updated", { count: skills2.length });
5450
+ },
5451
+ [debugLog]
7375
5452
  );
7376
- const isLoading = status === "streaming" || status === "submitted";
7377
5453
  const sendMessage = React2.useCallback(
7378
5454
  async (content, attachments) => {
5455
+ debugLog("Sending message:", content);
5456
+ setAgentIteration(0);
7379
5457
  await chatRef.current?.sendMessage(content, attachments);
7380
- setInput("");
7381
5458
  },
7382
- []
5459
+ [debugLog]
7383
5460
  );
7384
5461
  const stop = React2.useCallback(() => {
7385
5462
  chatRef.current?.stop();
@@ -7393,19 +5470,11 @@ function useChat(config) {
7393
5470
  const regenerate = React2.useCallback(async (messageId) => {
7394
5471
  await chatRef.current?.regenerate(messageId);
7395
5472
  }, []);
7396
- const continueWithToolResults = React2.useCallback(
7397
- async (toolResults) => {
7398
- await chatRef.current?.continueWithToolResults(toolResults);
7399
- },
7400
- []
7401
- );
7402
5473
  const switchBranch = React2.useCallback((messageId) => {
7403
5474
  chatRef.current?.switchBranch(messageId);
7404
5475
  }, []);
7405
5476
  const getBranchInfo = React2.useCallback(
7406
- (messageId) => {
7407
- return chatRef.current?.getBranchInfo(messageId) ?? null;
7408
- },
5477
+ (messageId) => chatRef.current?.getBranchInfo(messageId) ?? null,
7409
5478
  []
7410
5479
  );
7411
5480
  const editMessage = React2.useCallback(
@@ -7413,40 +5482,238 @@ function useChat(config) {
7413
5482
  await chatRef.current?.sendMessage(newContent, void 0, {
7414
5483
  editMessageId: messageId
7415
5484
  });
7416
- setInput("");
7417
5485
  },
7418
5486
  []
7419
5487
  );
5488
+ const getHasBranchesSnapshot = React2.useCallback(
5489
+ () => chatRef.current.hasBranches,
5490
+ []
5491
+ );
5492
+ const hasBranches = React2.useSyncExternalStore(
5493
+ chatRef.current.subscribe,
5494
+ getHasBranchesSnapshot,
5495
+ () => false
5496
+ );
5497
+ const getAllMessages = React2.useCallback(
5498
+ () => chatRef.current?.getAllMessages?.() ?? [],
5499
+ []
5500
+ );
5501
+ React2.useEffect(() => {
5502
+ if (onMessagesChange && messages.length > 0) {
5503
+ const allUIMessages = chatRef.current?.getAllMessages?.() ?? messages;
5504
+ const coreMessages = allUIMessages.map((m) => ({
5505
+ id: m.id,
5506
+ role: m.role,
5507
+ content: m.content,
5508
+ created_at: m.createdAt,
5509
+ tool_calls: m.toolCalls,
5510
+ tool_call_id: m.toolCallId,
5511
+ parent_id: m.parentId,
5512
+ children_ids: m.childrenIds,
5513
+ metadata: {
5514
+ attachments: m.attachments,
5515
+ thinking: m.thinking
5516
+ }
5517
+ }));
5518
+ onMessagesChange(coreMessages);
5519
+ }
5520
+ }, [messages, onMessagesChange]);
5521
+ React2.useEffect(() => {
5522
+ if (error && onError) {
5523
+ onError(error);
5524
+ }
5525
+ }, [error, onError]);
7420
5526
  React2.useEffect(() => {
7421
5527
  return () => {
7422
5528
  chatRef.current?.dispose();
7423
5529
  };
7424
5530
  }, []);
7425
- return {
7426
- messages,
7427
- status,
7428
- error,
7429
- isLoading,
7430
- input,
7431
- setInput,
7432
- sendMessage,
7433
- stop,
7434
- clearMessages,
7435
- setMessages,
7436
- regenerate,
7437
- continueWithToolResults,
7438
- chatRef,
7439
- // Branching
7440
- switchBranch,
7441
- getBranchInfo,
7442
- editMessage,
7443
- hasBranches
7444
- };
5531
+ const contextValue = React2.useMemo(
5532
+ () => ({
5533
+ // Chat state
5534
+ messages,
5535
+ status,
5536
+ error,
5537
+ isLoading,
5538
+ // Chat actions
5539
+ sendMessage,
5540
+ stop,
5541
+ clearMessages,
5542
+ setMessages,
5543
+ regenerate,
5544
+ // Branching
5545
+ switchBranch,
5546
+ getBranchInfo,
5547
+ editMessage,
5548
+ hasBranches,
5549
+ getAllMessages,
5550
+ // Tool execution
5551
+ registerTool,
5552
+ unregisterTool,
5553
+ registeredTools,
5554
+ toolExecutions,
5555
+ pendingApprovals,
5556
+ approveToolExecution,
5557
+ rejectToolExecution,
5558
+ agentIteration,
5559
+ // Actions
5560
+ registerAction,
5561
+ unregisterAction,
5562
+ registeredActions,
5563
+ // AI Context
5564
+ addContext,
5565
+ removeContext,
5566
+ contextChars,
5567
+ contextUsage,
5568
+ // System Prompt
5569
+ setSystemPrompt,
5570
+ // Skills
5571
+ setInlineSkills,
5572
+ // Config
5573
+ threadId,
5574
+ runtimeUrl,
5575
+ toolsConfig,
5576
+ // Headless primitives
5577
+ subscribeToStreamEvents,
5578
+ messageMeta: messageMetaStoreRef.current
5579
+ }),
5580
+ [
5581
+ messages,
5582
+ status,
5583
+ error,
5584
+ isLoading,
5585
+ sendMessage,
5586
+ stop,
5587
+ clearMessages,
5588
+ setMessages,
5589
+ regenerate,
5590
+ switchBranch,
5591
+ getBranchInfo,
5592
+ editMessage,
5593
+ hasBranches,
5594
+ getAllMessages,
5595
+ registerTool,
5596
+ unregisterTool,
5597
+ registeredTools,
5598
+ toolExecutions,
5599
+ pendingApprovals,
5600
+ approveToolExecution,
5601
+ rejectToolExecution,
5602
+ agentIteration,
5603
+ registerAction,
5604
+ unregisterAction,
5605
+ registeredActions,
5606
+ addContext,
5607
+ removeContext,
5608
+ contextChars,
5609
+ contextUsage,
5610
+ setSystemPrompt,
5611
+ setInlineSkills,
5612
+ threadId,
5613
+ runtimeUrl,
5614
+ toolsConfig
5615
+ ]
5616
+ );
5617
+ const messageHistoryContextValue = React2__default.default.useMemo(
5618
+ () => ({
5619
+ config: { ...defaultMessageHistoryConfig, ...messageHistory },
5620
+ tokenUsage: {
5621
+ current: 0,
5622
+ max: messageHistory?.maxContextTokens ?? 128e3,
5623
+ percentage: 0,
5624
+ isApproaching: false
5625
+ },
5626
+ compactionState: {
5627
+ rollingSummary: null,
5628
+ lastCompactionAt: null,
5629
+ compactionCount: 0,
5630
+ totalTokensSaved: 0,
5631
+ workingMemory: [],
5632
+ displayMessageCount: 0,
5633
+ llmMessageCount: 0
5634
+ }
5635
+ }),
5636
+ [messageHistory]
5637
+ );
5638
+ return /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryContext.Provider, { value: messageHistoryContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(CopilotContext.Provider, { value: contextValue, children: [
5639
+ mcpServers?.map((config) => /* @__PURE__ */ jsxRuntime.jsx(MCPConnection, { config }, config.name)),
5640
+ messageHistory?.strategy && messageHistory.strategy !== "none" && /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryBridge, { chatRef }),
5641
+ skills ? /* @__PURE__ */ jsxRuntime.jsx(SkillProvider, { skills, children }) : children
5642
+ ] }) });
7445
5643
  }
7446
5644
 
7447
- // src/react/skill/define-skill.ts
7448
- function defineSkill(def) {
7449
- return def;
5645
+ // src/react/hooks/useMCPTools.ts
5646
+ function useMCPTools(config) {
5647
+ const {
5648
+ prefixToolNames = true,
5649
+ autoRegister = true,
5650
+ hidden = false,
5651
+ source = "mcp",
5652
+ ...clientConfig
5653
+ } = config;
5654
+ const { registerTool, unregisterTool } = useCopilot();
5655
+ const registeredToolsRef = React2.useRef([]);
5656
+ const mcpClient = useMCPClient(clientConfig);
5657
+ const toolAdapter = React2.useMemo(
5658
+ () => new chunkJGPDQDY4_cjs.MCPToolAdapter(clientConfig.name),
5659
+ [clientConfig.name]
5660
+ );
5661
+ const toolDefinitions = React2.useMemo(() => {
5662
+ if (!mcpClient.isConnected || mcpClient.state.tools.length === 0) {
5663
+ return [];
5664
+ }
5665
+ return mcpClient.state.tools.map(
5666
+ (tool) => toolAdapter.toToolDefinition(tool, {
5667
+ prefix: prefixToolNames,
5668
+ asServerTool: true,
5669
+ // MCP tools execute remotely
5670
+ callTool: mcpClient.callTool,
5671
+ hidden,
5672
+ // Hide from chat UI
5673
+ source
5674
+ // Tool source for UI differentiation
5675
+ })
5676
+ );
5677
+ }, [
5678
+ mcpClient.isConnected,
5679
+ mcpClient.state.tools,
5680
+ mcpClient.callTool,
5681
+ toolAdapter,
5682
+ prefixToolNames,
5683
+ hidden,
5684
+ source
5685
+ ]);
5686
+ React2.useEffect(() => {
5687
+ if (!autoRegister) {
5688
+ return;
5689
+ }
5690
+ for (const toolName of registeredToolsRef.current) {
5691
+ unregisterTool(toolName);
5692
+ }
5693
+ registeredToolsRef.current = [];
5694
+ if (mcpClient.isConnected && toolDefinitions.length > 0) {
5695
+ for (const tool of toolDefinitions) {
5696
+ registerTool(tool);
5697
+ registeredToolsRef.current.push(tool.name);
5698
+ }
5699
+ }
5700
+ return () => {
5701
+ for (const toolName of registeredToolsRef.current) {
5702
+ unregisterTool(toolName);
5703
+ }
5704
+ registeredToolsRef.current = [];
5705
+ };
5706
+ }, [
5707
+ autoRegister,
5708
+ mcpClient.isConnected,
5709
+ toolDefinitions,
5710
+ registerTool,
5711
+ unregisterTool
5712
+ ]);
5713
+ return {
5714
+ ...mcpClient,
5715
+ toolDefinitions
5716
+ };
7450
5717
  }
7451
5718
 
7452
5719
  exports.AbstractAgentLoop = AbstractAgentLoop;
@@ -7454,56 +5721,25 @@ exports.AbstractChat = AbstractChat;
7454
5721
  exports.CopilotProvider = CopilotProvider;
7455
5722
  exports.MessageHistoryContext = MessageHistoryContext;
7456
5723
  exports.MessageTree = MessageTree;
7457
- exports.ReactChat = ReactChat;
7458
5724
  exports.ReactChatState = ReactChatState;
7459
- exports.ReactThreadManager = ReactThreadManager;
7460
- exports.ReactThreadManagerState = ReactThreadManagerState;
7461
5725
  exports.SkillProvider = SkillProvider;
7462
- exports.createMessageIntentHandler = createMessageIntentHandler;
7463
- exports.createPermissionStorage = createPermissionStorage;
7464
- exports.createReactChat = createReactChat;
7465
5726
  exports.createReactChatState = createReactChatState;
7466
- exports.createReactThreadManager = createReactThreadManager;
7467
- exports.createReactThreadManagerState = createReactThreadManagerState;
7468
- exports.createSessionPermissionCache = createSessionPermissionCache;
7469
- exports.createToolIntentHandler = createToolIntentHandler;
7470
5727
  exports.defaultMessageHistoryConfig = defaultMessageHistoryConfig;
7471
- exports.defineSkill = defineSkill;
7472
- exports.formatKnowledgeResultsForAI = formatKnowledgeResultsForAI;
7473
5728
  exports.initialAgentLoopState = initialAgentLoopState;
7474
5729
  exports.isCompactionMarker = isCompactionMarker;
7475
5730
  exports.keepToolPairsAtomic = keepToolPairsAtomic;
7476
- exports.searchKnowledgeBase = searchKnowledgeBase;
7477
5731
  exports.toDisplayMessage = toDisplayMessage;
7478
5732
  exports.toLLMMessage = toLLMMessage;
7479
5733
  exports.toLLMMessages = toLLMMessages;
7480
- exports.useAIAction = useAIAction;
7481
- exports.useAIActions = useAIActions;
7482
5734
  exports.useAIContext = useAIContext;
7483
5735
  exports.useAIContexts = useAIContexts;
7484
- exports.useAITools = useAITools;
7485
- exports.useAgent = useAgent;
7486
- exports.useCapabilities = useCapabilities;
7487
- exports.useChat = useChat;
7488
- exports.useContextStats = useContextStats;
7489
5736
  exports.useCopilot = useCopilot;
7490
- exports.useDevLogger = useDevLogger;
7491
- exports.useFeatureSupport = useFeatureSupport;
7492
- exports.useKnowledgeBase = useKnowledgeBase;
7493
5737
  exports.useMCPClient = useMCPClient;
7494
5738
  exports.useMCPTools = useMCPTools;
7495
- exports.useMCPUIIntents = useMCPUIIntents;
7496
5739
  exports.useMessageHistory = useMessageHistory;
7497
5740
  exports.useMessageHistoryContext = useMessageHistoryContext;
7498
- exports.useSkill = useSkill;
7499
- exports.useSkillStatus = useSkillStatus;
7500
- exports.useSuggestions = useSuggestions;
7501
- exports.useSupportedMediaTypes = useSupportedMediaTypes;
7502
- exports.useThreadManager = useThreadManager;
5741
+ exports.useSkillContext = useSkillContext;
7503
5742
  exports.useTool = useTool;
7504
- exports.useToolExecutor = useToolExecutor;
7505
- exports.useToolWithSchema = useToolWithSchema;
7506
5743
  exports.useTools = useTools;
7507
- exports.useToolsWithSchema = useToolsWithSchema;
7508
- //# sourceMappingURL=chunk-XUR3IOPX.cjs.map
7509
- //# sourceMappingURL=chunk-XUR3IOPX.cjs.map
5744
+ //# sourceMappingURL=chunk-LHLVTGIP.cjs.map
5745
+ //# sourceMappingURL=chunk-LHLVTGIP.cjs.map