@yourgpt/copilot-sdk 2.1.5-alpha.3 → 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 (106) hide show
  1. package/dist/{MessageTree-CoIt_4nB.d.cts → MessageTree-Clhiv_k2.d.ts} +5 -4
  2. package/dist/{MessageTree-CzaN9Eul.d.ts → MessageTree-Dt9qfJ55.d.cts} +5 -4
  3. package/dist/{ThreadManager-BEAECB7Y.d.ts → ThreadManager-D7KwT2FJ.d.ts} +3 -1
  4. package/dist/{ThreadManager-Cw5fwyCN.d.cts → ThreadManager-DK46fVl3.d.cts} +3 -1
  5. package/dist/{chunk-NUXLAZOE.cjs → chunk-3ZDRX7J2.cjs} +2 -2
  6. package/dist/{chunk-NUXLAZOE.cjs.map → chunk-3ZDRX7J2.cjs.map} +1 -1
  7. package/dist/{chunk-RKGRQRZU.js → chunk-533K2Z7C.js} +4 -4
  8. package/dist/{chunk-RKGRQRZU.js.map → chunk-533K2Z7C.js.map} +1 -1
  9. package/dist/chunk-5EGBIQYS.cjs +292 -0
  10. package/dist/chunk-5EGBIQYS.cjs.map +1 -0
  11. package/dist/chunk-5UGWLGFS.cjs +2039 -0
  12. package/dist/chunk-5UGWLGFS.cjs.map +1 -0
  13. package/dist/{chunk-3AONOZLY.js → chunk-AIVXGTWS.js} +2 -2
  14. package/dist/chunk-AIVXGTWS.js.map +1 -0
  15. package/dist/{chunk-LLM7AHMO.js → chunk-DDZLRCVX.js} +2 -2
  16. package/dist/{chunk-LLM7AHMO.js.map → chunk-DDZLRCVX.js.map} +1 -1
  17. package/dist/{chunk-PT2TOHG5.js → chunk-DH6EO6NW.js} +1337 -3049
  18. package/dist/chunk-DH6EO6NW.js.map +1 -0
  19. package/dist/{chunk-WIXFZUEZ.cjs → chunk-KGYDGK3U.cjs} +84 -30
  20. package/dist/chunk-KGYDGK3U.cjs.map +1 -0
  21. package/dist/{chunk-TCPAT3WG.cjs → chunk-LHLVTGIP.cjs} +1339 -3101
  22. package/dist/chunk-LHLVTGIP.cjs.map +1 -0
  23. package/dist/{chunk-TPB7XED6.cjs → chunk-TPDMBDQX.cjs} +2 -2
  24. package/dist/chunk-TPDMBDQX.cjs.map +1 -0
  25. package/dist/chunk-TXQ37MAO.js +287 -0
  26. package/dist/chunk-TXQ37MAO.js.map +1 -0
  27. package/dist/{chunk-MDS23G2S.cjs → chunk-Y2A6AMGO.cjs} +10 -10
  28. package/dist/{chunk-MDS23G2S.cjs.map → chunk-Y2A6AMGO.cjs.map} +1 -1
  29. package/dist/{chunk-WZ2TOZ7M.js → chunk-YLZCTR4O.js} +65 -11
  30. package/dist/chunk-YLZCTR4O.js.map +1 -0
  31. package/dist/chunk-ZAOTYA5L.js +1983 -0
  32. package/dist/chunk-ZAOTYA5L.js.map +1 -0
  33. package/dist/core/index.cjs +93 -93
  34. package/dist/core/index.d.cts +7 -7
  35. package/dist/core/index.d.ts +7 -7
  36. package/dist/core/index.js +5 -5
  37. package/dist/experimental/index.cjs +644 -0
  38. package/dist/experimental/index.cjs.map +1 -0
  39. package/dist/experimental/index.d.cts +924 -0
  40. package/dist/experimental/index.d.ts +924 -0
  41. package/dist/experimental/index.js +611 -0
  42. package/dist/experimental/index.js.map +1 -0
  43. package/dist/{index-D7169xuR.d.ts → index-D8zza1Q8.d.ts} +1 -1
  44. package/dist/{index-CzJB8Ddo.d.cts → index-DCVjTdIZ.d.cts} +1 -1
  45. package/dist/mcp/index.d.cts +3 -3
  46. package/dist/mcp/index.d.ts +3 -3
  47. package/dist/react/index.cjs +136 -123
  48. package/dist/react/index.d.cts +178 -12
  49. package/dist/react/index.d.ts +178 -12
  50. package/dist/react/index.js +7 -6
  51. package/dist/styles.css +45 -0
  52. package/dist/tools/anthropic/index.cjs +3 -3
  53. package/dist/tools/anthropic/index.d.cts +1 -1
  54. package/dist/tools/anthropic/index.d.ts +1 -1
  55. package/dist/tools/anthropic/index.js +2 -2
  56. package/dist/tools/brave/index.cjs +6 -6
  57. package/dist/tools/brave/index.d.cts +1 -1
  58. package/dist/tools/brave/index.d.ts +1 -1
  59. package/dist/tools/brave/index.js +3 -3
  60. package/dist/tools/exa/index.cjs +6 -6
  61. package/dist/tools/exa/index.d.cts +1 -1
  62. package/dist/tools/exa/index.d.ts +1 -1
  63. package/dist/tools/exa/index.js +3 -3
  64. package/dist/tools/google/index.cjs +6 -6
  65. package/dist/tools/google/index.d.cts +1 -1
  66. package/dist/tools/google/index.d.ts +1 -1
  67. package/dist/tools/google/index.js +4 -4
  68. package/dist/tools/openai/index.cjs +6 -6
  69. package/dist/tools/openai/index.d.cts +1 -1
  70. package/dist/tools/openai/index.d.ts +1 -1
  71. package/dist/tools/openai/index.js +3 -3
  72. package/dist/tools/searxng/index.cjs +6 -6
  73. package/dist/tools/searxng/index.d.cts +1 -1
  74. package/dist/tools/searxng/index.d.ts +1 -1
  75. package/dist/tools/searxng/index.js +3 -3
  76. package/dist/tools/serper/index.cjs +6 -6
  77. package/dist/tools/serper/index.d.cts +1 -1
  78. package/dist/tools/serper/index.d.ts +1 -1
  79. package/dist/tools/serper/index.js +3 -3
  80. package/dist/tools/tavily/index.cjs +6 -6
  81. package/dist/tools/tavily/index.d.cts +1 -1
  82. package/dist/tools/tavily/index.d.ts +1 -1
  83. package/dist/tools/tavily/index.js +3 -3
  84. package/dist/tools/web-search/index.cjs +7 -7
  85. package/dist/tools/web-search/index.d.cts +2 -2
  86. package/dist/tools/web-search/index.d.ts +2 -2
  87. package/dist/tools/web-search/index.js +4 -4
  88. package/dist/{tools-tmksfhUo.d.cts → tools-DcS6Aeao.d.cts} +7 -3
  89. package/dist/{tools-tmksfhUo.d.ts → tools-DcS6Aeao.d.ts} +7 -3
  90. package/dist/{types-BqwW3Baj.d.ts → types-BUYni9B8.d.ts} +1 -1
  91. package/dist/{types-BLw7mxtW.d.cts → types-Cvg4DUoc.d.cts} +1 -1
  92. package/dist/{types-BeFBBZ5i.d.ts → types-waEqyE4K.d.cts} +5 -0
  93. package/dist/{types-BeFBBZ5i.d.cts → types-waEqyE4K.d.ts} +5 -0
  94. package/dist/ui/index.cjs +354 -524
  95. package/dist/ui/index.cjs.map +1 -1
  96. package/dist/ui/index.d.cts +22 -4
  97. package/dist/ui/index.d.ts +22 -4
  98. package/dist/ui/index.js +197 -372
  99. package/dist/ui/index.js.map +1 -1
  100. package/package.json +6 -1
  101. package/dist/chunk-3AONOZLY.js.map +0 -1
  102. package/dist/chunk-PT2TOHG5.js.map +0 -1
  103. package/dist/chunk-TCPAT3WG.cjs.map +0 -1
  104. package/dist/chunk-TPB7XED6.cjs.map +0 -1
  105. package/dist/chunk-WIXFZUEZ.cjs.map +0 -1
  106. package/dist/chunk-WZ2TOZ7M.js.map +0 -1
@@ -1,34 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var chunkWIXFZUEZ_cjs = require('./chunk-WIXFZUEZ.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 = chunkWIXFZUEZ_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
- chunkWIXFZUEZ_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 chunkWIXFZUEZ_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
- chunkWIXFZUEZ_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();
@@ -5238,7 +5271,9 @@ function CopilotProvider({
5238
5271
  createdAt: m.created_at ?? /* @__PURE__ */ new Date(),
5239
5272
  attachments: m.metadata?.attachments,
5240
5273
  toolCalls: m.tool_calls,
5241
- toolCallId: m.tool_call_id
5274
+ toolCallId: m.tool_call_id,
5275
+ parentId: m.parent_id,
5276
+ childrenIds: m.children_ids
5242
5277
  })
5243
5278
  );
5244
5279
  chatRef.current = new ReactChatWithTools(
@@ -5259,6 +5294,7 @@ function CopilotProvider({
5259
5294
  onToolExecutionsChange: (executions) => {
5260
5295
  debugLog("Tool executions changed:", executions.length);
5261
5296
  setToolExecutions(executions);
5297
+ setAgentIteration(chatRef.current?.iteration ?? 0);
5262
5298
  },
5263
5299
  onApprovalRequired: (execution) => {
5264
5300
  debugLog("Tool approval required:", execution.name);
@@ -5268,6 +5304,13 @@ function CopilotProvider({
5268
5304
  },
5269
5305
  onError: (error2) => {
5270
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
+ }
5271
5314
  }
5272
5315
  }
5273
5316
  );
@@ -5321,8 +5364,8 @@ function CopilotProvider({
5321
5364
  );
5322
5365
  const error = errorFromChat ?? null;
5323
5366
  const isLoading = status === "streaming" || status === "submitted";
5324
- const registerTool = React2.useCallback((tool2) => {
5325
- chatRef.current?.registerTool(tool2);
5367
+ const registerTool = React2.useCallback((tool) => {
5368
+ chatRef.current?.registerTool(tool);
5326
5369
  }, []);
5327
5370
  const unregisterTool = React2.useCallback((name) => {
5328
5371
  chatRef.current?.unregisterTool(name);
@@ -5379,2005 +5422,41 @@ function CopilotProvider({
5379
5422
  chatRef.current?.setContext(contextString);
5380
5423
  setContextChars(contextString.length);
5381
5424
  debugLog("Context added:", id);
5382
- return id;
5383
- },
5384
- [debugLog]
5385
- );
5386
- const removeContext = React2.useCallback(
5387
- (id) => {
5388
- contextTreeRef.current = removeNode(contextTreeRef.current, id);
5389
- const contextString = printTree(contextTreeRef.current);
5390
- chatRef.current?.setContext(contextString);
5391
- setContextChars(contextString.length);
5392
- debugLog("Context removed:", id);
5393
- },
5394
- [debugLog]
5395
- );
5396
- const setSystemPrompt = React2.useCallback(
5397
- (prompt) => {
5398
- chatRef.current?.setSystemPrompt(prompt);
5399
- debugLog("System prompt updated via function");
5400
- },
5401
- [debugLog]
5402
- );
5403
- const setInlineSkills = React2.useCallback(
5404
- (skills2) => {
5405
- chatRef.current?.setInlineSkills(skills2);
5406
- debugLog("Inline skills updated", { count: skills2.length });
5407
- },
5408
- [debugLog]
5409
- );
5410
- const sendMessage = React2.useCallback(
5411
- async (content, attachments) => {
5412
- debugLog("Sending message:", content);
5413
- await chatRef.current?.sendMessage(content, attachments);
5414
- },
5415
- [debugLog]
5416
- );
5417
- const stop = React2.useCallback(() => {
5418
- chatRef.current?.stop();
5419
- }, []);
5420
- const clearMessages = React2.useCallback(() => {
5421
- chatRef.current?.clearMessages();
5422
- }, []);
5423
- const setMessages = React2.useCallback((messages2) => {
5424
- chatRef.current?.setMessages(messages2);
5425
- }, []);
5426
- const regenerate = React2.useCallback(async (messageId) => {
5427
- await chatRef.current?.regenerate(messageId);
5428
- }, []);
5429
- const switchBranch = React2.useCallback((messageId) => {
5430
- chatRef.current?.switchBranch(messageId);
5431
- }, []);
5432
- const getBranchInfo = React2.useCallback(
5433
- (messageId) => chatRef.current?.getBranchInfo(messageId) ?? null,
5434
- []
5435
- );
5436
- const editMessage = React2.useCallback(
5437
- async (messageId, newContent) => {
5438
- await chatRef.current?.sendMessage(newContent, void 0, {
5439
- editMessageId: messageId
5440
- });
5441
- },
5442
- []
5443
- );
5444
- const getHasBranchesSnapshot = React2.useCallback(
5445
- () => chatRef.current.hasBranches,
5446
- []
5447
- );
5448
- const hasBranches = React2.useSyncExternalStore(
5449
- chatRef.current.subscribe,
5450
- getHasBranchesSnapshot,
5451
- () => false
5452
- );
5453
- const getAllMessages = React2.useCallback(
5454
- () => chatRef.current?.getAllMessages?.() ?? [],
5455
- []
5456
- );
5457
- React2.useEffect(() => {
5458
- if (onMessagesChange && messages.length > 0) {
5459
- const allUIMessages = chatRef.current?.getAllMessages?.() ?? messages;
5460
- const coreMessages = allUIMessages.map((m) => ({
5461
- id: m.id,
5462
- role: m.role,
5463
- content: m.content,
5464
- created_at: m.createdAt,
5465
- tool_calls: m.toolCalls,
5466
- tool_call_id: m.toolCallId,
5467
- parent_id: m.parentId,
5468
- children_ids: m.childrenIds,
5469
- metadata: {
5470
- attachments: m.attachments,
5471
- thinking: m.thinking
5472
- }
5473
- }));
5474
- onMessagesChange(coreMessages);
5475
- }
5476
- }, [messages, onMessagesChange]);
5477
- React2.useEffect(() => {
5478
- if (error && onError) {
5479
- onError(error);
5480
- }
5481
- }, [error, onError]);
5482
- React2.useEffect(() => {
5483
- return () => {
5484
- chatRef.current?.dispose();
5485
- };
5486
- }, []);
5487
- const contextValue = React2.useMemo(
5488
- () => ({
5489
- // Chat state
5490
- messages,
5491
- status,
5492
- error,
5493
- isLoading,
5494
- // Chat actions
5495
- sendMessage,
5496
- stop,
5497
- clearMessages,
5498
- setMessages,
5499
- regenerate,
5500
- // Branching
5501
- switchBranch,
5502
- getBranchInfo,
5503
- editMessage,
5504
- hasBranches,
5505
- getAllMessages,
5506
- // Tool execution
5507
- registerTool,
5508
- unregisterTool,
5509
- registeredTools,
5510
- toolExecutions,
5511
- pendingApprovals,
5512
- approveToolExecution,
5513
- rejectToolExecution,
5514
- // Actions
5515
- registerAction,
5516
- unregisterAction,
5517
- registeredActions,
5518
- // AI Context
5519
- addContext,
5520
- removeContext,
5521
- contextChars,
5522
- contextUsage,
5523
- // System Prompt
5524
- setSystemPrompt,
5525
- // Skills
5526
- setInlineSkills,
5527
- // Config
5528
- threadId,
5529
- runtimeUrl,
5530
- toolsConfig
5531
- }),
5532
- [
5533
- messages,
5534
- status,
5535
- error,
5536
- isLoading,
5537
- sendMessage,
5538
- stop,
5539
- clearMessages,
5540
- setMessages,
5541
- regenerate,
5542
- switchBranch,
5543
- getBranchInfo,
5544
- editMessage,
5545
- hasBranches,
5546
- getAllMessages,
5547
- registerTool,
5548
- unregisterTool,
5549
- registeredTools,
5550
- toolExecutions,
5551
- pendingApprovals,
5552
- approveToolExecution,
5553
- rejectToolExecution,
5554
- registerAction,
5555
- unregisterAction,
5556
- registeredActions,
5557
- addContext,
5558
- removeContext,
5559
- contextChars,
5560
- contextUsage,
5561
- setSystemPrompt,
5562
- setInlineSkills,
5563
- threadId,
5564
- runtimeUrl,
5565
- toolsConfig
5566
- ]
5567
- );
5568
- const messageHistoryContextValue = React2__default.default.useMemo(
5569
- () => ({
5570
- config: { ...defaultMessageHistoryConfig, ...messageHistory },
5571
- tokenUsage: {
5572
- current: 0,
5573
- max: messageHistory?.maxContextTokens ?? 128e3,
5574
- percentage: 0,
5575
- isApproaching: false
5576
- },
5577
- compactionState: {
5578
- rollingSummary: null,
5579
- lastCompactionAt: null,
5580
- compactionCount: 0,
5581
- totalTokensSaved: 0,
5582
- workingMemory: [],
5583
- displayMessageCount: 0,
5584
- llmMessageCount: 0
5585
- }
5586
- }),
5587
- [messageHistory]
5588
- );
5589
- return /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryContext.Provider, { value: messageHistoryContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(CopilotContext.Provider, { value: contextValue, children: [
5590
- mcpServers?.map((config) => /* @__PURE__ */ jsxRuntime.jsx(MCPConnection, { config }, config.name)),
5591
- messageHistory?.strategy && messageHistory.strategy !== "none" && /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryBridge, { chatRef }),
5592
- skills ? /* @__PURE__ */ jsxRuntime.jsx(SkillProvider, { skills, children }) : children
5593
- ] }) });
5594
- }
5595
- function useAIActions(actions) {
5596
- const { registerAction, unregisterAction } = useCopilot();
5597
- React2.useEffect(() => {
5598
- for (const action of actions) {
5599
- registerAction(action);
5600
- }
5601
- return () => {
5602
- for (const action of actions) {
5603
- unregisterAction(action.name);
5604
- }
5605
- };
5606
- }, [actions, registerAction, unregisterAction]);
5607
- }
5608
- function useAIAction(action) {
5609
- useAIActions([action]);
5610
- }
5611
- function useAITools(options = {}) {
5612
- const {
5613
- screenshot = false,
5614
- console: consoleCapture = false,
5615
- network = false,
5616
- requireConsent = true,
5617
- screenshotOptions,
5618
- consoleOptions,
5619
- networkOptions,
5620
- onConsentRequest,
5621
- autoStart = true
5622
- } = options;
5623
- const [isEnabled] = React2.useState(screenshot || consoleCapture || network);
5624
- const [activeCaptures, setActiveCaptures] = React2.useState({
5625
- console: false,
5626
- network: false
5627
- });
5628
- const [pendingConsent, setPendingConsent] = React2.useState(null);
5629
- const consentResolverRef = React2.useRef(null);
5630
- const rememberedConsentRef = React2.useRef(/* @__PURE__ */ new Set());
5631
- React2.useEffect(() => {
5632
- if (!autoStart || !isEnabled) return;
5633
- if (consoleCapture && !chunkWIXFZUEZ_cjs.isConsoleCaptureActive()) {
5634
- chunkWIXFZUEZ_cjs.startConsoleCapture(consoleOptions);
5635
- setActiveCaptures((prev) => ({ ...prev, console: true }));
5636
- }
5637
- if (network && !chunkWIXFZUEZ_cjs.isNetworkCaptureActive()) {
5638
- chunkWIXFZUEZ_cjs.startNetworkCapture(networkOptions);
5639
- setActiveCaptures((prev) => ({ ...prev, network: true }));
5640
- }
5641
- return () => {
5642
- chunkWIXFZUEZ_cjs.stopConsoleCapture();
5643
- chunkWIXFZUEZ_cjs.stopNetworkCapture();
5644
- };
5645
- }, [
5646
- autoStart,
5647
- isEnabled,
5648
- consoleCapture,
5649
- network,
5650
- consoleOptions,
5651
- networkOptions
5652
- ]);
5653
- const captureScreenshotFn = React2.useCallback(
5654
- async (opts) => {
5655
- if (!screenshot) {
5656
- throw new Error("Screenshot capture is not enabled");
5657
- }
5658
- if (!chunkWIXFZUEZ_cjs.isScreenshotSupported()) {
5659
- throw new Error(
5660
- "Screenshot capture is not supported in this environment"
5661
- );
5662
- }
5663
- return chunkWIXFZUEZ_cjs.captureScreenshot({ ...screenshotOptions, ...opts });
5664
- },
5665
- [screenshot, screenshotOptions]
5666
- );
5667
- const getConsoleLogsFn = React2.useCallback(
5668
- (opts) => {
5669
- if (!consoleCapture) {
5670
- return { logs: [], totalCaptured: 0 };
5671
- }
5672
- return chunkWIXFZUEZ_cjs.getConsoleLogs({ ...consoleOptions, ...opts });
5673
- },
5674
- [consoleCapture, consoleOptions]
5675
- );
5676
- const getNetworkRequestsFn = React2.useCallback(
5677
- (opts) => {
5678
- if (!network) {
5679
- return { requests: [], totalCaptured: 0 };
5680
- }
5681
- return chunkWIXFZUEZ_cjs.getNetworkRequests({ ...networkOptions, ...opts });
5682
- },
5683
- [network, networkOptions]
5684
- );
5685
- const requestConsent = React2.useCallback(
5686
- async (tools, reason = "") => {
5687
- const enabledTools = tools.filter((tool2) => {
5688
- if (tool2 === "screenshot") return screenshot;
5689
- if (tool2 === "console") return consoleCapture;
5690
- if (tool2 === "network") return network;
5691
- return false;
5692
- });
5693
- if (enabledTools.length === 0) {
5694
- return { approved: [], denied: [] };
5695
- }
5696
- if (!requireConsent) {
5697
- return { approved: enabledTools, denied: [] };
5698
- }
5699
- const needsConsent = enabledTools.filter(
5700
- (tool2) => !rememberedConsentRef.current.has(tool2)
5701
- );
5702
- if (needsConsent.length === 0) {
5703
- return { approved: enabledTools, denied: [] };
5704
- }
5705
- const request = {
5706
- tools: needsConsent,
5707
- reason,
5708
- keywords: []
5709
- };
5710
- if (onConsentRequest) {
5711
- const response = await onConsentRequest(request);
5712
- if (response.remember) {
5713
- response.approved.forEach(
5714
- (tool2) => rememberedConsentRef.current.add(tool2)
5715
- );
5716
- }
5717
- return response;
5718
- }
5719
- return new Promise((resolve) => {
5720
- setPendingConsent(request);
5721
- consentResolverRef.current = (response) => {
5722
- if (response.remember) {
5723
- response.approved.forEach(
5724
- (tool2) => rememberedConsentRef.current.add(tool2)
5725
- );
5726
- }
5727
- resolve(response);
5728
- };
5729
- });
5730
- },
5731
- [screenshot, consoleCapture, network, requireConsent, onConsentRequest]
5732
- );
5733
- const respondToConsent = React2.useCallback((response) => {
5734
- if (consentResolverRef.current) {
5735
- consentResolverRef.current(response);
5736
- consentResolverRef.current = null;
5737
- }
5738
- setPendingConsent(null);
5739
- }, []);
5740
- const captureContext = React2.useCallback(
5741
- async (tools) => {
5742
- const toolsToCapture = tools || ["screenshot", "console", "network"];
5743
- const context = {
5744
- timestamp: Date.now()
5745
- };
5746
- const captures = [];
5747
- if (toolsToCapture.includes("screenshot") && screenshot) {
5748
- captures.push(
5749
- captureScreenshotFn().then((result) => {
5750
- context.screenshot = result;
5751
- }).catch(() => {
5752
- })
5753
- );
5754
- }
5755
- if (toolsToCapture.includes("console") && consoleCapture) {
5756
- context.consoleLogs = getConsoleLogsFn();
5757
- }
5758
- if (toolsToCapture.includes("network") && network) {
5759
- context.networkRequests = getNetworkRequestsFn();
5760
- }
5761
- await Promise.all(captures);
5762
- return context;
5763
- },
5764
- [
5765
- screenshot,
5766
- consoleCapture,
5767
- network,
5768
- captureScreenshotFn,
5769
- getConsoleLogsFn,
5770
- getNetworkRequestsFn
5771
- ]
5772
- );
5773
- const startCapturing = React2.useCallback(() => {
5774
- if (consoleCapture && !chunkWIXFZUEZ_cjs.isConsoleCaptureActive()) {
5775
- chunkWIXFZUEZ_cjs.startConsoleCapture(consoleOptions);
5776
- setActiveCaptures((prev) => ({ ...prev, console: true }));
5777
- }
5778
- if (network && !chunkWIXFZUEZ_cjs.isNetworkCaptureActive()) {
5779
- chunkWIXFZUEZ_cjs.startNetworkCapture(networkOptions);
5780
- setActiveCaptures((prev) => ({ ...prev, network: true }));
5781
- }
5782
- }, [consoleCapture, network, consoleOptions, networkOptions]);
5783
- const stopCapturing = React2.useCallback(() => {
5784
- chunkWIXFZUEZ_cjs.stopConsoleCapture();
5785
- chunkWIXFZUEZ_cjs.stopNetworkCapture();
5786
- setActiveCaptures({ console: false, network: false });
5787
- }, []);
5788
- const clearCaptured = React2.useCallback(() => {
5789
- chunkWIXFZUEZ_cjs.clearConsoleLogs();
5790
- chunkWIXFZUEZ_cjs.clearNetworkRequests();
5791
- }, []);
5792
- const formatForAI = React2.useCallback((context) => {
5793
- const parts = [];
5794
- if (context.screenshot) {
5795
- parts.push(
5796
- `Screenshot captured (${context.screenshot.width}x${context.screenshot.height}, ${context.screenshot.format})`
5797
- );
5798
- }
5799
- if (context.consoleLogs && context.consoleLogs.logs.length > 0) {
5800
- parts.push(chunkWIXFZUEZ_cjs.formatLogsForAI(context.consoleLogs.logs));
5801
- }
5802
- if (context.networkRequests && context.networkRequests.requests.length > 0) {
5803
- parts.push(chunkWIXFZUEZ_cjs.formatRequestsForAI(context.networkRequests.requests));
5804
- }
5805
- return parts.length > 0 ? parts.join("\n\n---\n\n") : "No context captured.";
5806
- }, []);
5807
- const detectIntentFn = React2.useCallback(
5808
- (message) => {
5809
- const result = chunkWIXFZUEZ_cjs.detectIntent(message);
5810
- result.suggestedTools = result.suggestedTools.filter((tool2) => {
5811
- if (tool2 === "screenshot") return screenshot;
5812
- if (tool2 === "console") return consoleCapture;
5813
- if (tool2 === "network") return network;
5814
- return false;
5815
- });
5816
- return result;
5817
- },
5818
- [screenshot, consoleCapture, network]
5819
- );
5820
- return React2.useMemo(
5821
- () => ({
5822
- isEnabled,
5823
- activeCaptures,
5824
- captureScreenshot: captureScreenshotFn,
5825
- getConsoleLogs: getConsoleLogsFn,
5826
- getNetworkRequests: getNetworkRequestsFn,
5827
- captureContext,
5828
- detectIntent: detectIntentFn,
5829
- requestConsent,
5830
- startCapturing,
5831
- stopCapturing,
5832
- clearCaptured,
5833
- formatForAI,
5834
- pendingConsent,
5835
- respondToConsent
5836
- }),
5837
- [
5838
- isEnabled,
5839
- activeCaptures,
5840
- captureScreenshotFn,
5841
- getConsoleLogsFn,
5842
- getNetworkRequestsFn,
5843
- captureContext,
5844
- detectIntentFn,
5845
- requestConsent,
5846
- startCapturing,
5847
- stopCapturing,
5848
- clearCaptured,
5849
- formatForAI,
5850
- pendingConsent,
5851
- respondToConsent
5852
- ]
5853
- );
5854
- }
5855
- function convertZodSchema(schema, _toolName) {
5856
- try {
5857
- const zodWithJsonSchema = z__namespace;
5858
- if (typeof zodWithJsonSchema.toJSONSchema === "function") {
5859
- const jsonSchema = zodWithJsonSchema.toJSONSchema(
5860
- schema
5861
- );
5862
- if (jsonSchema.type === "object") {
5863
- return {
5864
- type: "object",
5865
- properties: jsonSchema.properties || {},
5866
- required: jsonSchema.required
5867
- };
5868
- }
5869
- }
5870
- } catch {
5871
- }
5872
- return chunkWIXFZUEZ_cjs.zodObjectToInputSchema(schema);
5873
- }
5874
- function useToolWithSchema(config, dependencies = []) {
5875
- const { registerTool, unregisterTool } = useCopilot();
5876
- const configRef = React2.useRef(config);
5877
- configRef.current = config;
5878
- const inputSchema = React2.useMemo(() => {
5879
- try {
5880
- return convertZodSchema(config.schema, config.name);
5881
- } catch (error) {
5882
- console.warn(
5883
- `[useToolWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
5884
- error
5885
- );
5886
- return {
5887
- type: "object",
5888
- properties: {}
5889
- };
5890
- }
5891
- }, [config.schema, config.name]);
5892
- React2.useEffect(() => {
5893
- const tool2 = {
5894
- name: config.name,
5895
- description: config.description,
5896
- location: "client",
5897
- inputSchema,
5898
- handler: async (params, context) => {
5899
- return configRef.current.handler(params, context);
5900
- },
5901
- render: config.render,
5902
- available: config.available ?? true
5903
- };
5904
- registerTool(tool2);
5905
- return () => {
5906
- unregisterTool(config.name);
5907
- };
5908
- }, [config.name, inputSchema, ...dependencies]);
5909
- }
5910
- function useToolsWithSchema(tools, dependencies = []) {
5911
- const { registerTool, unregisterTool } = useCopilot();
5912
- const toolsRef = React2.useRef(tools);
5913
- toolsRef.current = tools;
5914
- React2.useEffect(() => {
5915
- const toolNames = [];
5916
- for (const config of tools) {
5917
- let inputSchema;
5918
- try {
5919
- inputSchema = convertZodSchema(config.schema, config.name);
5920
- } catch (error) {
5921
- console.warn(
5922
- `[useToolsWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
5923
- error
5924
- );
5925
- inputSchema = { type: "object", properties: {} };
5926
- }
5927
- const tool2 = {
5928
- name: config.name,
5929
- description: config.description,
5930
- location: "client",
5931
- inputSchema,
5932
- handler: async (params, context) => {
5933
- const currentConfig = toolsRef.current.find(
5934
- (t) => t.name === config.name
5935
- );
5936
- if (currentConfig) {
5937
- return currentConfig.handler(params, context);
5938
- }
5939
- return { success: false, error: "Tool handler not found" };
5940
- },
5941
- available: config.available ?? true
5942
- };
5943
- registerTool(tool2);
5944
- toolNames.push(config.name);
5945
- }
5946
- return () => {
5947
- for (const name of toolNames) {
5948
- unregisterTool(name);
5949
- }
5950
- };
5951
- }, [tools.map((t) => t.name).join(","), ...dependencies]);
5952
- }
5953
- var CopilotContext2 = React2.createContext(null);
5954
- function useCopilotContext() {
5955
- const context = React2.useContext(CopilotContext2);
5956
- if (!context) {
5957
- throw new Error("useCopilotContext must be used within a CopilotProvider");
5958
- }
5959
- return context;
5960
- }
5961
-
5962
- // src/react/hooks/useToolExecutor.ts
5963
- function useToolExecutor() {
5964
- const {
5965
- registeredTools,
5966
- config,
5967
- chat,
5968
- addToolExecution,
5969
- updateToolExecution
5970
- } = useCopilotContext();
5971
- const toolsRef = React2.useRef(registeredTools);
5972
- toolsRef.current = registeredTools;
5973
- const executeTool = React2.useCallback(
5974
- async (toolCall) => {
5975
- const tool2 = toolsRef.current.find((t) => t.name === toolCall.name);
5976
- if (!tool2) {
5977
- return {
5978
- success: false,
5979
- error: `Unknown tool: ${toolCall.name}`
5980
- };
5981
- }
5982
- if (!tool2.handler) {
5983
- return {
5984
- success: false,
5985
- error: `Tool "${toolCall.name}" has no handler`
5986
- };
5987
- }
5988
- const execution = {
5989
- id: toolCall.id,
5990
- name: toolCall.name,
5991
- args: toolCall.input,
5992
- status: "executing",
5993
- timestamp: Date.now(),
5994
- approvalStatus: "none",
5995
- hidden: tool2.hidden
5996
- };
5997
- addToolExecution?.(execution);
5998
- try {
5999
- const startTime = Date.now();
6000
- const result = await tool2.handler(toolCall.input);
6001
- const duration = Date.now() - startTime;
6002
- updateToolExecution?.(toolCall.id, {
6003
- status: result.success ? "completed" : "error",
6004
- result,
6005
- error: result.error,
6006
- duration
6007
- });
6008
- return result;
6009
- } catch (error) {
6010
- const errorMessage = error instanceof Error ? error.message : "Tool execution failed";
6011
- updateToolExecution?.(toolCall.id, {
6012
- status: "error",
6013
- error: errorMessage
6014
- });
6015
- return {
6016
- success: false,
6017
- error: errorMessage
6018
- };
6019
- }
6020
- },
6021
- [addToolExecution, updateToolExecution]
6022
- );
6023
- const sendToolResult = React2.useCallback(
6024
- async (toolCallId, result) => {
6025
- const runtimeUrl = config.runtimeUrl || config.cloud?.endpoint;
6026
- if (!runtimeUrl) {
6027
- console.warn(
6028
- "[useToolExecutor] No runtime URL configured, cannot send tool result"
6029
- );
6030
- return;
6031
- }
6032
- const baseUrl = runtimeUrl.replace(/\/chat\/?$/, "");
6033
- try {
6034
- const response = await fetch(`${baseUrl}/tool-result`, {
6035
- method: "POST",
6036
- headers: {
6037
- "Content-Type": "application/json"
6038
- },
6039
- body: JSON.stringify({
6040
- threadId: chat.threadId || "default",
6041
- toolCallId,
6042
- result
6043
- })
6044
- });
6045
- if (!response.ok) {
6046
- console.error(
6047
- "[useToolExecutor] Failed to send tool result:",
6048
- await response.text()
6049
- );
6050
- }
6051
- } catch (error) {
6052
- console.error("[useToolExecutor] Error sending tool result:", error);
6053
- }
6054
- },
6055
- [config.runtimeUrl, config.cloud?.endpoint, chat.threadId]
6056
- );
6057
- const getTool = React2.useCallback((name) => {
6058
- return toolsRef.current.find((t) => t.name === name);
6059
- }, []);
6060
- const hasTool = React2.useCallback((name) => {
6061
- return toolsRef.current.some((t) => t.name === name);
6062
- }, []);
6063
- return {
6064
- executeTool,
6065
- sendToolResult,
6066
- getTool,
6067
- hasTool
6068
- };
6069
- }
6070
- function useSuggestions(options = {}) {
6071
- const {
6072
- count = 3,
6073
- context,
6074
- suggestions: staticSuggestions,
6075
- autoRefresh = true
6076
- } = options;
6077
- const { chat, actions, config } = useCopilotContext();
6078
- const [suggestions, setSuggestions] = React2.useState([]);
6079
- const [isLoading, setIsLoading] = React2.useState(false);
6080
- const normalizedStatic = React2.useMemo(
6081
- () => staticSuggestions?.map((s) => typeof s === "string" ? { text: s } : s),
6082
- [staticSuggestions]
6083
- );
6084
- const refresh = React2.useCallback(async () => {
6085
- if (normalizedStatic) {
6086
- setSuggestions(normalizedStatic.slice(0, count));
6087
- return;
6088
- }
6089
- if (!config.cloud) {
6090
- return;
6091
- }
6092
- setIsLoading(true);
6093
- try {
6094
- const endpoint = config.cloud.endpoint || "https://api.yourgpt.ai/v1";
6095
- const response = await fetch(`${endpoint}/suggestions`, {
6096
- method: "POST",
6097
- headers: {
6098
- "Content-Type": "application/json",
6099
- Authorization: `Bearer ${config.cloud.apiKey}`
6100
- },
6101
- body: JSON.stringify({
6102
- botId: config.cloud.botId,
6103
- count,
6104
- context,
6105
- messages: chat.messages.slice(-5)
6106
- // Last 5 messages for context
6107
- })
6108
- });
6109
- if (response.ok) {
6110
- const data = await response.json();
6111
- setSuggestions(
6112
- data.suggestions.map(
6113
- (s) => typeof s === "string" ? { text: s } : s
6114
- )
6115
- );
6116
- }
6117
- } catch (error) {
6118
- console.error("Failed to fetch suggestions:", error);
6119
- } finally {
6120
- setIsLoading(false);
6121
- }
6122
- }, [config.cloud, count, context, chat.messages, normalizedStatic]);
6123
- const select = React2.useCallback(
6124
- (suggestion) => {
6125
- const text = typeof suggestion === "string" ? suggestion : suggestion.text;
6126
- actions.sendMessage(text);
6127
- },
6128
- [actions]
6129
- );
6130
- React2.useEffect(() => {
6131
- if (autoRefresh && chat.messages.length === 0) {
6132
- refresh();
6133
- }
6134
- }, [autoRefresh, chat.messages.length, refresh]);
6135
- return {
6136
- suggestions: normalizedStatic?.slice(0, count) || suggestions,
6137
- isLoading,
6138
- refresh,
6139
- select
6140
- };
6141
- }
6142
- function useAgent(options) {
6143
- const { name, initialState = {}, onStateChange } = options;
6144
- const { config } = useCopilotContext();
6145
- const [state, setStateInternal] = React2.useState(initialState);
6146
- const [isRunning, setIsRunning] = React2.useState(false);
6147
- const [nodeName, setNodeName] = React2.useState(null);
6148
- const [error, setError] = React2.useState(null);
6149
- const abortControllerRef = React2.useRef(null);
6150
- const getEndpoint = React2.useCallback(() => {
6151
- if (config.cloud) {
6152
- return `${config.cloud.endpoint || "https://api.yourgpt.ai/v1"}/agents/${name}`;
6153
- }
6154
- return `${config.runtimeUrl || "/api"}/agents/${name}`;
6155
- }, [config, name]);
6156
- const start = React2.useCallback(
6157
- async (input) => {
6158
- setIsRunning(true);
6159
- setError(null);
6160
- abortControllerRef.current = new AbortController();
6161
- try {
6162
- const endpoint = getEndpoint();
6163
- const headers = {
6164
- "Content-Type": "application/json"
6165
- };
6166
- if (config.cloud?.apiKey) {
6167
- headers["Authorization"] = `Bearer ${config.cloud.apiKey}`;
6168
- }
6169
- const response = await fetch(`${endpoint}/start`, {
6170
- method: "POST",
6171
- headers,
6172
- body: JSON.stringify({
6173
- input: typeof input === "string" ? { message: input } : input,
6174
- state
6175
- }),
6176
- signal: abortControllerRef.current.signal
6177
- });
6178
- if (!response.ok) {
6179
- throw new Error(`Agent error: ${response.status}`);
6180
- }
6181
- for await (const event of chunkWIXFZUEZ_cjs.streamSSE(response)) {
6182
- handleAgentEvent(event);
6183
- }
6184
- } catch (err) {
6185
- if (err.name !== "AbortError") {
6186
- setError(err instanceof Error ? err : new Error("Unknown error"));
6187
- }
6188
- } finally {
6189
- setIsRunning(false);
6190
- abortControllerRef.current = null;
6191
- }
6192
- },
6193
- [config, getEndpoint, state]
6194
- );
6195
- const handleAgentEvent = React2.useCallback(
6196
- (event) => {
6197
- if (event.type === "error") {
6198
- setError(new Error(event.message));
6199
- return;
6200
- }
6201
- if ("state" in event && event.state) {
6202
- setStateInternal(event.state);
6203
- onStateChange?.(event.state);
6204
- }
6205
- if ("nodeName" in event && event.nodeName) {
6206
- setNodeName(event.nodeName);
6207
- }
6208
- },
6209
- [onStateChange]
6210
- );
6211
- const stop = React2.useCallback(() => {
6212
- abortControllerRef.current?.abort();
6213
- }, []);
6214
- const setState = React2.useCallback(
6215
- (partialState) => {
6216
- setStateInternal((prev) => {
6217
- const newState = { ...prev, ...partialState };
6218
- onStateChange?.(newState);
6219
- return newState;
6220
- });
6221
- },
6222
- [onStateChange]
6223
- );
6224
- React2.useEffect(() => {
6225
- return () => {
6226
- abortControllerRef.current?.abort();
6227
- };
6228
- }, []);
6229
- return {
6230
- state,
6231
- isRunning,
6232
- nodeName,
6233
- start,
6234
- stop,
6235
- setState,
6236
- error
6237
- };
6238
- }
6239
-
6240
- // src/react/utils/knowledge-base.ts
6241
- var KNOWLEDGE_BASE_API = "https://api.yourgpt.ai/chatbot/v1/searchIndexDocument";
6242
- async function searchKnowledgeBase(query, config) {
6243
- try {
6244
- const response = await fetch(KNOWLEDGE_BASE_API, {
6245
- method: "POST",
6246
- headers: {
6247
- accept: "*/*",
6248
- "content-type": "application/json",
6249
- authorization: `Bearer ${config.token}`
6250
- },
6251
- body: JSON.stringify({
6252
- project_uid: config.projectUid,
6253
- query,
6254
- page: 1,
6255
- limit: String(config.limit || 10),
6256
- app_id: config.appId || "1"
6257
- })
6258
- });
6259
- if (!response.ok) {
6260
- return {
6261
- success: false,
6262
- results: [],
6263
- error: `API error: ${response.status} ${response.statusText}`
6264
- };
6265
- }
6266
- const data = await response.json();
6267
- const results = (data.data || data.results || []).map((item) => ({
6268
- id: item.id || item._id || String(Math.random()),
6269
- title: item.title || item.name || void 0,
6270
- content: item.content || item.text || item.snippet || "",
6271
- score: item.score || item.relevance || void 0,
6272
- url: item.url || item.source_url || void 0,
6273
- metadata: item.metadata || {}
6274
- }));
6275
- return {
6276
- success: true,
6277
- results,
6278
- total: data.total || results.length,
6279
- page: data.page || 1
6280
- };
6281
- } catch (error) {
6282
- return {
6283
- success: false,
6284
- results: [],
6285
- error: error instanceof Error ? error.message : "Unknown error"
6286
- };
6287
- }
6288
- }
6289
- function formatKnowledgeResultsForAI(results) {
6290
- if (results.length === 0) {
6291
- return "No relevant documents found in the knowledge base.";
6292
- }
6293
- return results.map((result, index) => {
6294
- const parts = [`[${index + 1}]`];
6295
- if (result.title) parts.push(`**${result.title}**`);
6296
- parts.push(result.content);
6297
- if (result.url) parts.push(`Source: ${result.url}`);
6298
- return parts.join("\n");
6299
- }).join("\n\n---\n\n");
6300
- }
6301
-
6302
- // src/react/hooks/useKnowledgeBase.ts
6303
- function useKnowledgeBase(config) {
6304
- const { registerTool, unregisterTool } = useCopilot();
6305
- const configRef = React2.useRef(config);
6306
- configRef.current = config;
6307
- const handleSearch = React2.useCallback(
6308
- async (params) => {
6309
- const query = params.query;
6310
- if (!query) {
6311
- return {
6312
- success: false,
6313
- error: "Query is required"
6314
- };
6315
- }
6316
- const currentConfig = configRef.current;
6317
- const kbConfig = {
6318
- projectUid: currentConfig.projectUid,
6319
- token: currentConfig.token,
6320
- appId: currentConfig.appId,
6321
- limit: currentConfig.limit || 5
6322
- };
6323
- const response = await searchKnowledgeBase(
6324
- query,
6325
- kbConfig
6326
- );
6327
- if (!response.success) {
6328
- return {
6329
- success: false,
6330
- error: response.error || "Knowledge base search failed"
6331
- };
6332
- }
6333
- const formattedResults = formatKnowledgeResultsForAI(response.results);
6334
- return {
6335
- success: true,
6336
- message: formattedResults,
6337
- data: {
6338
- resultCount: response.results.length,
6339
- total: response.total
6340
- }
6341
- };
6342
- },
6343
- []
6344
- );
6345
- React2.useEffect(() => {
6346
- if (config.enabled === false) {
6347
- return;
6348
- }
6349
- registerTool({
6350
- name: "search_knowledge",
6351
- 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.",
6352
- location: "client",
6353
- inputSchema: {
6354
- type: "object",
6355
- properties: {
6356
- query: {
6357
- type: "string",
6358
- description: "The search query to find relevant information in the knowledge base"
6359
- }
6360
- },
6361
- required: ["query"]
6362
- },
6363
- handler: handleSearch
6364
- });
6365
- return () => {
6366
- unregisterTool("search_knowledge");
6367
- };
6368
- }, [
6369
- config.enabled,
6370
- config.projectUid,
6371
- config.token,
6372
- registerTool,
6373
- unregisterTool,
6374
- handleSearch
6375
- ]);
6376
- }
6377
- var DEFAULT_CAPABILITIES = {
6378
- supportsVision: false,
6379
- supportsTools: true,
6380
- supportsThinking: false,
6381
- supportsStreaming: true,
6382
- supportsPDF: false,
6383
- supportsAudio: false,
6384
- supportsVideo: false,
6385
- maxTokens: 8192,
6386
- supportedImageTypes: [],
6387
- supportsJsonMode: false,
6388
- supportsSystemMessages: true
6389
- };
6390
- function useCapabilities() {
6391
- const { config } = useCopilotContext();
6392
- const [capabilities, setCapabilities] = React2.useState(DEFAULT_CAPABILITIES);
6393
- const [provider, setProvider] = React2.useState("unknown");
6394
- const [model, setModel] = React2.useState("unknown");
6395
- const [supportedModels, setSupportedModels] = React2.useState([]);
6396
- const [isLoading, setIsLoading] = React2.useState(true);
6397
- const [error, setError] = React2.useState(null);
6398
- const capabilitiesUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/chat\/?$/, "/capabilities") : null;
6399
- const fetchCapabilities = React2.useCallback(async () => {
6400
- if (!capabilitiesUrl) {
6401
- setIsLoading(false);
6402
- return;
6403
- }
6404
- try {
6405
- setIsLoading(true);
6406
- setError(null);
6407
- const response = await fetch(capabilitiesUrl);
6408
- if (!response.ok) {
6409
- throw new Error(`Failed to fetch capabilities: ${response.status}`);
6410
- }
6411
- const data = await response.json();
6412
- setCapabilities(data.capabilities);
6413
- setProvider(data.provider);
6414
- setModel(data.model);
6415
- setSupportedModels(data.supportedModels);
6416
- } catch (err) {
6417
- setError(err instanceof Error ? err : new Error("Unknown error"));
6418
- } finally {
6419
- setIsLoading(false);
6420
- }
6421
- }, [capabilitiesUrl]);
6422
- React2.useEffect(() => {
6423
- fetchCapabilities();
6424
- }, [fetchCapabilities]);
6425
- return {
6426
- /** Current model capabilities */
6427
- capabilities,
6428
- /** Current provider name */
6429
- provider,
6430
- /** Current model ID */
6431
- model,
6432
- /** List of supported models for current provider */
6433
- supportedModels,
6434
- /** Whether capabilities are being loaded */
6435
- isLoading,
6436
- /** Error if fetch failed */
6437
- error,
6438
- /** Refetch capabilities */
6439
- refetch: fetchCapabilities
6440
- };
6441
- }
6442
- function useFeatureSupport(feature) {
6443
- const { capabilities } = useCapabilities();
6444
- return capabilities[feature] ?? false;
6445
- }
6446
- function useSupportedMediaTypes() {
6447
- const { capabilities } = useCapabilities();
6448
- return {
6449
- /** Supported image MIME types */
6450
- imageTypes: capabilities.supportedImageTypes || [],
6451
- /** Supported audio MIME types */
6452
- audioTypes: capabilities.supportedAudioTypes || [],
6453
- /** Supported video MIME types */
6454
- videoTypes: capabilities.supportedVideoTypes || [],
6455
- /** Whether any image types are supported */
6456
- hasImageSupport: (capabilities.supportedImageTypes?.length ?? 0) > 0,
6457
- /** Whether any audio types are supported */
6458
- hasAudioSupport: (capabilities.supportedAudioTypes?.length ?? 0) > 0,
6459
- /** Whether any video types are supported */
6460
- hasVideoSupport: (capabilities.supportedVideoTypes?.length ?? 0) > 0
6461
- };
6462
- }
6463
- function useDevLogger() {
6464
- const ctx = useCopilotContext();
6465
- return React2.useMemo(() => {
6466
- const toolExecutions = (ctx.agentLoop?.toolExecutions || []).map(
6467
- (exec) => ({
6468
- id: exec.id,
6469
- name: exec.name,
6470
- status: exec.status,
6471
- approvalStatus: exec.approvalStatus || "not_required"
6472
- })
6473
- );
6474
- const pendingApprovalsCount = ctx.pendingApprovals?.length || 0;
6475
- const registeredTools = (ctx.registeredTools || []).map((tool2) => ({
6476
- name: tool2.name,
6477
- location: tool2.location || "client"
6478
- }));
6479
- const registeredActions = (ctx.registeredActions || []).map((action) => ({
6480
- name: action.name
6481
- }));
6482
- const storedPermissions = (ctx.storedPermissions || []).map((p) => ({
6483
- toolName: p.toolName,
6484
- level: p.level
6485
- }));
6486
- return {
6487
- chat: {
6488
- isLoading: ctx.chat?.isLoading || false,
6489
- messageCount: ctx.chat?.messages?.length || 0,
6490
- threadId: ctx.chat?.threadId || "none",
6491
- error: ctx.chat?.error?.message || null
6492
- },
6493
- tools: {
6494
- isEnabled: !!ctx.toolsConfig,
6495
- isCapturing: ctx.tools?.isCapturing || false,
6496
- pendingConsent: !!ctx.tools?.pendingConsent
6497
- },
6498
- agentLoop: {
6499
- toolExecutions,
6500
- pendingApprovals: pendingApprovalsCount,
6501
- iteration: ctx.agentLoop?.iteration || 0,
6502
- maxIterations: ctx.agentLoop?.maxIterations || 10
6503
- },
6504
- registered: {
6505
- tools: registeredTools,
6506
- actions: registeredActions,
6507
- contextCount: ctx.contextTree?.length || 0
6508
- },
6509
- permissions: {
6510
- stored: storedPermissions,
6511
- loaded: ctx.permissionsLoaded || false
6512
- },
6513
- config: {
6514
- runtimeUrl: ctx.config?.runtimeUrl || ctx.config?.cloud?.endpoint || ""
6515
- }
6516
- };
6517
- }, [
6518
- ctx.chat,
6519
- ctx.tools,
6520
- ctx.toolsConfig,
6521
- ctx.agentLoop,
6522
- ctx.pendingApprovals,
6523
- ctx.registeredTools,
6524
- ctx.registeredActions,
6525
- ctx.contextTree,
6526
- ctx.storedPermissions,
6527
- ctx.permissionsLoaded,
6528
- ctx.config
6529
- ]);
6530
- }
6531
-
6532
- // src/react/internal/ReactThreadManagerState.ts
6533
- var ReactThreadManagerState = class {
6534
- constructor(initialThreads) {
6535
- this._threads = [];
6536
- this._currentThreadId = null;
6537
- this._currentThread = null;
6538
- this._loadStatus = "idle";
6539
- this._error = void 0;
6540
- // Callbacks for React subscriptions (useSyncExternalStore)
6541
- this.subscribers = /* @__PURE__ */ new Set();
6542
- // ============================================
6543
- // Subscription (for useSyncExternalStore)
6544
- // ============================================
6545
- /**
6546
- * Subscribe to state changes.
6547
- * Returns an unsubscribe function.
6548
- *
6549
- * @example
6550
- * ```tsx
6551
- * const threads = useSyncExternalStore(
6552
- * state.subscribe,
6553
- * () => state.threads
6554
- * );
6555
- * ```
6556
- */
6557
- this.subscribe = (callback) => {
6558
- this.subscribers.add(callback);
6559
- return () => {
6560
- this.subscribers.delete(callback);
6561
- };
6562
- };
6563
- if (initialThreads) {
6564
- this._threads = initialThreads;
6565
- }
6566
- }
6567
- // ============================================
6568
- // Getters
6569
- // ============================================
6570
- get threads() {
6571
- return this._threads;
6572
- }
6573
- get currentThreadId() {
6574
- return this._currentThreadId;
6575
- }
6576
- get currentThread() {
6577
- return this._currentThread;
6578
- }
6579
- get loadStatus() {
6580
- return this._loadStatus;
6581
- }
6582
- get error() {
6583
- return this._error;
6584
- }
6585
- // ============================================
6586
- // Setters (trigger reactivity)
6587
- // ============================================
6588
- set threads(value) {
6589
- this._threads = value;
6590
- this.notify();
6591
- }
6592
- // ============================================
6593
- // Mutations
6594
- // ============================================
6595
- setThreads(threads) {
6596
- this._threads = threads;
6597
- this.notify();
6598
- }
6599
- setCurrentThread(thread) {
6600
- this._currentThread = thread;
6601
- this._currentThreadId = thread?.id ?? null;
6602
- this.notify();
6603
- }
6604
- setCurrentThreadId(id) {
6605
- this._currentThreadId = id;
6606
- this.notify();
6607
- }
6608
- addThread(thread) {
6609
- this._threads = [thread, ...this._threads];
6610
- this.notify();
6611
- }
6612
- updateThread(id, updates) {
6613
- this._threads = this._threads.map(
6614
- (t) => t.id === id ? { ...t, ...updates } : t
6615
- );
6616
- if (updates.updatedAt) {
6617
- this._threads = [...this._threads].sort(
6618
- (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
6619
- );
6620
- }
6621
- if (this._currentThread?.id === id) {
6622
- this._currentThread = { ...this._currentThread, ...updates };
6623
- }
6624
- this.notify();
6625
- }
6626
- removeThread(id) {
6627
- this._threads = this._threads.filter((t) => t.id !== id);
6628
- if (this._currentThreadId === id) {
6629
- this._currentThreadId = null;
6630
- this._currentThread = null;
6631
- }
6632
- this.notify();
6633
- }
6634
- setLoadStatus(status) {
6635
- this._loadStatus = status;
6636
- this.notify();
6637
- }
6638
- setError(error) {
6639
- this._error = error;
6640
- this.notify();
6641
- }
6642
- // ============================================
6643
- // Snapshots (for useSyncExternalStore)
6644
- // ============================================
6645
- getThreadsSnapshot() {
6646
- return this._threads;
6647
- }
6648
- getCurrentThreadSnapshot() {
6649
- return this._currentThread;
6650
- }
6651
- getLoadStatusSnapshot() {
6652
- return this._loadStatus;
6653
- }
6654
- getErrorSnapshot() {
6655
- return this._error;
6656
- }
6657
- // ============================================
6658
- // Private Methods
6659
- // ============================================
6660
- notify() {
6661
- this.subscribers.forEach((cb) => cb());
6662
- }
6663
- /**
6664
- * Cleanup subscriptions
6665
- */
6666
- dispose() {
6667
- this.subscribers.clear();
6668
- }
6669
- };
6670
- function createReactThreadManagerState(initialThreads) {
6671
- return new ReactThreadManagerState(initialThreads);
6672
- }
6673
-
6674
- // src/react/internal/ReactThreadManager.ts
6675
- var _ReactThreadManager = class _ReactThreadManager extends chunkWIXFZUEZ_cjs.ThreadManager {
6676
- constructor(config = {}, callbacks = {}) {
6677
- const reactState = new ReactThreadManagerState();
6678
- super({ ...config, state: reactState }, callbacks);
6679
- // ============================================
6680
- // Subscription Methods (for useSyncExternalStore)
6681
- // ============================================
6682
- /**
6683
- * Subscribe to state changes
6684
- * Use with useSyncExternalStore
6685
- */
6686
- this.subscribe = (callback) => {
6687
- return this.state.subscribe(callback);
6688
- };
6689
- // ============================================
6690
- // Snapshot Getters (for useSyncExternalStore)
6691
- // ============================================
6692
- /**
6693
- * Get threads snapshot
6694
- */
6695
- this.getThreadsSnapshot = () => {
6696
- return this.state.getThreadsSnapshot();
6697
- };
6698
- /**
6699
- * Get current thread snapshot
6700
- */
6701
- this.getCurrentThreadSnapshot = () => {
6702
- return this.state.getCurrentThreadSnapshot();
6703
- };
6704
- /**
6705
- * Get current thread ID snapshot
6706
- */
6707
- this.getCurrentThreadIdSnapshot = () => {
6708
- return this.state.currentThreadId;
6709
- };
6710
- /**
6711
- * Get load status snapshot
6712
- */
6713
- this.getLoadStatusSnapshot = () => {
6714
- return this.state.getLoadStatusSnapshot();
6715
- };
6716
- /**
6717
- * Get error snapshot
6718
- */
6719
- this.getErrorSnapshot = () => {
6720
- return this.state.getErrorSnapshot();
6721
- };
6722
- /**
6723
- * Get isLoading snapshot
6724
- */
6725
- this.getIsLoadingSnapshot = () => {
6726
- return this.state.getLoadStatusSnapshot() === "loading";
6727
- };
6728
- /**
6729
- * Get threads snapshot for server (always empty for hydration consistency)
6730
- */
6731
- this.getThreadsServerSnapshot = () => {
6732
- return _ReactThreadManager.EMPTY_THREADS;
6733
- };
6734
- /**
6735
- * Get current thread snapshot for server (always null)
6736
- */
6737
- this.getCurrentThreadServerSnapshot = () => {
6738
- return null;
6739
- };
6740
- /**
6741
- * Get current thread ID snapshot for server (always null)
6742
- */
6743
- this.getCurrentThreadIdServerSnapshot = () => {
6744
- return null;
6745
- };
6746
- /**
6747
- * Get load status snapshot for server (always "idle")
6748
- */
6749
- this.getLoadStatusServerSnapshot = () => {
6750
- return _ReactThreadManager.IDLE_STATUS;
6751
- };
6752
- /**
6753
- * Get error snapshot for server (always undefined)
6754
- */
6755
- this.getErrorServerSnapshot = () => {
6756
- return void 0;
6757
- };
6758
- /**
6759
- * Get isLoading snapshot for server (always false)
6760
- */
6761
- this.getIsLoadingServerSnapshot = () => {
6762
- return false;
6763
- };
6764
- }
6765
- // ============================================
6766
- // Cleanup
6767
- // ============================================
6768
- /**
6769
- * Dispose of the manager
6770
- */
6771
- async dispose() {
6772
- this.state.dispose();
6773
- await super.dispose();
6774
- }
6775
- };
6776
- // ============================================
6777
- // Server Snapshots (for SSR - stable cached values)
6778
- // ============================================
6779
- // Cached values for server snapshots (must be stable references)
6780
- _ReactThreadManager.EMPTY_THREADS = [];
6781
- _ReactThreadManager.IDLE_STATUS = "idle";
6782
- var ReactThreadManager = _ReactThreadManager;
6783
- function createReactThreadManager(config, callbacks) {
6784
- return new ReactThreadManager(config, callbacks);
6785
- }
6786
-
6787
- // src/react/hooks/useThreadManager.ts
6788
- var defaultManager = null;
6789
- function getDefaultManager() {
6790
- if (!defaultManager) {
6791
- defaultManager = createReactThreadManager();
6792
- }
6793
- return defaultManager;
6794
- }
6795
- var internalManager = null;
6796
- function getInternalManager(config) {
6797
- if (!internalManager) {
6798
- internalManager = createReactThreadManager(
6799
- {
6800
- adapter: config.adapter,
6801
- saveDebounce: config.saveDebounce,
6802
- autoLoad: config.autoLoad,
6803
- autoRestoreLastThread: config.autoRestoreLastThread
6804
- },
6805
- config.callbacks
6806
- );
6807
- }
6808
- return internalManager;
6809
- }
6810
- function useThreadManager(config) {
6811
- const manager = React2.useMemo(() => {
6812
- if (!config) {
6813
- return getDefaultManager();
6814
- }
6815
- if (!config.adapter) {
6816
- return getInternalManager(config);
6817
- }
6818
- return createReactThreadManager(
6819
- {
6820
- adapter: config.adapter,
6821
- saveDebounce: config.saveDebounce,
6822
- autoLoad: config.autoLoad,
6823
- autoRestoreLastThread: config.autoRestoreLastThread
6824
- },
6825
- config.callbacks
6826
- );
6827
- }, [
6828
- config?.adapter,
6829
- config?.saveDebounce,
6830
- config?.autoLoad,
6831
- config?.autoRestoreLastThread
6832
- // Note: callbacks are intentionally not in deps to avoid recreating manager
6833
- ]);
6834
- const threads = React2.useSyncExternalStore(
6835
- manager.subscribe,
6836
- manager.getThreadsSnapshot,
6837
- manager.getThreadsServerSnapshot
6838
- // SSR - always empty array
6839
- );
6840
- const currentThread = React2.useSyncExternalStore(
6841
- manager.subscribe,
6842
- manager.getCurrentThreadSnapshot,
6843
- manager.getCurrentThreadServerSnapshot
6844
- // SSR - always null
6845
- );
6846
- const currentThreadId = React2.useSyncExternalStore(
6847
- manager.subscribe,
6848
- manager.getCurrentThreadIdSnapshot,
6849
- manager.getCurrentThreadIdServerSnapshot
6850
- // SSR - always null
6851
- );
6852
- const loadStatus = React2.useSyncExternalStore(
6853
- manager.subscribe,
6854
- manager.getLoadStatusSnapshot,
6855
- manager.getLoadStatusServerSnapshot
6856
- // SSR - always "idle"
6857
- );
6858
- const error = React2.useSyncExternalStore(
6859
- manager.subscribe,
6860
- manager.getErrorSnapshot,
6861
- manager.getErrorServerSnapshot
6862
- // SSR - always undefined
6863
- );
6864
- const isLoading = React2.useSyncExternalStore(
6865
- manager.subscribe,
6866
- manager.getIsLoadingSnapshot,
6867
- manager.getIsLoadingServerSnapshot
6868
- // SSR - always false
6869
- );
6870
- React2.useEffect(() => {
6871
- return () => {
6872
- if (config?.adapter && manager !== defaultManager && manager !== internalManager) {
6873
- manager.dispose();
6874
- }
6875
- };
6876
- }, [manager, config]);
6877
- React2.useEffect(() => {
6878
- const handleBeforeUnload = () => {
6879
- if (manager.hasPendingChanges) {
6880
- manager.saveNow().catch(() => {
6881
- });
6882
- }
6883
- };
6884
- if (typeof window !== "undefined") {
6885
- window.addEventListener("beforeunload", handleBeforeUnload);
6886
- return () => {
6887
- window.removeEventListener("beforeunload", handleBeforeUnload);
6888
- };
6889
- }
6890
- }, [manager]);
6891
- const createThread = React2.useCallback(
6892
- (options) => manager.createThread(options),
6893
- [manager]
6894
- );
6895
- const switchThread = React2.useCallback(
6896
- (id) => manager.switchThread(id),
6897
- [manager]
6898
- );
6899
- const updateCurrentThread = React2.useCallback(
6900
- (updates) => manager.updateCurrentThread(updates),
6901
- [manager]
6902
- );
6903
- const deleteThread = React2.useCallback(
6904
- (id) => manager.deleteThread(id),
6905
- [manager]
6906
- );
6907
- const clearCurrentThread = React2.useCallback(
6908
- () => manager.clearCurrentThread(),
6909
- [manager]
6910
- );
6911
- const refreshThreads = React2.useCallback(() => manager.loadThreads(), [manager]);
6912
- const saveNow = React2.useCallback(() => manager.saveNow(), [manager]);
6913
- const clearAllThreads = React2.useCallback(
6914
- () => manager.clearAllThreads(),
6915
- [manager]
6916
- );
6917
- const messages = React2.useMemo(
6918
- () => currentThread?.messages ?? [],
6919
- [currentThread]
6920
- );
6921
- const setMessages = React2.useCallback(
6922
- (newMessages) => updateCurrentThread({ messages: newMessages }),
6923
- [updateCurrentThread]
6924
- );
6925
- const hasPendingChanges = manager.hasPendingChanges;
6926
- return {
6927
- // State
6928
- threads,
6929
- currentThread,
6930
- currentThreadId,
6931
- isLoading,
6932
- loadStatus,
6933
- error,
6934
- // Actions
6935
- createThread,
6936
- switchThread,
6937
- updateCurrentThread,
6938
- deleteThread,
6939
- clearCurrentThread,
6940
- refreshThreads,
6941
- saveNow,
6942
- clearAllThreads,
6943
- // Utilities
6944
- messages,
6945
- setMessages,
6946
- hasPendingChanges
6947
- };
6948
- }
6949
- function useMCPUIIntents(config = {}) {
6950
- const {
6951
- onToolCall,
6952
- onIntent,
6953
- onPrompt,
6954
- onNotify,
6955
- onLink,
6956
- requireConsent = { tool: false, link: true }
6957
- } = config;
6958
- const handleIntent = React2.useCallback(
6959
- async (intent, context) => {
6960
- switch (intent.type) {
6961
- case "tool": {
6962
- if (requireConsent.tool) ;
6963
- await onToolCall?.(intent.name, intent.arguments, context);
6964
- break;
6965
- }
6966
- case "intent": {
6967
- await onIntent?.(intent.action, intent.data, context);
6968
- break;
6969
- }
6970
- case "prompt": {
6971
- onPrompt?.(intent.text, context);
6972
- break;
6973
- }
6974
- case "notify": {
6975
- onNotify?.(intent.message, intent.level, context);
6976
- break;
6977
- }
6978
- case "link": {
6979
- const shouldContinue = onLink?.(intent.url, intent.newTab, context);
6980
- if (shouldContinue === false) {
6981
- break;
6982
- }
6983
- if (requireConsent.link) {
6984
- const isSafeUrl = intent.url.startsWith("https://") || intent.url.startsWith("http://localhost");
6985
- if (!isSafeUrl) {
6986
- console.warn(
6987
- "[MCP-UI] Blocked potentially unsafe link:",
6988
- intent.url
6989
- );
6990
- break;
6991
- }
6992
- }
6993
- if (typeof window !== "undefined") {
6994
- if (intent.newTab !== false) {
6995
- window.open(intent.url, "_blank", "noopener,noreferrer");
6996
- } else {
6997
- window.location.href = intent.url;
6998
- }
6999
- }
7000
- break;
7001
- }
7002
- default: {
7003
- console.warn(
7004
- "[MCP-UI] Unknown intent type:",
7005
- intent.type
7006
- );
7007
- }
7008
- }
7009
- },
7010
- [onToolCall, onIntent, onPrompt, onNotify, onLink, requireConsent]
7011
- );
7012
- return React2.useMemo(
7013
- () => ({
7014
- handleIntent
7015
- }),
7016
- [handleIntent]
7017
- );
7018
- }
7019
- function createMessageIntentHandler(sendMessage) {
7020
- return {
7021
- onIntent: async (action, data) => {
7022
- const dataStr = data ? ` with ${JSON.stringify(data)}` : "";
7023
- await sendMessage(`User action: ${action}${dataStr}`);
7024
- },
7025
- onPrompt: (text) => {
7026
- sendMessage(text);
7027
- },
7028
- onNotify: (message, level) => {
7029
- if (level === "error") {
7030
- sendMessage(`Error: ${message}`);
7031
- }
7032
- }
7033
- };
7034
- }
7035
- function createToolIntentHandler(callTool) {
7036
- return {
7037
- onToolCall: async (name, args) => {
7038
- await callTool(name, args);
7039
- }
7040
- };
7041
- }
7042
- function getLastResponseUsage(messages) {
7043
- for (let i = messages.length - 1; i >= 0; i--) {
7044
- const msg = messages[i];
7045
- if (msg.role === "assistant" && msg.metadata?.usage) {
7046
- const u = msg.metadata.usage;
7047
- const prompt = u.prompt_tokens ?? 0;
7048
- const completion = u.completion_tokens ?? 0;
7049
- return {
7050
- prompt_tokens: prompt,
7051
- completion_tokens: completion,
7052
- total_tokens: u.total_tokens ?? prompt + completion
7053
- };
7054
- }
7055
- }
7056
- return null;
7057
- }
7058
- function useContextStats() {
7059
- const { contextChars, contextUsage, registeredTools, messages } = useCopilot();
7060
- const toolCount = React2.useMemo(() => registeredTools.length, [registeredTools]);
7061
- const messageCount = React2.useMemo(
7062
- () => messages.filter((m) => m.role !== "system").length,
7063
- [messages]
7064
- );
7065
- const totalTokens = React2.useMemo(() => {
7066
- if (contextUsage) return contextUsage.total.tokens;
7067
- return Math.ceil(contextChars / 3.5);
7068
- }, [contextUsage, contextChars]);
7069
- const usagePercent = React2.useMemo(() => {
7070
- if (contextUsage) return contextUsage.total.percent;
7071
- return 0;
7072
- }, [contextUsage]);
7073
- const lastResponseUsage = React2.useMemo(
7074
- () => getLastResponseUsage(messages),
7075
- [messages]
7076
- );
7077
- return {
7078
- contextUsage,
7079
- totalTokens,
7080
- usagePercent,
7081
- contextChars,
7082
- toolCount,
7083
- messageCount,
7084
- lastResponseUsage
7085
- };
7086
- }
7087
- var DEV_CONTENT_WARN_THRESHOLD = 2e3;
7088
- function useSkill(skill) {
7089
- const { register, unregister } = useSkillContext();
7090
- if (process.env.NODE_ENV !== "production" && skill.source.type === "inline" && skill.source.content.length > DEV_CONTENT_WARN_THRESHOLD) {
7091
- console.warn(
7092
- `[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.`
7093
- );
7094
- }
7095
- React2.useEffect(() => {
7096
- if (skill.source.type !== "inline") {
7097
- console.warn(
7098
- `[copilot-sdk/skills] useSkill only supports inline skills client-side. Skill "${skill.name}" has source type "${skill.source.type}" and will be skipped.`
7099
- );
7100
- return;
7101
- }
7102
- const resolved = {
7103
- ...skill,
7104
- content: skill.source.content
7105
- };
7106
- register(resolved);
7107
- return () => {
7108
- unregister(skill.name);
7109
- };
7110
- }, [
7111
- skill.name,
7112
- skill.source.type === "inline" ? skill.source.content : "",
7113
- skill.strategy,
7114
- skill.description
7115
- ]);
7116
- }
7117
- function useSkillStatus() {
7118
- const { skills, registry } = useSkillContext();
7119
- const has = React2.useCallback(
7120
- (name) => registry.has(name),
7121
- // eslint-disable-next-line react-hooks/exhaustive-deps
7122
- [skills]
7123
- );
7124
- return {
7125
- skills,
7126
- count: skills.length,
7127
- has
7128
- };
7129
- }
7130
-
7131
- // src/react/utils/permission-storage.ts
7132
- var DEFAULT_KEY_PREFIX = "yourgpt-permissions";
7133
- function createPermissionStorage(config) {
7134
- switch (config.type) {
7135
- case "localStorage":
7136
- return createBrowserStorageAdapter(
7137
- typeof window !== "undefined" ? localStorage : null,
7138
- config.keyPrefix
7139
- );
7140
- case "sessionStorage":
7141
- return createBrowserStorageAdapter(
7142
- typeof window !== "undefined" ? sessionStorage : null,
7143
- config.keyPrefix
7144
- );
7145
- case "memory":
7146
- default:
7147
- return createMemoryStorageAdapter();
7148
- }
7149
- }
7150
- function createBrowserStorageAdapter(storage, keyPrefix = DEFAULT_KEY_PREFIX) {
7151
- const getStorageKey = () => keyPrefix;
7152
- const loadPermissions = () => {
7153
- if (!storage) return /* @__PURE__ */ new Map();
7154
- try {
7155
- const data = storage.getItem(getStorageKey());
7156
- if (!data) return /* @__PURE__ */ new Map();
7157
- const parsed = JSON.parse(data);
7158
- return new Map(parsed.map((p) => [p.toolName, p]));
7159
- } catch {
7160
- return /* @__PURE__ */ new Map();
7161
- }
7162
- };
7163
- const savePermissions = (permissions) => {
7164
- if (!storage) return;
7165
- try {
7166
- storage.setItem(
7167
- getStorageKey(),
7168
- JSON.stringify(Array.from(permissions.values()))
7169
- );
7170
- } catch (e) {
7171
- console.warn("[PermissionStorage] Failed to save permissions:", e);
7172
- }
7173
- };
7174
- return {
7175
- async get(toolName) {
7176
- const permissions = loadPermissions();
7177
- return permissions.get(toolName) || null;
7178
- },
7179
- async set(permission) {
7180
- const permissions = loadPermissions();
7181
- permissions.set(permission.toolName, permission);
7182
- savePermissions(permissions);
7183
- },
7184
- async remove(toolName) {
7185
- const permissions = loadPermissions();
7186
- permissions.delete(toolName);
7187
- savePermissions(permissions);
7188
- },
7189
- async getAll() {
7190
- const permissions = loadPermissions();
7191
- return Array.from(permissions.values());
7192
- },
7193
- async clear() {
7194
- if (!storage) return;
7195
- storage.removeItem(getStorageKey());
7196
- }
7197
- };
7198
- }
7199
- function createMemoryStorageAdapter() {
7200
- const permissions = /* @__PURE__ */ new Map();
7201
- return {
7202
- async get(toolName) {
7203
- return permissions.get(toolName) || null;
7204
- },
7205
- async set(permission) {
7206
- permissions.set(permission.toolName, permission);
7207
- },
7208
- async remove(toolName) {
7209
- permissions.delete(toolName);
7210
- },
7211
- async getAll() {
7212
- return Array.from(permissions.values());
7213
- },
7214
- async clear() {
7215
- permissions.clear();
7216
- }
7217
- };
7218
- }
7219
- function createSessionPermissionCache() {
7220
- return /* @__PURE__ */ new Map();
7221
- }
7222
-
7223
- // src/react/internal/ReactChat.ts
7224
- var ReactChat = class extends AbstractChat {
7225
- constructor(config) {
7226
- const reactState = new ReactChatState(config.initialMessages);
7227
- const init = {
7228
- runtimeUrl: config.runtimeUrl,
7229
- systemPrompt: config.systemPrompt,
7230
- llm: config.llm,
7231
- threadId: config.threadId,
7232
- streaming: config.streaming ?? true,
7233
- headers: config.headers,
7234
- initialMessages: config.initialMessages,
7235
- state: reactState,
7236
- callbacks: config.callbacks,
7237
- debug: config.debug
7238
- };
7239
- super(init);
7240
- // ============================================
7241
- // Subscribe (for useSyncExternalStore)
7242
- // ============================================
7243
- /**
7244
- * Subscribe to state changes.
7245
- * Returns an unsubscribe function.
7246
- *
7247
- * @example
7248
- * ```tsx
7249
- * const messages = useSyncExternalStore(
7250
- * chat.subscribe,
7251
- * () => chat.messages
7252
- * );
7253
- * ```
7254
- */
7255
- this.subscribe = (callback) => {
7256
- return this.reactState.subscribe(callback);
7257
- };
7258
- this.reactState = reactState;
7259
- }
7260
- // ============================================
7261
- // Event handling shortcuts
7262
- // ============================================
7263
- /**
7264
- * Subscribe to tool calls events
7265
- */
7266
- onToolCalls(handler) {
7267
- return this.on("toolCalls", handler);
7268
- }
7269
- /**
7270
- * Subscribe to done events
7271
- */
7272
- onDone(handler) {
7273
- return this.on("done", handler);
7274
- }
7275
- /**
7276
- * Subscribe to error events
7277
- */
7278
- onError(handler) {
7279
- return this.on("error", handler);
7280
- }
7281
- // ============================================
7282
- // Branching API — pass-throughs to ReactChatState
7283
- // ============================================
7284
- /**
7285
- * Navigate to a sibling branch (makes it the active path).
7286
- */
7287
- switchBranch(messageId) {
7288
- this.reactState.switchBranch(messageId);
7289
- }
7290
- /**
7291
- * Get branch navigation info for a message.
7292
- * Returns null if the message has no siblings.
7293
- */
7294
- getBranchInfo(messageId) {
7295
- return this.reactState.getBranchInfo(messageId);
7296
- }
7297
- /**
7298
- * Get all messages across all branches (for persistence).
7299
- */
7300
- getAllMessages() {
7301
- return this.reactState.getAllMessages();
7302
- }
7303
- /**
7304
- * Whether any message has siblings (branching has occurred).
7305
- */
7306
- get hasBranches() {
7307
- return this.reactState.hasBranches;
7308
- }
7309
- // ============================================
7310
- // Override dispose to clean up state
7311
- // ============================================
7312
- dispose() {
7313
- super.dispose();
7314
- this.reactState.dispose();
7315
- }
7316
- /**
7317
- * Revive a disposed instance (for React StrictMode compatibility)
7318
- */
7319
- revive() {
7320
- super.revive();
7321
- this.reactState.revive();
7322
- }
7323
- };
7324
- function createReactChat(config) {
7325
- return new ReactChat(config);
7326
- }
7327
- function useChat(config) {
7328
- const chatRef = React2.useRef(null);
7329
- const [input, setInput] = React2.useState("");
7330
- if (chatRef.current !== null && chatRef.current.disposed) {
7331
- chatRef.current.revive();
7332
- }
7333
- if (chatRef.current === null) {
7334
- chatRef.current = createReactChat({
7335
- runtimeUrl: config.runtimeUrl,
7336
- systemPrompt: config.systemPrompt,
7337
- llm: config.llm,
7338
- threadId: config.threadId,
7339
- streaming: config.streaming,
7340
- headers: config.headers,
7341
- initialMessages: config.initialMessages,
7342
- debug: config.debug,
7343
- callbacks: {
7344
- onMessagesChange: config.onMessagesChange,
7345
- onError: config.onError,
7346
- onFinish: config.onFinish,
7347
- onToolCalls: config.onToolCalls
7348
- }
7349
- });
7350
- }
7351
- const messages = React2.useSyncExternalStore(
7352
- chatRef.current.subscribe,
7353
- () => chatRef.current.messages,
7354
- () => chatRef.current.messages
7355
- // Server snapshot
5425
+ return id;
5426
+ },
5427
+ [debugLog]
7356
5428
  );
7357
- const status = React2.useSyncExternalStore(
7358
- chatRef.current.subscribe,
7359
- () => chatRef.current.status,
7360
- () => "ready"
7361
- // 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]
7362
5438
  );
7363
- const error = React2.useSyncExternalStore(
7364
- chatRef.current.subscribe,
7365
- () => chatRef.current.error,
7366
- () => void 0
7367
- // Server snapshot
5439
+ const setSystemPrompt = React2.useCallback(
5440
+ (prompt) => {
5441
+ chatRef.current?.setSystemPrompt(prompt);
5442
+ debugLog("System prompt updated via function");
5443
+ },
5444
+ [debugLog]
7368
5445
  );
7369
- const hasBranches = React2.useSyncExternalStore(
7370
- chatRef.current.subscribe,
7371
- () => chatRef.current.hasBranches,
7372
- () => false
5446
+ const setInlineSkills = React2.useCallback(
5447
+ (skills2) => {
5448
+ chatRef.current?.setInlineSkills(skills2);
5449
+ debugLog("Inline skills updated", { count: skills2.length });
5450
+ },
5451
+ [debugLog]
7373
5452
  );
7374
- const isLoading = status === "streaming" || status === "submitted";
7375
5453
  const sendMessage = React2.useCallback(
7376
5454
  async (content, attachments) => {
5455
+ debugLog("Sending message:", content);
5456
+ setAgentIteration(0);
7377
5457
  await chatRef.current?.sendMessage(content, attachments);
7378
- setInput("");
7379
5458
  },
7380
- []
5459
+ [debugLog]
7381
5460
  );
7382
5461
  const stop = React2.useCallback(() => {
7383
5462
  chatRef.current?.stop();
@@ -7391,19 +5470,11 @@ function useChat(config) {
7391
5470
  const regenerate = React2.useCallback(async (messageId) => {
7392
5471
  await chatRef.current?.regenerate(messageId);
7393
5472
  }, []);
7394
- const continueWithToolResults = React2.useCallback(
7395
- async (toolResults) => {
7396
- await chatRef.current?.continueWithToolResults(toolResults);
7397
- },
7398
- []
7399
- );
7400
5473
  const switchBranch = React2.useCallback((messageId) => {
7401
5474
  chatRef.current?.switchBranch(messageId);
7402
5475
  }, []);
7403
5476
  const getBranchInfo = React2.useCallback(
7404
- (messageId) => {
7405
- return chatRef.current?.getBranchInfo(messageId) ?? null;
7406
- },
5477
+ (messageId) => chatRef.current?.getBranchInfo(messageId) ?? null,
7407
5478
  []
7408
5479
  );
7409
5480
  const editMessage = React2.useCallback(
@@ -7411,40 +5482,238 @@ function useChat(config) {
7411
5482
  await chatRef.current?.sendMessage(newContent, void 0, {
7412
5483
  editMessageId: messageId
7413
5484
  });
7414
- setInput("");
7415
5485
  },
7416
5486
  []
7417
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]);
7418
5526
  React2.useEffect(() => {
7419
5527
  return () => {
7420
5528
  chatRef.current?.dispose();
7421
5529
  };
7422
5530
  }, []);
7423
- return {
7424
- messages,
7425
- status,
7426
- error,
7427
- isLoading,
7428
- input,
7429
- setInput,
7430
- sendMessage,
7431
- stop,
7432
- clearMessages,
7433
- setMessages,
7434
- regenerate,
7435
- continueWithToolResults,
7436
- chatRef,
7437
- // Branching
7438
- switchBranch,
7439
- getBranchInfo,
7440
- editMessage,
7441
- hasBranches
7442
- };
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
+ ] }) });
7443
5643
  }
7444
5644
 
7445
- // src/react/skill/define-skill.ts
7446
- function defineSkill(def) {
7447
- 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
+ };
7448
5717
  }
7449
5718
 
7450
5719
  exports.AbstractAgentLoop = AbstractAgentLoop;
@@ -7452,56 +5721,25 @@ exports.AbstractChat = AbstractChat;
7452
5721
  exports.CopilotProvider = CopilotProvider;
7453
5722
  exports.MessageHistoryContext = MessageHistoryContext;
7454
5723
  exports.MessageTree = MessageTree;
7455
- exports.ReactChat = ReactChat;
7456
5724
  exports.ReactChatState = ReactChatState;
7457
- exports.ReactThreadManager = ReactThreadManager;
7458
- exports.ReactThreadManagerState = ReactThreadManagerState;
7459
5725
  exports.SkillProvider = SkillProvider;
7460
- exports.createMessageIntentHandler = createMessageIntentHandler;
7461
- exports.createPermissionStorage = createPermissionStorage;
7462
- exports.createReactChat = createReactChat;
7463
5726
  exports.createReactChatState = createReactChatState;
7464
- exports.createReactThreadManager = createReactThreadManager;
7465
- exports.createReactThreadManagerState = createReactThreadManagerState;
7466
- exports.createSessionPermissionCache = createSessionPermissionCache;
7467
- exports.createToolIntentHandler = createToolIntentHandler;
7468
5727
  exports.defaultMessageHistoryConfig = defaultMessageHistoryConfig;
7469
- exports.defineSkill = defineSkill;
7470
- exports.formatKnowledgeResultsForAI = formatKnowledgeResultsForAI;
7471
5728
  exports.initialAgentLoopState = initialAgentLoopState;
7472
5729
  exports.isCompactionMarker = isCompactionMarker;
7473
5730
  exports.keepToolPairsAtomic = keepToolPairsAtomic;
7474
- exports.searchKnowledgeBase = searchKnowledgeBase;
7475
5731
  exports.toDisplayMessage = toDisplayMessage;
7476
5732
  exports.toLLMMessage = toLLMMessage;
7477
5733
  exports.toLLMMessages = toLLMMessages;
7478
- exports.useAIAction = useAIAction;
7479
- exports.useAIActions = useAIActions;
7480
5734
  exports.useAIContext = useAIContext;
7481
5735
  exports.useAIContexts = useAIContexts;
7482
- exports.useAITools = useAITools;
7483
- exports.useAgent = useAgent;
7484
- exports.useCapabilities = useCapabilities;
7485
- exports.useChat = useChat;
7486
- exports.useContextStats = useContextStats;
7487
5736
  exports.useCopilot = useCopilot;
7488
- exports.useDevLogger = useDevLogger;
7489
- exports.useFeatureSupport = useFeatureSupport;
7490
- exports.useKnowledgeBase = useKnowledgeBase;
7491
5737
  exports.useMCPClient = useMCPClient;
7492
5738
  exports.useMCPTools = useMCPTools;
7493
- exports.useMCPUIIntents = useMCPUIIntents;
7494
5739
  exports.useMessageHistory = useMessageHistory;
7495
5740
  exports.useMessageHistoryContext = useMessageHistoryContext;
7496
- exports.useSkill = useSkill;
7497
- exports.useSkillStatus = useSkillStatus;
7498
- exports.useSuggestions = useSuggestions;
7499
- exports.useSupportedMediaTypes = useSupportedMediaTypes;
7500
- exports.useThreadManager = useThreadManager;
5741
+ exports.useSkillContext = useSkillContext;
7501
5742
  exports.useTool = useTool;
7502
- exports.useToolExecutor = useToolExecutor;
7503
- exports.useToolWithSchema = useToolWithSchema;
7504
5743
  exports.useTools = useTools;
7505
- exports.useToolsWithSchema = useToolsWithSchema;
7506
- //# sourceMappingURL=chunk-TCPAT3WG.cjs.map
7507
- //# sourceMappingURL=chunk-TCPAT3WG.cjs.map
5744
+ //# sourceMappingURL=chunk-LHLVTGIP.cjs.map
5745
+ //# sourceMappingURL=chunk-LHLVTGIP.cjs.map