@yourgpt/copilot-sdk 2.1.5-alpha.4 → 2.1.5-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{MessageTree-CSIHErPK.d.ts → MessageTree-Clhiv_k2.d.ts} +4 -3
- package/dist/{MessageTree-B0JGQOCi.d.cts → MessageTree-Dt9qfJ55.d.cts} +4 -3
- package/dist/{chunk-NUXLAZOE.cjs → chunk-3ZDRX7J2.cjs} +2 -2
- package/dist/{chunk-NUXLAZOE.cjs.map → chunk-3ZDRX7J2.cjs.map} +1 -1
- package/dist/{chunk-RKGRQRZU.js → chunk-533K2Z7C.js} +4 -4
- package/dist/{chunk-RKGRQRZU.js.map → chunk-533K2Z7C.js.map} +1 -1
- package/dist/chunk-5EGBIQYS.cjs +292 -0
- package/dist/chunk-5EGBIQYS.cjs.map +1 -0
- package/dist/chunk-5UGWLGFS.cjs +2039 -0
- package/dist/chunk-5UGWLGFS.cjs.map +1 -0
- package/dist/{chunk-3AONOZLY.js → chunk-AIVXGTWS.js} +2 -2
- package/dist/chunk-AIVXGTWS.js.map +1 -0
- package/dist/{chunk-LLM7AHMO.js → chunk-DDZLRCVX.js} +2 -2
- package/dist/{chunk-LLM7AHMO.js.map → chunk-DDZLRCVX.js.map} +1 -1
- package/dist/{chunk-FLZO2FO3.js → chunk-DH6EO6NW.js} +1334 -3048
- package/dist/chunk-DH6EO6NW.js.map +1 -0
- package/dist/{chunk-B4YDIMP3.cjs → chunk-KGYDGK3U.cjs} +82 -29
- package/dist/chunk-KGYDGK3U.cjs.map +1 -0
- package/dist/{chunk-XUR3IOPX.cjs → chunk-LHLVTGIP.cjs} +1336 -3100
- package/dist/chunk-LHLVTGIP.cjs.map +1 -0
- package/dist/{chunk-TPB7XED6.cjs → chunk-TPDMBDQX.cjs} +2 -2
- package/dist/chunk-TPDMBDQX.cjs.map +1 -0
- package/dist/chunk-TXQ37MAO.js +287 -0
- package/dist/chunk-TXQ37MAO.js.map +1 -0
- package/dist/{chunk-MDS23G2S.cjs → chunk-Y2A6AMGO.cjs} +10 -10
- package/dist/{chunk-MDS23G2S.cjs.map → chunk-Y2A6AMGO.cjs.map} +1 -1
- package/dist/{chunk-EEH3L64W.js → chunk-YLZCTR4O.js} +63 -10
- package/dist/chunk-YLZCTR4O.js.map +1 -0
- package/dist/chunk-ZAOTYA5L.js +1983 -0
- package/dist/chunk-ZAOTYA5L.js.map +1 -0
- package/dist/core/index.cjs +93 -93
- package/dist/core/index.d.cts +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +5 -5
- package/dist/experimental/index.cjs +644 -0
- package/dist/experimental/index.cjs.map +1 -0
- package/dist/experimental/index.d.cts +924 -0
- package/dist/experimental/index.d.ts +924 -0
- package/dist/experimental/index.js +611 -0
- package/dist/experimental/index.js.map +1 -0
- package/dist/{index-D7169xuR.d.ts → index-D8zza1Q8.d.ts} +1 -1
- package/dist/{index-CzJB8Ddo.d.cts → index-DCVjTdIZ.d.cts} +1 -1
- package/dist/mcp/index.d.cts +3 -3
- package/dist/mcp/index.d.ts +3 -3
- package/dist/react/index.cjs +136 -123
- package/dist/react/index.d.cts +174 -8
- package/dist/react/index.d.ts +174 -8
- package/dist/react/index.js +7 -6
- package/dist/styles.css +45 -0
- package/dist/tools/anthropic/index.cjs +3 -3
- package/dist/tools/anthropic/index.d.cts +1 -1
- package/dist/tools/anthropic/index.d.ts +1 -1
- package/dist/tools/anthropic/index.js +2 -2
- package/dist/tools/brave/index.cjs +6 -6
- package/dist/tools/brave/index.d.cts +1 -1
- package/dist/tools/brave/index.d.ts +1 -1
- package/dist/tools/brave/index.js +3 -3
- package/dist/tools/exa/index.cjs +6 -6
- package/dist/tools/exa/index.d.cts +1 -1
- package/dist/tools/exa/index.d.ts +1 -1
- package/dist/tools/exa/index.js +3 -3
- package/dist/tools/google/index.cjs +6 -6
- package/dist/tools/google/index.d.cts +1 -1
- package/dist/tools/google/index.d.ts +1 -1
- package/dist/tools/google/index.js +4 -4
- package/dist/tools/openai/index.cjs +6 -6
- package/dist/tools/openai/index.d.cts +1 -1
- package/dist/tools/openai/index.d.ts +1 -1
- package/dist/tools/openai/index.js +3 -3
- package/dist/tools/searxng/index.cjs +6 -6
- package/dist/tools/searxng/index.d.cts +1 -1
- package/dist/tools/searxng/index.d.ts +1 -1
- package/dist/tools/searxng/index.js +3 -3
- package/dist/tools/serper/index.cjs +6 -6
- package/dist/tools/serper/index.d.cts +1 -1
- package/dist/tools/serper/index.d.ts +1 -1
- package/dist/tools/serper/index.js +3 -3
- package/dist/tools/tavily/index.cjs +6 -6
- package/dist/tools/tavily/index.d.cts +1 -1
- package/dist/tools/tavily/index.d.ts +1 -1
- package/dist/tools/tavily/index.js +3 -3
- package/dist/tools/web-search/index.cjs +7 -7
- package/dist/tools/web-search/index.d.cts +2 -2
- package/dist/tools/web-search/index.d.ts +2 -2
- package/dist/tools/web-search/index.js +4 -4
- package/dist/{tools-tmksfhUo.d.cts → tools-DcS6Aeao.d.cts} +7 -3
- package/dist/{tools-tmksfhUo.d.ts → tools-DcS6Aeao.d.ts} +7 -3
- package/dist/{types-BqwW3Baj.d.ts → types-BUYni9B8.d.ts} +1 -1
- package/dist/{types-BLw7mxtW.d.cts → types-Cvg4DUoc.d.cts} +1 -1
- package/dist/ui/index.cjs +345 -522
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +21 -3
- package/dist/ui/index.d.ts +21 -3
- package/dist/ui/index.js +188 -370
- package/dist/ui/index.js.map +1 -1
- package/package.json +6 -1
- package/dist/chunk-3AONOZLY.js.map +0 -1
- package/dist/chunk-B4YDIMP3.cjs.map +0 -1
- package/dist/chunk-EEH3L64W.js.map +0 -1
- package/dist/chunk-FLZO2FO3.js.map +0 -1
- package/dist/chunk-TPB7XED6.cjs.map +0 -1
- package/dist/chunk-XUR3IOPX.cjs.map +0 -1
|
@@ -1,34 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
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(
|
|
666
|
-
return estimateTokens(JSON.stringify(
|
|
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(
|
|
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 ===
|
|
661
|
+
if (normalized === tool.name.toLowerCase()) {
|
|
682
662
|
return true;
|
|
683
663
|
}
|
|
684
664
|
if (normalized.startsWith("group:")) {
|
|
685
|
-
return (
|
|
665
|
+
return (tool.group ?? "").toLowerCase() === normalized.slice(6);
|
|
686
666
|
}
|
|
687
667
|
if (normalized.startsWith("category:")) {
|
|
688
|
-
return (
|
|
668
|
+
return (tool.category ?? "").toLowerCase() === normalized.slice(9);
|
|
689
669
|
}
|
|
690
670
|
if (normalized.startsWith("profile:")) {
|
|
691
|
-
return (
|
|
671
|
+
return (tool.profiles ?? []).map((value) => value.toLowerCase()).includes(normalized.slice(8));
|
|
692
672
|
}
|
|
693
673
|
if (activeProfile && normalized === activeProfile.toLowerCase()) {
|
|
694
|
-
return (
|
|
674
|
+
return (tool.profiles ?? []).map((value) => value.toLowerCase()).includes(normalized);
|
|
695
675
|
}
|
|
696
676
|
return false;
|
|
697
677
|
}
|
|
698
|
-
function scoreTool(
|
|
678
|
+
function scoreTool(tool, queryTokens, activeProfile) {
|
|
699
679
|
const haystack = [
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
...
|
|
705
|
-
...
|
|
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 =
|
|
708
|
-
if (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 (
|
|
692
|
+
if (tool.name.toLowerCase() === token) {
|
|
713
693
|
score += 6;
|
|
714
|
-
} else if (
|
|
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((
|
|
929
|
-
name:
|
|
930
|
-
description:
|
|
931
|
-
category:
|
|
932
|
-
group:
|
|
933
|
-
deferLoading:
|
|
934
|
-
profiles:
|
|
935
|
-
searchKeywords:
|
|
936
|
-
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,
|
|
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 ??
|
|
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 &&
|
|
977
|
-
aiContext = typeof
|
|
956
|
+
if (!aiContext && tool?.aiContext) {
|
|
957
|
+
aiContext = typeof tool.aiContext === "function" ? tool.aiContext(
|
|
978
958
|
typedResult ?? { success: true },
|
|
979
959
|
args ?? {}
|
|
980
|
-
) :
|
|
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,
|
|
1010
|
-
const text = buildToolResultContent(result,
|
|
1011
|
-
const truncation = resolveTruncationConfig({ tool
|
|
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,
|
|
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,
|
|
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((
|
|
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
|
-
(
|
|
1406
|
-
(selector) => matchesSelector(
|
|
1407
|
-
) || !!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((
|
|
1411
|
-
if (
|
|
1412
|
-
return
|
|
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
|
-
(
|
|
1420
|
-
(selector) => matchesSelector(
|
|
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((
|
|
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
|
|
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
|
-
|
|
1463
|
+
tool,
|
|
1484
1464
|
toolCall?.args ?? {},
|
|
1485
1465
|
this.config
|
|
1486
1466
|
);
|
|
1487
1467
|
} catch {
|
|
1488
1468
|
content = buildToolResultContentForPrompt(
|
|
1489
1469
|
message.content,
|
|
1490
|
-
|
|
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((
|
|
1977
|
-
name:
|
|
1978
|
-
description:
|
|
1979
|
-
category:
|
|
1980
|
-
group:
|
|
1981
|
-
deferLoading:
|
|
1982
|
-
profiles:
|
|
1983
|
-
searchKeywords:
|
|
1984
|
-
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
|
|
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
|
-
...
|
|
2133
|
-
...
|
|
2134
|
-
...
|
|
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
|
-
|
|
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
|
-
...
|
|
2264
|
-
...
|
|
2265
|
-
...
|
|
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 =
|
|
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
|
|
2506
|
-
this.registerTool(
|
|
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(
|
|
2596
|
-
const existing = this.registeredTools.get(
|
|
2654
|
+
registerTool(tool) {
|
|
2655
|
+
const existing = this.registeredTools.get(tool.name);
|
|
2597
2656
|
if (existing) {
|
|
2598
|
-
existing.tool =
|
|
2657
|
+
existing.tool = tool;
|
|
2599
2658
|
existing.refCount++;
|
|
2600
2659
|
existing.active = true;
|
|
2601
2660
|
} else {
|
|
2602
|
-
this.registeredTools.set(
|
|
2603
|
-
tool
|
|
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
|
|
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:
|
|
2736
|
+
hidden: tool?.hidden
|
|
2678
2737
|
};
|
|
2679
2738
|
this.addToolExecution(execution);
|
|
2680
2739
|
this.callbacks.onToolStart?.(execution);
|
|
2681
|
-
if (!
|
|
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 (
|
|
2696
|
-
const approvalTitle = typeof
|
|
2697
|
-
const approvalMessage = typeof
|
|
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 (!
|
|
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
|
|
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/
|
|
2956
|
-
var
|
|
2957
|
-
constructor(
|
|
2958
|
-
|
|
2959
|
-
this.
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
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
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
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
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
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
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
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
|
-
//
|
|
3102
|
+
// Core Queries
|
|
3108
3103
|
// ============================================
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
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
|
-
|
|
3119
|
-
|
|
3123
|
+
_invalidateCache() {
|
|
3124
|
+
this._visibleCache = null;
|
|
3120
3125
|
}
|
|
3121
3126
|
/**
|
|
3122
|
-
*
|
|
3123
|
-
* Use this to show loading indicators and disable send button
|
|
3127
|
+
* Returns ALL messages across every branch (for persistence / ThreadManager).
|
|
3124
3128
|
*/
|
|
3125
|
-
|
|
3126
|
-
|
|
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
|
-
*
|
|
3133
|
-
*
|
|
3133
|
+
* Branch navigation info for the UI navigator.
|
|
3134
|
+
* Returns null if the message has no siblings (only child).
|
|
3134
3135
|
*/
|
|
3135
|
-
|
|
3136
|
-
const
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
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
|
|
3153
|
-
return this.
|
|
3151
|
+
get currentLeafId() {
|
|
3152
|
+
return this._currentLeafId;
|
|
3154
3153
|
}
|
|
3155
|
-
get
|
|
3156
|
-
|
|
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
|
-
//
|
|
3161
|
+
// Mutations
|
|
3160
3162
|
// ============================================
|
|
3161
3163
|
/**
|
|
3162
|
-
*
|
|
3163
|
-
*
|
|
3164
|
-
*
|
|
3165
|
-
*
|
|
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
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
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.
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
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
|
-
*
|
|
3185
|
+
* Navigate: make messageId the active child at its parent fork,
|
|
3186
|
+
* then walk to its leaf and update currentLeafId.
|
|
3282
3187
|
*/
|
|
3283
|
-
|
|
3284
|
-
this.
|
|
3285
|
-
|
|
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
|
-
*
|
|
3197
|
+
* Update message content in-place (streaming updates).
|
|
3198
|
+
* No tree structure change.
|
|
3292
3199
|
*/
|
|
3293
|
-
|
|
3294
|
-
this.
|
|
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
|
-
*
|
|
3208
|
+
* Set current leaf explicitly.
|
|
3209
|
+
* Used by regenerate() to rewind the active path before pushing a new message.
|
|
3298
3210
|
*/
|
|
3299
|
-
|
|
3300
|
-
this.
|
|
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
|
-
*
|
|
3226
|
+
* Rebuild entire tree from a message array.
|
|
3227
|
+
* Used by setMessages().
|
|
3304
3228
|
*/
|
|
3305
|
-
|
|
3306
|
-
this.
|
|
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
|
-
//
|
|
3240
|
+
// Private Helpers
|
|
3310
3241
|
// ============================================
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
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
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
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
|
-
*
|
|
3285
|
+
* Walk the active path from root to the current leaf.
|
|
3337
3286
|
*/
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
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/
|
|
3354
|
-
var
|
|
3355
|
-
constructor(
|
|
3356
|
-
|
|
3357
|
-
this.
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
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
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
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
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
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
|
-
|
|
3427
|
-
}
|
|
3428
|
-
return result.map((msg) => ({
|
|
3429
|
-
...msg,
|
|
3430
|
-
childrenIds: childrenMap.get(msg.id) ?? []
|
|
3431
|
-
}));
|
|
3463
|
+
});
|
|
3432
3464
|
}
|
|
3433
3465
|
// ============================================
|
|
3434
|
-
//
|
|
3466
|
+
// Chat Getters
|
|
3435
3467
|
// ============================================
|
|
3436
|
-
|
|
3437
|
-
|
|
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
|
-
|
|
3456
|
-
this.
|
|
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
|
-
*
|
|
3481
|
+
* Whether any operation is in progress (chat or tools)
|
|
3482
|
+
* Use this to show loading indicators and disable send button
|
|
3460
3483
|
*/
|
|
3461
|
-
|
|
3462
|
-
|
|
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
|
-
*
|
|
3466
|
-
*
|
|
3491
|
+
* Check if a request is currently in progress (excludes pending approvals)
|
|
3492
|
+
* Use this to prevent sending new messages
|
|
3467
3493
|
*/
|
|
3468
|
-
|
|
3469
|
-
const
|
|
3470
|
-
|
|
3471
|
-
|
|
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
|
-
|
|
3484
|
-
|
|
3499
|
+
// ============================================
|
|
3500
|
+
// Tool Execution Getters
|
|
3501
|
+
// ============================================
|
|
3502
|
+
get toolExecutions() {
|
|
3503
|
+
return this.agentLoop.toolExecutions;
|
|
3485
3504
|
}
|
|
3486
|
-
get
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
return
|
|
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
|
-
//
|
|
3518
|
+
// Chat Actions
|
|
3494
3519
|
// ============================================
|
|
3495
3520
|
/**
|
|
3496
|
-
*
|
|
3497
|
-
*
|
|
3498
|
-
*
|
|
3499
|
-
* -
|
|
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
|
-
|
|
3502
|
-
this.
|
|
3503
|
-
|
|
3504
|
-
|
|
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.
|
|
3512
|
-
|
|
3513
|
-
this._invalidateCache();
|
|
3514
|
-
return message;
|
|
3532
|
+
this.agentLoop.resetIterations();
|
|
3533
|
+
return await this.chat.sendMessage(content, attachments, options);
|
|
3515
3534
|
}
|
|
3516
3535
|
/**
|
|
3517
|
-
*
|
|
3518
|
-
* then walk to its leaf and update currentLeafId.
|
|
3536
|
+
* Stop generation and cancel any running tools
|
|
3519
3537
|
*/
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
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
|
-
*
|
|
3530
|
-
* No tree structure change.
|
|
3544
|
+
* Clear all messages
|
|
3531
3545
|
*/
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
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
|
|
3541
|
-
* Used by regenerate() to rewind the active path before pushing a new message.
|
|
3551
|
+
* Set messages directly
|
|
3542
3552
|
*/
|
|
3543
|
-
|
|
3544
|
-
this.
|
|
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
|
-
*
|
|
3559
|
-
* Used by setMessages().
|
|
3557
|
+
* Regenerate last response
|
|
3560
3558
|
*/
|
|
3561
|
-
|
|
3562
|
-
this.
|
|
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
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3562
|
+
/**
|
|
3563
|
+
* Set tools available for the LLM
|
|
3564
|
+
*/
|
|
3565
|
+
setTools(tools) {
|
|
3566
|
+
this.chat.setTools(tools);
|
|
3600
3567
|
}
|
|
3601
3568
|
/**
|
|
3602
|
-
*
|
|
3569
|
+
* Update prompt/tool optimization controls.
|
|
3603
3570
|
*/
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
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
|
-
*
|
|
3576
|
+
* Set the active tool profile used for request-time tool selection.
|
|
3618
3577
|
*/
|
|
3619
|
-
|
|
3620
|
-
|
|
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
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
3684
|
-
|
|
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
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
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/
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
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
|
-
|
|
4106
|
-
|
|
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
|
-
|
|
4131
|
-
|
|
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
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
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
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
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
|
|
4854
|
+
return chunkKGYDGK3U_cjs.zodToJsonSchema(config.inputSchema);
|
|
4861
4855
|
}
|
|
4862
4856
|
return config.inputSchema;
|
|
4863
4857
|
}, [config.inputSchema]);
|
|
4864
4858
|
React2.useEffect(() => {
|
|
4865
|
-
const
|
|
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(
|
|
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
|
-
|
|
5247
|
+
chunkKGYDGK3U_cjs.createLogger("provider", () => debug ?? false)(action, data);
|
|
5216
5248
|
},
|
|
5217
5249
|
[debug]
|
|
5218
5250
|
);
|
|
@@ -5224,6 +5256,7 @@ function CopilotProvider({
|
|
|
5224
5256
|
}
|
|
5225
5257
|
}, [toolsConfig]);
|
|
5226
5258
|
const [toolExecutions, setToolExecutions] = React2.useState([]);
|
|
5259
|
+
const [agentIteration, setAgentIteration] = React2.useState(0);
|
|
5227
5260
|
const chatRef = React2.useRef(null);
|
|
5228
5261
|
if (chatRef.current !== null && chatRef.current.disposed) {
|
|
5229
5262
|
chatRef.current.revive();
|
|
@@ -5261,6 +5294,7 @@ function CopilotProvider({
|
|
|
5261
5294
|
onToolExecutionsChange: (executions) => {
|
|
5262
5295
|
debugLog("Tool executions changed:", executions.length);
|
|
5263
5296
|
setToolExecutions(executions);
|
|
5297
|
+
setAgentIteration(chatRef.current?.iteration ?? 0);
|
|
5264
5298
|
},
|
|
5265
5299
|
onApprovalRequired: (execution) => {
|
|
5266
5300
|
debugLog("Tool approval required:", execution.name);
|
|
@@ -5270,6 +5304,13 @@ function CopilotProvider({
|
|
|
5270
5304
|
},
|
|
5271
5305
|
onError: (error2) => {
|
|
5272
5306
|
if (error2) onError?.(error2);
|
|
5307
|
+
},
|
|
5308
|
+
onStreamChunk: (chunk) => {
|
|
5309
|
+
if (streamListenersRef.current.size > 0) {
|
|
5310
|
+
for (const handler of streamListenersRef.current) {
|
|
5311
|
+
handler(chunk);
|
|
5312
|
+
}
|
|
5313
|
+
}
|
|
5273
5314
|
}
|
|
5274
5315
|
}
|
|
5275
5316
|
);
|
|
@@ -5323,8 +5364,8 @@ function CopilotProvider({
|
|
|
5323
5364
|
);
|
|
5324
5365
|
const error = errorFromChat ?? null;
|
|
5325
5366
|
const isLoading = status === "streaming" || status === "submitted";
|
|
5326
|
-
const registerTool = React2.useCallback((
|
|
5327
|
-
chatRef.current?.registerTool(
|
|
5367
|
+
const registerTool = React2.useCallback((tool) => {
|
|
5368
|
+
chatRef.current?.registerTool(tool);
|
|
5328
5369
|
}, []);
|
|
5329
5370
|
const unregisterTool = React2.useCallback((name) => {
|
|
5330
5371
|
chatRef.current?.unregisterTool(name);
|
|
@@ -5381,2005 +5422,41 @@ function CopilotProvider({
|
|
|
5381
5422
|
chatRef.current?.setContext(contextString);
|
|
5382
5423
|
setContextChars(contextString.length);
|
|
5383
5424
|
debugLog("Context added:", id);
|
|
5384
|
-
return id;
|
|
5385
|
-
},
|
|
5386
|
-
[debugLog]
|
|
5387
|
-
);
|
|
5388
|
-
const removeContext = React2.useCallback(
|
|
5389
|
-
(id) => {
|
|
5390
|
-
contextTreeRef.current = removeNode(contextTreeRef.current, id);
|
|
5391
|
-
const contextString = printTree(contextTreeRef.current);
|
|
5392
|
-
chatRef.current?.setContext(contextString);
|
|
5393
|
-
setContextChars(contextString.length);
|
|
5394
|
-
debugLog("Context removed:", id);
|
|
5395
|
-
},
|
|
5396
|
-
[debugLog]
|
|
5397
|
-
);
|
|
5398
|
-
const setSystemPrompt = React2.useCallback(
|
|
5399
|
-
(prompt) => {
|
|
5400
|
-
chatRef.current?.setSystemPrompt(prompt);
|
|
5401
|
-
debugLog("System prompt updated via function");
|
|
5402
|
-
},
|
|
5403
|
-
[debugLog]
|
|
5404
|
-
);
|
|
5405
|
-
const setInlineSkills = React2.useCallback(
|
|
5406
|
-
(skills2) => {
|
|
5407
|
-
chatRef.current?.setInlineSkills(skills2);
|
|
5408
|
-
debugLog("Inline skills updated", { count: skills2.length });
|
|
5409
|
-
},
|
|
5410
|
-
[debugLog]
|
|
5411
|
-
);
|
|
5412
|
-
const sendMessage = React2.useCallback(
|
|
5413
|
-
async (content, attachments) => {
|
|
5414
|
-
debugLog("Sending message:", content);
|
|
5415
|
-
await chatRef.current?.sendMessage(content, attachments);
|
|
5416
|
-
},
|
|
5417
|
-
[debugLog]
|
|
5418
|
-
);
|
|
5419
|
-
const stop = React2.useCallback(() => {
|
|
5420
|
-
chatRef.current?.stop();
|
|
5421
|
-
}, []);
|
|
5422
|
-
const clearMessages = React2.useCallback(() => {
|
|
5423
|
-
chatRef.current?.clearMessages();
|
|
5424
|
-
}, []);
|
|
5425
|
-
const setMessages = React2.useCallback((messages2) => {
|
|
5426
|
-
chatRef.current?.setMessages(messages2);
|
|
5427
|
-
}, []);
|
|
5428
|
-
const regenerate = React2.useCallback(async (messageId) => {
|
|
5429
|
-
await chatRef.current?.regenerate(messageId);
|
|
5430
|
-
}, []);
|
|
5431
|
-
const switchBranch = React2.useCallback((messageId) => {
|
|
5432
|
-
chatRef.current?.switchBranch(messageId);
|
|
5433
|
-
}, []);
|
|
5434
|
-
const getBranchInfo = React2.useCallback(
|
|
5435
|
-
(messageId) => chatRef.current?.getBranchInfo(messageId) ?? null,
|
|
5436
|
-
[]
|
|
5437
|
-
);
|
|
5438
|
-
const editMessage = React2.useCallback(
|
|
5439
|
-
async (messageId, newContent) => {
|
|
5440
|
-
await chatRef.current?.sendMessage(newContent, void 0, {
|
|
5441
|
-
editMessageId: messageId
|
|
5442
|
-
});
|
|
5443
|
-
},
|
|
5444
|
-
[]
|
|
5445
|
-
);
|
|
5446
|
-
const getHasBranchesSnapshot = React2.useCallback(
|
|
5447
|
-
() => chatRef.current.hasBranches,
|
|
5448
|
-
[]
|
|
5449
|
-
);
|
|
5450
|
-
const hasBranches = React2.useSyncExternalStore(
|
|
5451
|
-
chatRef.current.subscribe,
|
|
5452
|
-
getHasBranchesSnapshot,
|
|
5453
|
-
() => false
|
|
5454
|
-
);
|
|
5455
|
-
const getAllMessages = React2.useCallback(
|
|
5456
|
-
() => chatRef.current?.getAllMessages?.() ?? [],
|
|
5457
|
-
[]
|
|
5458
|
-
);
|
|
5459
|
-
React2.useEffect(() => {
|
|
5460
|
-
if (onMessagesChange && messages.length > 0) {
|
|
5461
|
-
const allUIMessages = chatRef.current?.getAllMessages?.() ?? messages;
|
|
5462
|
-
const coreMessages = allUIMessages.map((m) => ({
|
|
5463
|
-
id: m.id,
|
|
5464
|
-
role: m.role,
|
|
5465
|
-
content: m.content,
|
|
5466
|
-
created_at: m.createdAt,
|
|
5467
|
-
tool_calls: m.toolCalls,
|
|
5468
|
-
tool_call_id: m.toolCallId,
|
|
5469
|
-
parent_id: m.parentId,
|
|
5470
|
-
children_ids: m.childrenIds,
|
|
5471
|
-
metadata: {
|
|
5472
|
-
attachments: m.attachments,
|
|
5473
|
-
thinking: m.thinking
|
|
5474
|
-
}
|
|
5475
|
-
}));
|
|
5476
|
-
onMessagesChange(coreMessages);
|
|
5477
|
-
}
|
|
5478
|
-
}, [messages, onMessagesChange]);
|
|
5479
|
-
React2.useEffect(() => {
|
|
5480
|
-
if (error && onError) {
|
|
5481
|
-
onError(error);
|
|
5482
|
-
}
|
|
5483
|
-
}, [error, onError]);
|
|
5484
|
-
React2.useEffect(() => {
|
|
5485
|
-
return () => {
|
|
5486
|
-
chatRef.current?.dispose();
|
|
5487
|
-
};
|
|
5488
|
-
}, []);
|
|
5489
|
-
const contextValue = React2.useMemo(
|
|
5490
|
-
() => ({
|
|
5491
|
-
// Chat state
|
|
5492
|
-
messages,
|
|
5493
|
-
status,
|
|
5494
|
-
error,
|
|
5495
|
-
isLoading,
|
|
5496
|
-
// Chat actions
|
|
5497
|
-
sendMessage,
|
|
5498
|
-
stop,
|
|
5499
|
-
clearMessages,
|
|
5500
|
-
setMessages,
|
|
5501
|
-
regenerate,
|
|
5502
|
-
// Branching
|
|
5503
|
-
switchBranch,
|
|
5504
|
-
getBranchInfo,
|
|
5505
|
-
editMessage,
|
|
5506
|
-
hasBranches,
|
|
5507
|
-
getAllMessages,
|
|
5508
|
-
// Tool execution
|
|
5509
|
-
registerTool,
|
|
5510
|
-
unregisterTool,
|
|
5511
|
-
registeredTools,
|
|
5512
|
-
toolExecutions,
|
|
5513
|
-
pendingApprovals,
|
|
5514
|
-
approveToolExecution,
|
|
5515
|
-
rejectToolExecution,
|
|
5516
|
-
// Actions
|
|
5517
|
-
registerAction,
|
|
5518
|
-
unregisterAction,
|
|
5519
|
-
registeredActions,
|
|
5520
|
-
// AI Context
|
|
5521
|
-
addContext,
|
|
5522
|
-
removeContext,
|
|
5523
|
-
contextChars,
|
|
5524
|
-
contextUsage,
|
|
5525
|
-
// System Prompt
|
|
5526
|
-
setSystemPrompt,
|
|
5527
|
-
// Skills
|
|
5528
|
-
setInlineSkills,
|
|
5529
|
-
// Config
|
|
5530
|
-
threadId,
|
|
5531
|
-
runtimeUrl,
|
|
5532
|
-
toolsConfig
|
|
5533
|
-
}),
|
|
5534
|
-
[
|
|
5535
|
-
messages,
|
|
5536
|
-
status,
|
|
5537
|
-
error,
|
|
5538
|
-
isLoading,
|
|
5539
|
-
sendMessage,
|
|
5540
|
-
stop,
|
|
5541
|
-
clearMessages,
|
|
5542
|
-
setMessages,
|
|
5543
|
-
regenerate,
|
|
5544
|
-
switchBranch,
|
|
5545
|
-
getBranchInfo,
|
|
5546
|
-
editMessage,
|
|
5547
|
-
hasBranches,
|
|
5548
|
-
getAllMessages,
|
|
5549
|
-
registerTool,
|
|
5550
|
-
unregisterTool,
|
|
5551
|
-
registeredTools,
|
|
5552
|
-
toolExecutions,
|
|
5553
|
-
pendingApprovals,
|
|
5554
|
-
approveToolExecution,
|
|
5555
|
-
rejectToolExecution,
|
|
5556
|
-
registerAction,
|
|
5557
|
-
unregisterAction,
|
|
5558
|
-
registeredActions,
|
|
5559
|
-
addContext,
|
|
5560
|
-
removeContext,
|
|
5561
|
-
contextChars,
|
|
5562
|
-
contextUsage,
|
|
5563
|
-
setSystemPrompt,
|
|
5564
|
-
setInlineSkills,
|
|
5565
|
-
threadId,
|
|
5566
|
-
runtimeUrl,
|
|
5567
|
-
toolsConfig
|
|
5568
|
-
]
|
|
5569
|
-
);
|
|
5570
|
-
const messageHistoryContextValue = React2__default.default.useMemo(
|
|
5571
|
-
() => ({
|
|
5572
|
-
config: { ...defaultMessageHistoryConfig, ...messageHistory },
|
|
5573
|
-
tokenUsage: {
|
|
5574
|
-
current: 0,
|
|
5575
|
-
max: messageHistory?.maxContextTokens ?? 128e3,
|
|
5576
|
-
percentage: 0,
|
|
5577
|
-
isApproaching: false
|
|
5578
|
-
},
|
|
5579
|
-
compactionState: {
|
|
5580
|
-
rollingSummary: null,
|
|
5581
|
-
lastCompactionAt: null,
|
|
5582
|
-
compactionCount: 0,
|
|
5583
|
-
totalTokensSaved: 0,
|
|
5584
|
-
workingMemory: [],
|
|
5585
|
-
displayMessageCount: 0,
|
|
5586
|
-
llmMessageCount: 0
|
|
5587
|
-
}
|
|
5588
|
-
}),
|
|
5589
|
-
[messageHistory]
|
|
5590
|
-
);
|
|
5591
|
-
return /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryContext.Provider, { value: messageHistoryContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(CopilotContext.Provider, { value: contextValue, children: [
|
|
5592
|
-
mcpServers?.map((config) => /* @__PURE__ */ jsxRuntime.jsx(MCPConnection, { config }, config.name)),
|
|
5593
|
-
messageHistory?.strategy && messageHistory.strategy !== "none" && /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryBridge, { chatRef }),
|
|
5594
|
-
skills ? /* @__PURE__ */ jsxRuntime.jsx(SkillProvider, { skills, children }) : children
|
|
5595
|
-
] }) });
|
|
5596
|
-
}
|
|
5597
|
-
function useAIActions(actions) {
|
|
5598
|
-
const { registerAction, unregisterAction } = useCopilot();
|
|
5599
|
-
React2.useEffect(() => {
|
|
5600
|
-
for (const action of actions) {
|
|
5601
|
-
registerAction(action);
|
|
5602
|
-
}
|
|
5603
|
-
return () => {
|
|
5604
|
-
for (const action of actions) {
|
|
5605
|
-
unregisterAction(action.name);
|
|
5606
|
-
}
|
|
5607
|
-
};
|
|
5608
|
-
}, [actions, registerAction, unregisterAction]);
|
|
5609
|
-
}
|
|
5610
|
-
function useAIAction(action) {
|
|
5611
|
-
useAIActions([action]);
|
|
5612
|
-
}
|
|
5613
|
-
function useAITools(options = {}) {
|
|
5614
|
-
const {
|
|
5615
|
-
screenshot = false,
|
|
5616
|
-
console: consoleCapture = false,
|
|
5617
|
-
network = false,
|
|
5618
|
-
requireConsent = true,
|
|
5619
|
-
screenshotOptions,
|
|
5620
|
-
consoleOptions,
|
|
5621
|
-
networkOptions,
|
|
5622
|
-
onConsentRequest,
|
|
5623
|
-
autoStart = true
|
|
5624
|
-
} = options;
|
|
5625
|
-
const [isEnabled] = React2.useState(screenshot || consoleCapture || network);
|
|
5626
|
-
const [activeCaptures, setActiveCaptures] = React2.useState({
|
|
5627
|
-
console: false,
|
|
5628
|
-
network: false
|
|
5629
|
-
});
|
|
5630
|
-
const [pendingConsent, setPendingConsent] = React2.useState(null);
|
|
5631
|
-
const consentResolverRef = React2.useRef(null);
|
|
5632
|
-
const rememberedConsentRef = React2.useRef(/* @__PURE__ */ new Set());
|
|
5633
|
-
React2.useEffect(() => {
|
|
5634
|
-
if (!autoStart || !isEnabled) return;
|
|
5635
|
-
if (consoleCapture && !chunkB4YDIMP3_cjs.isConsoleCaptureActive()) {
|
|
5636
|
-
chunkB4YDIMP3_cjs.startConsoleCapture(consoleOptions);
|
|
5637
|
-
setActiveCaptures((prev) => ({ ...prev, console: true }));
|
|
5638
|
-
}
|
|
5639
|
-
if (network && !chunkB4YDIMP3_cjs.isNetworkCaptureActive()) {
|
|
5640
|
-
chunkB4YDIMP3_cjs.startNetworkCapture(networkOptions);
|
|
5641
|
-
setActiveCaptures((prev) => ({ ...prev, network: true }));
|
|
5642
|
-
}
|
|
5643
|
-
return () => {
|
|
5644
|
-
chunkB4YDIMP3_cjs.stopConsoleCapture();
|
|
5645
|
-
chunkB4YDIMP3_cjs.stopNetworkCapture();
|
|
5646
|
-
};
|
|
5647
|
-
}, [
|
|
5648
|
-
autoStart,
|
|
5649
|
-
isEnabled,
|
|
5650
|
-
consoleCapture,
|
|
5651
|
-
network,
|
|
5652
|
-
consoleOptions,
|
|
5653
|
-
networkOptions
|
|
5654
|
-
]);
|
|
5655
|
-
const captureScreenshotFn = React2.useCallback(
|
|
5656
|
-
async (opts) => {
|
|
5657
|
-
if (!screenshot) {
|
|
5658
|
-
throw new Error("Screenshot capture is not enabled");
|
|
5659
|
-
}
|
|
5660
|
-
if (!chunkB4YDIMP3_cjs.isScreenshotSupported()) {
|
|
5661
|
-
throw new Error(
|
|
5662
|
-
"Screenshot capture is not supported in this environment"
|
|
5663
|
-
);
|
|
5664
|
-
}
|
|
5665
|
-
return chunkB4YDIMP3_cjs.captureScreenshot({ ...screenshotOptions, ...opts });
|
|
5666
|
-
},
|
|
5667
|
-
[screenshot, screenshotOptions]
|
|
5668
|
-
);
|
|
5669
|
-
const getConsoleLogsFn = React2.useCallback(
|
|
5670
|
-
(opts) => {
|
|
5671
|
-
if (!consoleCapture) {
|
|
5672
|
-
return { logs: [], totalCaptured: 0 };
|
|
5673
|
-
}
|
|
5674
|
-
return chunkB4YDIMP3_cjs.getConsoleLogs({ ...consoleOptions, ...opts });
|
|
5675
|
-
},
|
|
5676
|
-
[consoleCapture, consoleOptions]
|
|
5677
|
-
);
|
|
5678
|
-
const getNetworkRequestsFn = React2.useCallback(
|
|
5679
|
-
(opts) => {
|
|
5680
|
-
if (!network) {
|
|
5681
|
-
return { requests: [], totalCaptured: 0 };
|
|
5682
|
-
}
|
|
5683
|
-
return chunkB4YDIMP3_cjs.getNetworkRequests({ ...networkOptions, ...opts });
|
|
5684
|
-
},
|
|
5685
|
-
[network, networkOptions]
|
|
5686
|
-
);
|
|
5687
|
-
const requestConsent = React2.useCallback(
|
|
5688
|
-
async (tools, reason = "") => {
|
|
5689
|
-
const enabledTools = tools.filter((tool2) => {
|
|
5690
|
-
if (tool2 === "screenshot") return screenshot;
|
|
5691
|
-
if (tool2 === "console") return consoleCapture;
|
|
5692
|
-
if (tool2 === "network") return network;
|
|
5693
|
-
return false;
|
|
5694
|
-
});
|
|
5695
|
-
if (enabledTools.length === 0) {
|
|
5696
|
-
return { approved: [], denied: [] };
|
|
5697
|
-
}
|
|
5698
|
-
if (!requireConsent) {
|
|
5699
|
-
return { approved: enabledTools, denied: [] };
|
|
5700
|
-
}
|
|
5701
|
-
const needsConsent = enabledTools.filter(
|
|
5702
|
-
(tool2) => !rememberedConsentRef.current.has(tool2)
|
|
5703
|
-
);
|
|
5704
|
-
if (needsConsent.length === 0) {
|
|
5705
|
-
return { approved: enabledTools, denied: [] };
|
|
5706
|
-
}
|
|
5707
|
-
const request = {
|
|
5708
|
-
tools: needsConsent,
|
|
5709
|
-
reason,
|
|
5710
|
-
keywords: []
|
|
5711
|
-
};
|
|
5712
|
-
if (onConsentRequest) {
|
|
5713
|
-
const response = await onConsentRequest(request);
|
|
5714
|
-
if (response.remember) {
|
|
5715
|
-
response.approved.forEach(
|
|
5716
|
-
(tool2) => rememberedConsentRef.current.add(tool2)
|
|
5717
|
-
);
|
|
5718
|
-
}
|
|
5719
|
-
return response;
|
|
5720
|
-
}
|
|
5721
|
-
return new Promise((resolve) => {
|
|
5722
|
-
setPendingConsent(request);
|
|
5723
|
-
consentResolverRef.current = (response) => {
|
|
5724
|
-
if (response.remember) {
|
|
5725
|
-
response.approved.forEach(
|
|
5726
|
-
(tool2) => rememberedConsentRef.current.add(tool2)
|
|
5727
|
-
);
|
|
5728
|
-
}
|
|
5729
|
-
resolve(response);
|
|
5730
|
-
};
|
|
5731
|
-
});
|
|
5732
|
-
},
|
|
5733
|
-
[screenshot, consoleCapture, network, requireConsent, onConsentRequest]
|
|
5734
|
-
);
|
|
5735
|
-
const respondToConsent = React2.useCallback((response) => {
|
|
5736
|
-
if (consentResolverRef.current) {
|
|
5737
|
-
consentResolverRef.current(response);
|
|
5738
|
-
consentResolverRef.current = null;
|
|
5739
|
-
}
|
|
5740
|
-
setPendingConsent(null);
|
|
5741
|
-
}, []);
|
|
5742
|
-
const captureContext = React2.useCallback(
|
|
5743
|
-
async (tools) => {
|
|
5744
|
-
const toolsToCapture = tools || ["screenshot", "console", "network"];
|
|
5745
|
-
const context = {
|
|
5746
|
-
timestamp: Date.now()
|
|
5747
|
-
};
|
|
5748
|
-
const captures = [];
|
|
5749
|
-
if (toolsToCapture.includes("screenshot") && screenshot) {
|
|
5750
|
-
captures.push(
|
|
5751
|
-
captureScreenshotFn().then((result) => {
|
|
5752
|
-
context.screenshot = result;
|
|
5753
|
-
}).catch(() => {
|
|
5754
|
-
})
|
|
5755
|
-
);
|
|
5756
|
-
}
|
|
5757
|
-
if (toolsToCapture.includes("console") && consoleCapture) {
|
|
5758
|
-
context.consoleLogs = getConsoleLogsFn();
|
|
5759
|
-
}
|
|
5760
|
-
if (toolsToCapture.includes("network") && network) {
|
|
5761
|
-
context.networkRequests = getNetworkRequestsFn();
|
|
5762
|
-
}
|
|
5763
|
-
await Promise.all(captures);
|
|
5764
|
-
return context;
|
|
5765
|
-
},
|
|
5766
|
-
[
|
|
5767
|
-
screenshot,
|
|
5768
|
-
consoleCapture,
|
|
5769
|
-
network,
|
|
5770
|
-
captureScreenshotFn,
|
|
5771
|
-
getConsoleLogsFn,
|
|
5772
|
-
getNetworkRequestsFn
|
|
5773
|
-
]
|
|
5774
|
-
);
|
|
5775
|
-
const startCapturing = React2.useCallback(() => {
|
|
5776
|
-
if (consoleCapture && !chunkB4YDIMP3_cjs.isConsoleCaptureActive()) {
|
|
5777
|
-
chunkB4YDIMP3_cjs.startConsoleCapture(consoleOptions);
|
|
5778
|
-
setActiveCaptures((prev) => ({ ...prev, console: true }));
|
|
5779
|
-
}
|
|
5780
|
-
if (network && !chunkB4YDIMP3_cjs.isNetworkCaptureActive()) {
|
|
5781
|
-
chunkB4YDIMP3_cjs.startNetworkCapture(networkOptions);
|
|
5782
|
-
setActiveCaptures((prev) => ({ ...prev, network: true }));
|
|
5783
|
-
}
|
|
5784
|
-
}, [consoleCapture, network, consoleOptions, networkOptions]);
|
|
5785
|
-
const stopCapturing = React2.useCallback(() => {
|
|
5786
|
-
chunkB4YDIMP3_cjs.stopConsoleCapture();
|
|
5787
|
-
chunkB4YDIMP3_cjs.stopNetworkCapture();
|
|
5788
|
-
setActiveCaptures({ console: false, network: false });
|
|
5789
|
-
}, []);
|
|
5790
|
-
const clearCaptured = React2.useCallback(() => {
|
|
5791
|
-
chunkB4YDIMP3_cjs.clearConsoleLogs();
|
|
5792
|
-
chunkB4YDIMP3_cjs.clearNetworkRequests();
|
|
5793
|
-
}, []);
|
|
5794
|
-
const formatForAI = React2.useCallback((context) => {
|
|
5795
|
-
const parts = [];
|
|
5796
|
-
if (context.screenshot) {
|
|
5797
|
-
parts.push(
|
|
5798
|
-
`Screenshot captured (${context.screenshot.width}x${context.screenshot.height}, ${context.screenshot.format})`
|
|
5799
|
-
);
|
|
5800
|
-
}
|
|
5801
|
-
if (context.consoleLogs && context.consoleLogs.logs.length > 0) {
|
|
5802
|
-
parts.push(chunkB4YDIMP3_cjs.formatLogsForAI(context.consoleLogs.logs));
|
|
5803
|
-
}
|
|
5804
|
-
if (context.networkRequests && context.networkRequests.requests.length > 0) {
|
|
5805
|
-
parts.push(chunkB4YDIMP3_cjs.formatRequestsForAI(context.networkRequests.requests));
|
|
5806
|
-
}
|
|
5807
|
-
return parts.length > 0 ? parts.join("\n\n---\n\n") : "No context captured.";
|
|
5808
|
-
}, []);
|
|
5809
|
-
const detectIntentFn = React2.useCallback(
|
|
5810
|
-
(message) => {
|
|
5811
|
-
const result = chunkB4YDIMP3_cjs.detectIntent(message);
|
|
5812
|
-
result.suggestedTools = result.suggestedTools.filter((tool2) => {
|
|
5813
|
-
if (tool2 === "screenshot") return screenshot;
|
|
5814
|
-
if (tool2 === "console") return consoleCapture;
|
|
5815
|
-
if (tool2 === "network") return network;
|
|
5816
|
-
return false;
|
|
5817
|
-
});
|
|
5818
|
-
return result;
|
|
5819
|
-
},
|
|
5820
|
-
[screenshot, consoleCapture, network]
|
|
5821
|
-
);
|
|
5822
|
-
return React2.useMemo(
|
|
5823
|
-
() => ({
|
|
5824
|
-
isEnabled,
|
|
5825
|
-
activeCaptures,
|
|
5826
|
-
captureScreenshot: captureScreenshotFn,
|
|
5827
|
-
getConsoleLogs: getConsoleLogsFn,
|
|
5828
|
-
getNetworkRequests: getNetworkRequestsFn,
|
|
5829
|
-
captureContext,
|
|
5830
|
-
detectIntent: detectIntentFn,
|
|
5831
|
-
requestConsent,
|
|
5832
|
-
startCapturing,
|
|
5833
|
-
stopCapturing,
|
|
5834
|
-
clearCaptured,
|
|
5835
|
-
formatForAI,
|
|
5836
|
-
pendingConsent,
|
|
5837
|
-
respondToConsent
|
|
5838
|
-
}),
|
|
5839
|
-
[
|
|
5840
|
-
isEnabled,
|
|
5841
|
-
activeCaptures,
|
|
5842
|
-
captureScreenshotFn,
|
|
5843
|
-
getConsoleLogsFn,
|
|
5844
|
-
getNetworkRequestsFn,
|
|
5845
|
-
captureContext,
|
|
5846
|
-
detectIntentFn,
|
|
5847
|
-
requestConsent,
|
|
5848
|
-
startCapturing,
|
|
5849
|
-
stopCapturing,
|
|
5850
|
-
clearCaptured,
|
|
5851
|
-
formatForAI,
|
|
5852
|
-
pendingConsent,
|
|
5853
|
-
respondToConsent
|
|
5854
|
-
]
|
|
5855
|
-
);
|
|
5856
|
-
}
|
|
5857
|
-
function convertZodSchema(schema, _toolName) {
|
|
5858
|
-
try {
|
|
5859
|
-
const zodWithJsonSchema = z__namespace;
|
|
5860
|
-
if (typeof zodWithJsonSchema.toJSONSchema === "function") {
|
|
5861
|
-
const jsonSchema = zodWithJsonSchema.toJSONSchema(
|
|
5862
|
-
schema
|
|
5863
|
-
);
|
|
5864
|
-
if (jsonSchema.type === "object") {
|
|
5865
|
-
return {
|
|
5866
|
-
type: "object",
|
|
5867
|
-
properties: jsonSchema.properties || {},
|
|
5868
|
-
required: jsonSchema.required
|
|
5869
|
-
};
|
|
5870
|
-
}
|
|
5871
|
-
}
|
|
5872
|
-
} catch {
|
|
5873
|
-
}
|
|
5874
|
-
return chunkB4YDIMP3_cjs.zodObjectToInputSchema(schema);
|
|
5875
|
-
}
|
|
5876
|
-
function useToolWithSchema(config, dependencies = []) {
|
|
5877
|
-
const { registerTool, unregisterTool } = useCopilot();
|
|
5878
|
-
const configRef = React2.useRef(config);
|
|
5879
|
-
configRef.current = config;
|
|
5880
|
-
const inputSchema = React2.useMemo(() => {
|
|
5881
|
-
try {
|
|
5882
|
-
return convertZodSchema(config.schema, config.name);
|
|
5883
|
-
} catch (error) {
|
|
5884
|
-
console.warn(
|
|
5885
|
-
`[useToolWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
|
|
5886
|
-
error
|
|
5887
|
-
);
|
|
5888
|
-
return {
|
|
5889
|
-
type: "object",
|
|
5890
|
-
properties: {}
|
|
5891
|
-
};
|
|
5892
|
-
}
|
|
5893
|
-
}, [config.schema, config.name]);
|
|
5894
|
-
React2.useEffect(() => {
|
|
5895
|
-
const tool2 = {
|
|
5896
|
-
name: config.name,
|
|
5897
|
-
description: config.description,
|
|
5898
|
-
location: "client",
|
|
5899
|
-
inputSchema,
|
|
5900
|
-
handler: async (params, context) => {
|
|
5901
|
-
return configRef.current.handler(params, context);
|
|
5902
|
-
},
|
|
5903
|
-
render: config.render,
|
|
5904
|
-
available: config.available ?? true
|
|
5905
|
-
};
|
|
5906
|
-
registerTool(tool2);
|
|
5907
|
-
return () => {
|
|
5908
|
-
unregisterTool(config.name);
|
|
5909
|
-
};
|
|
5910
|
-
}, [config.name, inputSchema, ...dependencies]);
|
|
5911
|
-
}
|
|
5912
|
-
function useToolsWithSchema(tools, dependencies = []) {
|
|
5913
|
-
const { registerTool, unregisterTool } = useCopilot();
|
|
5914
|
-
const toolsRef = React2.useRef(tools);
|
|
5915
|
-
toolsRef.current = tools;
|
|
5916
|
-
React2.useEffect(() => {
|
|
5917
|
-
const toolNames = [];
|
|
5918
|
-
for (const config of tools) {
|
|
5919
|
-
let inputSchema;
|
|
5920
|
-
try {
|
|
5921
|
-
inputSchema = convertZodSchema(config.schema, config.name);
|
|
5922
|
-
} catch (error) {
|
|
5923
|
-
console.warn(
|
|
5924
|
-
`[useToolsWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
|
|
5925
|
-
error
|
|
5926
|
-
);
|
|
5927
|
-
inputSchema = { type: "object", properties: {} };
|
|
5928
|
-
}
|
|
5929
|
-
const tool2 = {
|
|
5930
|
-
name: config.name,
|
|
5931
|
-
description: config.description,
|
|
5932
|
-
location: "client",
|
|
5933
|
-
inputSchema,
|
|
5934
|
-
handler: async (params, context) => {
|
|
5935
|
-
const currentConfig = toolsRef.current.find(
|
|
5936
|
-
(t) => t.name === config.name
|
|
5937
|
-
);
|
|
5938
|
-
if (currentConfig) {
|
|
5939
|
-
return currentConfig.handler(params, context);
|
|
5940
|
-
}
|
|
5941
|
-
return { success: false, error: "Tool handler not found" };
|
|
5942
|
-
},
|
|
5943
|
-
available: config.available ?? true
|
|
5944
|
-
};
|
|
5945
|
-
registerTool(tool2);
|
|
5946
|
-
toolNames.push(config.name);
|
|
5947
|
-
}
|
|
5948
|
-
return () => {
|
|
5949
|
-
for (const name of toolNames) {
|
|
5950
|
-
unregisterTool(name);
|
|
5951
|
-
}
|
|
5952
|
-
};
|
|
5953
|
-
}, [tools.map((t) => t.name).join(","), ...dependencies]);
|
|
5954
|
-
}
|
|
5955
|
-
var CopilotContext2 = React2.createContext(null);
|
|
5956
|
-
function useCopilotContext() {
|
|
5957
|
-
const context = React2.useContext(CopilotContext2);
|
|
5958
|
-
if (!context) {
|
|
5959
|
-
throw new Error("useCopilotContext must be used within a CopilotProvider");
|
|
5960
|
-
}
|
|
5961
|
-
return context;
|
|
5962
|
-
}
|
|
5963
|
-
|
|
5964
|
-
// src/react/hooks/useToolExecutor.ts
|
|
5965
|
-
function useToolExecutor() {
|
|
5966
|
-
const {
|
|
5967
|
-
registeredTools,
|
|
5968
|
-
config,
|
|
5969
|
-
chat,
|
|
5970
|
-
addToolExecution,
|
|
5971
|
-
updateToolExecution
|
|
5972
|
-
} = useCopilotContext();
|
|
5973
|
-
const toolsRef = React2.useRef(registeredTools);
|
|
5974
|
-
toolsRef.current = registeredTools;
|
|
5975
|
-
const executeTool = React2.useCallback(
|
|
5976
|
-
async (toolCall) => {
|
|
5977
|
-
const tool2 = toolsRef.current.find((t) => t.name === toolCall.name);
|
|
5978
|
-
if (!tool2) {
|
|
5979
|
-
return {
|
|
5980
|
-
success: false,
|
|
5981
|
-
error: `Unknown tool: ${toolCall.name}`
|
|
5982
|
-
};
|
|
5983
|
-
}
|
|
5984
|
-
if (!tool2.handler) {
|
|
5985
|
-
return {
|
|
5986
|
-
success: false,
|
|
5987
|
-
error: `Tool "${toolCall.name}" has no handler`
|
|
5988
|
-
};
|
|
5989
|
-
}
|
|
5990
|
-
const execution = {
|
|
5991
|
-
id: toolCall.id,
|
|
5992
|
-
name: toolCall.name,
|
|
5993
|
-
args: toolCall.input,
|
|
5994
|
-
status: "executing",
|
|
5995
|
-
timestamp: Date.now(),
|
|
5996
|
-
approvalStatus: "none",
|
|
5997
|
-
hidden: tool2.hidden
|
|
5998
|
-
};
|
|
5999
|
-
addToolExecution?.(execution);
|
|
6000
|
-
try {
|
|
6001
|
-
const startTime = Date.now();
|
|
6002
|
-
const result = await tool2.handler(toolCall.input);
|
|
6003
|
-
const duration = Date.now() - startTime;
|
|
6004
|
-
updateToolExecution?.(toolCall.id, {
|
|
6005
|
-
status: result.success ? "completed" : "error",
|
|
6006
|
-
result,
|
|
6007
|
-
error: result.error,
|
|
6008
|
-
duration
|
|
6009
|
-
});
|
|
6010
|
-
return result;
|
|
6011
|
-
} catch (error) {
|
|
6012
|
-
const errorMessage = error instanceof Error ? error.message : "Tool execution failed";
|
|
6013
|
-
updateToolExecution?.(toolCall.id, {
|
|
6014
|
-
status: "error",
|
|
6015
|
-
error: errorMessage
|
|
6016
|
-
});
|
|
6017
|
-
return {
|
|
6018
|
-
success: false,
|
|
6019
|
-
error: errorMessage
|
|
6020
|
-
};
|
|
6021
|
-
}
|
|
6022
|
-
},
|
|
6023
|
-
[addToolExecution, updateToolExecution]
|
|
6024
|
-
);
|
|
6025
|
-
const sendToolResult = React2.useCallback(
|
|
6026
|
-
async (toolCallId, result) => {
|
|
6027
|
-
const runtimeUrl = config.runtimeUrl || config.cloud?.endpoint;
|
|
6028
|
-
if (!runtimeUrl) {
|
|
6029
|
-
console.warn(
|
|
6030
|
-
"[useToolExecutor] No runtime URL configured, cannot send tool result"
|
|
6031
|
-
);
|
|
6032
|
-
return;
|
|
6033
|
-
}
|
|
6034
|
-
const baseUrl = runtimeUrl.replace(/\/chat\/?$/, "");
|
|
6035
|
-
try {
|
|
6036
|
-
const response = await fetch(`${baseUrl}/tool-result`, {
|
|
6037
|
-
method: "POST",
|
|
6038
|
-
headers: {
|
|
6039
|
-
"Content-Type": "application/json"
|
|
6040
|
-
},
|
|
6041
|
-
body: JSON.stringify({
|
|
6042
|
-
threadId: chat.threadId || "default",
|
|
6043
|
-
toolCallId,
|
|
6044
|
-
result
|
|
6045
|
-
})
|
|
6046
|
-
});
|
|
6047
|
-
if (!response.ok) {
|
|
6048
|
-
console.error(
|
|
6049
|
-
"[useToolExecutor] Failed to send tool result:",
|
|
6050
|
-
await response.text()
|
|
6051
|
-
);
|
|
6052
|
-
}
|
|
6053
|
-
} catch (error) {
|
|
6054
|
-
console.error("[useToolExecutor] Error sending tool result:", error);
|
|
6055
|
-
}
|
|
6056
|
-
},
|
|
6057
|
-
[config.runtimeUrl, config.cloud?.endpoint, chat.threadId]
|
|
6058
|
-
);
|
|
6059
|
-
const getTool = React2.useCallback((name) => {
|
|
6060
|
-
return toolsRef.current.find((t) => t.name === name);
|
|
6061
|
-
}, []);
|
|
6062
|
-
const hasTool = React2.useCallback((name) => {
|
|
6063
|
-
return toolsRef.current.some((t) => t.name === name);
|
|
6064
|
-
}, []);
|
|
6065
|
-
return {
|
|
6066
|
-
executeTool,
|
|
6067
|
-
sendToolResult,
|
|
6068
|
-
getTool,
|
|
6069
|
-
hasTool
|
|
6070
|
-
};
|
|
6071
|
-
}
|
|
6072
|
-
function useSuggestions(options = {}) {
|
|
6073
|
-
const {
|
|
6074
|
-
count = 3,
|
|
6075
|
-
context,
|
|
6076
|
-
suggestions: staticSuggestions,
|
|
6077
|
-
autoRefresh = true
|
|
6078
|
-
} = options;
|
|
6079
|
-
const { chat, actions, config } = useCopilotContext();
|
|
6080
|
-
const [suggestions, setSuggestions] = React2.useState([]);
|
|
6081
|
-
const [isLoading, setIsLoading] = React2.useState(false);
|
|
6082
|
-
const normalizedStatic = React2.useMemo(
|
|
6083
|
-
() => staticSuggestions?.map((s) => typeof s === "string" ? { text: s } : s),
|
|
6084
|
-
[staticSuggestions]
|
|
6085
|
-
);
|
|
6086
|
-
const refresh = React2.useCallback(async () => {
|
|
6087
|
-
if (normalizedStatic) {
|
|
6088
|
-
setSuggestions(normalizedStatic.slice(0, count));
|
|
6089
|
-
return;
|
|
6090
|
-
}
|
|
6091
|
-
if (!config.cloud) {
|
|
6092
|
-
return;
|
|
6093
|
-
}
|
|
6094
|
-
setIsLoading(true);
|
|
6095
|
-
try {
|
|
6096
|
-
const endpoint = config.cloud.endpoint || "https://api.yourgpt.ai/v1";
|
|
6097
|
-
const response = await fetch(`${endpoint}/suggestions`, {
|
|
6098
|
-
method: "POST",
|
|
6099
|
-
headers: {
|
|
6100
|
-
"Content-Type": "application/json",
|
|
6101
|
-
Authorization: `Bearer ${config.cloud.apiKey}`
|
|
6102
|
-
},
|
|
6103
|
-
body: JSON.stringify({
|
|
6104
|
-
botId: config.cloud.botId,
|
|
6105
|
-
count,
|
|
6106
|
-
context,
|
|
6107
|
-
messages: chat.messages.slice(-5)
|
|
6108
|
-
// Last 5 messages for context
|
|
6109
|
-
})
|
|
6110
|
-
});
|
|
6111
|
-
if (response.ok) {
|
|
6112
|
-
const data = await response.json();
|
|
6113
|
-
setSuggestions(
|
|
6114
|
-
data.suggestions.map(
|
|
6115
|
-
(s) => typeof s === "string" ? { text: s } : s
|
|
6116
|
-
)
|
|
6117
|
-
);
|
|
6118
|
-
}
|
|
6119
|
-
} catch (error) {
|
|
6120
|
-
console.error("Failed to fetch suggestions:", error);
|
|
6121
|
-
} finally {
|
|
6122
|
-
setIsLoading(false);
|
|
6123
|
-
}
|
|
6124
|
-
}, [config.cloud, count, context, chat.messages, normalizedStatic]);
|
|
6125
|
-
const select = React2.useCallback(
|
|
6126
|
-
(suggestion) => {
|
|
6127
|
-
const text = typeof suggestion === "string" ? suggestion : suggestion.text;
|
|
6128
|
-
actions.sendMessage(text);
|
|
6129
|
-
},
|
|
6130
|
-
[actions]
|
|
6131
|
-
);
|
|
6132
|
-
React2.useEffect(() => {
|
|
6133
|
-
if (autoRefresh && chat.messages.length === 0) {
|
|
6134
|
-
refresh();
|
|
6135
|
-
}
|
|
6136
|
-
}, [autoRefresh, chat.messages.length, refresh]);
|
|
6137
|
-
return {
|
|
6138
|
-
suggestions: normalizedStatic?.slice(0, count) || suggestions,
|
|
6139
|
-
isLoading,
|
|
6140
|
-
refresh,
|
|
6141
|
-
select
|
|
6142
|
-
};
|
|
6143
|
-
}
|
|
6144
|
-
function useAgent(options) {
|
|
6145
|
-
const { name, initialState = {}, onStateChange } = options;
|
|
6146
|
-
const { config } = useCopilotContext();
|
|
6147
|
-
const [state, setStateInternal] = React2.useState(initialState);
|
|
6148
|
-
const [isRunning, setIsRunning] = React2.useState(false);
|
|
6149
|
-
const [nodeName, setNodeName] = React2.useState(null);
|
|
6150
|
-
const [error, setError] = React2.useState(null);
|
|
6151
|
-
const abortControllerRef = React2.useRef(null);
|
|
6152
|
-
const getEndpoint = React2.useCallback(() => {
|
|
6153
|
-
if (config.cloud) {
|
|
6154
|
-
return `${config.cloud.endpoint || "https://api.yourgpt.ai/v1"}/agents/${name}`;
|
|
6155
|
-
}
|
|
6156
|
-
return `${config.runtimeUrl || "/api"}/agents/${name}`;
|
|
6157
|
-
}, [config, name]);
|
|
6158
|
-
const start = React2.useCallback(
|
|
6159
|
-
async (input) => {
|
|
6160
|
-
setIsRunning(true);
|
|
6161
|
-
setError(null);
|
|
6162
|
-
abortControllerRef.current = new AbortController();
|
|
6163
|
-
try {
|
|
6164
|
-
const endpoint = getEndpoint();
|
|
6165
|
-
const headers = {
|
|
6166
|
-
"Content-Type": "application/json"
|
|
6167
|
-
};
|
|
6168
|
-
if (config.cloud?.apiKey) {
|
|
6169
|
-
headers["Authorization"] = `Bearer ${config.cloud.apiKey}`;
|
|
6170
|
-
}
|
|
6171
|
-
const response = await fetch(`${endpoint}/start`, {
|
|
6172
|
-
method: "POST",
|
|
6173
|
-
headers,
|
|
6174
|
-
body: JSON.stringify({
|
|
6175
|
-
input: typeof input === "string" ? { message: input } : input,
|
|
6176
|
-
state
|
|
6177
|
-
}),
|
|
6178
|
-
signal: abortControllerRef.current.signal
|
|
6179
|
-
});
|
|
6180
|
-
if (!response.ok) {
|
|
6181
|
-
throw new Error(`Agent error: ${response.status}`);
|
|
6182
|
-
}
|
|
6183
|
-
for await (const event of chunkB4YDIMP3_cjs.streamSSE(response)) {
|
|
6184
|
-
handleAgentEvent(event);
|
|
6185
|
-
}
|
|
6186
|
-
} catch (err) {
|
|
6187
|
-
if (err.name !== "AbortError") {
|
|
6188
|
-
setError(err instanceof Error ? err : new Error("Unknown error"));
|
|
6189
|
-
}
|
|
6190
|
-
} finally {
|
|
6191
|
-
setIsRunning(false);
|
|
6192
|
-
abortControllerRef.current = null;
|
|
6193
|
-
}
|
|
6194
|
-
},
|
|
6195
|
-
[config, getEndpoint, state]
|
|
6196
|
-
);
|
|
6197
|
-
const handleAgentEvent = React2.useCallback(
|
|
6198
|
-
(event) => {
|
|
6199
|
-
if (event.type === "error") {
|
|
6200
|
-
setError(new Error(event.message));
|
|
6201
|
-
return;
|
|
6202
|
-
}
|
|
6203
|
-
if ("state" in event && event.state) {
|
|
6204
|
-
setStateInternal(event.state);
|
|
6205
|
-
onStateChange?.(event.state);
|
|
6206
|
-
}
|
|
6207
|
-
if ("nodeName" in event && event.nodeName) {
|
|
6208
|
-
setNodeName(event.nodeName);
|
|
6209
|
-
}
|
|
6210
|
-
},
|
|
6211
|
-
[onStateChange]
|
|
6212
|
-
);
|
|
6213
|
-
const stop = React2.useCallback(() => {
|
|
6214
|
-
abortControllerRef.current?.abort();
|
|
6215
|
-
}, []);
|
|
6216
|
-
const setState = React2.useCallback(
|
|
6217
|
-
(partialState) => {
|
|
6218
|
-
setStateInternal((prev) => {
|
|
6219
|
-
const newState = { ...prev, ...partialState };
|
|
6220
|
-
onStateChange?.(newState);
|
|
6221
|
-
return newState;
|
|
6222
|
-
});
|
|
6223
|
-
},
|
|
6224
|
-
[onStateChange]
|
|
6225
|
-
);
|
|
6226
|
-
React2.useEffect(() => {
|
|
6227
|
-
return () => {
|
|
6228
|
-
abortControllerRef.current?.abort();
|
|
6229
|
-
};
|
|
6230
|
-
}, []);
|
|
6231
|
-
return {
|
|
6232
|
-
state,
|
|
6233
|
-
isRunning,
|
|
6234
|
-
nodeName,
|
|
6235
|
-
start,
|
|
6236
|
-
stop,
|
|
6237
|
-
setState,
|
|
6238
|
-
error
|
|
6239
|
-
};
|
|
6240
|
-
}
|
|
6241
|
-
|
|
6242
|
-
// src/react/utils/knowledge-base.ts
|
|
6243
|
-
var KNOWLEDGE_BASE_API = "https://api.yourgpt.ai/chatbot/v1/searchIndexDocument";
|
|
6244
|
-
async function searchKnowledgeBase(query, config) {
|
|
6245
|
-
try {
|
|
6246
|
-
const response = await fetch(KNOWLEDGE_BASE_API, {
|
|
6247
|
-
method: "POST",
|
|
6248
|
-
headers: {
|
|
6249
|
-
accept: "*/*",
|
|
6250
|
-
"content-type": "application/json",
|
|
6251
|
-
authorization: `Bearer ${config.token}`
|
|
6252
|
-
},
|
|
6253
|
-
body: JSON.stringify({
|
|
6254
|
-
project_uid: config.projectUid,
|
|
6255
|
-
query,
|
|
6256
|
-
page: 1,
|
|
6257
|
-
limit: String(config.limit || 10),
|
|
6258
|
-
app_id: config.appId || "1"
|
|
6259
|
-
})
|
|
6260
|
-
});
|
|
6261
|
-
if (!response.ok) {
|
|
6262
|
-
return {
|
|
6263
|
-
success: false,
|
|
6264
|
-
results: [],
|
|
6265
|
-
error: `API error: ${response.status} ${response.statusText}`
|
|
6266
|
-
};
|
|
6267
|
-
}
|
|
6268
|
-
const data = await response.json();
|
|
6269
|
-
const results = (data.data || data.results || []).map((item) => ({
|
|
6270
|
-
id: item.id || item._id || String(Math.random()),
|
|
6271
|
-
title: item.title || item.name || void 0,
|
|
6272
|
-
content: item.content || item.text || item.snippet || "",
|
|
6273
|
-
score: item.score || item.relevance || void 0,
|
|
6274
|
-
url: item.url || item.source_url || void 0,
|
|
6275
|
-
metadata: item.metadata || {}
|
|
6276
|
-
}));
|
|
6277
|
-
return {
|
|
6278
|
-
success: true,
|
|
6279
|
-
results,
|
|
6280
|
-
total: data.total || results.length,
|
|
6281
|
-
page: data.page || 1
|
|
6282
|
-
};
|
|
6283
|
-
} catch (error) {
|
|
6284
|
-
return {
|
|
6285
|
-
success: false,
|
|
6286
|
-
results: [],
|
|
6287
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
6288
|
-
};
|
|
6289
|
-
}
|
|
6290
|
-
}
|
|
6291
|
-
function formatKnowledgeResultsForAI(results) {
|
|
6292
|
-
if (results.length === 0) {
|
|
6293
|
-
return "No relevant documents found in the knowledge base.";
|
|
6294
|
-
}
|
|
6295
|
-
return results.map((result, index) => {
|
|
6296
|
-
const parts = [`[${index + 1}]`];
|
|
6297
|
-
if (result.title) parts.push(`**${result.title}**`);
|
|
6298
|
-
parts.push(result.content);
|
|
6299
|
-
if (result.url) parts.push(`Source: ${result.url}`);
|
|
6300
|
-
return parts.join("\n");
|
|
6301
|
-
}).join("\n\n---\n\n");
|
|
6302
|
-
}
|
|
6303
|
-
|
|
6304
|
-
// src/react/hooks/useKnowledgeBase.ts
|
|
6305
|
-
function useKnowledgeBase(config) {
|
|
6306
|
-
const { registerTool, unregisterTool } = useCopilot();
|
|
6307
|
-
const configRef = React2.useRef(config);
|
|
6308
|
-
configRef.current = config;
|
|
6309
|
-
const handleSearch = React2.useCallback(
|
|
6310
|
-
async (params) => {
|
|
6311
|
-
const query = params.query;
|
|
6312
|
-
if (!query) {
|
|
6313
|
-
return {
|
|
6314
|
-
success: false,
|
|
6315
|
-
error: "Query is required"
|
|
6316
|
-
};
|
|
6317
|
-
}
|
|
6318
|
-
const currentConfig = configRef.current;
|
|
6319
|
-
const kbConfig = {
|
|
6320
|
-
projectUid: currentConfig.projectUid,
|
|
6321
|
-
token: currentConfig.token,
|
|
6322
|
-
appId: currentConfig.appId,
|
|
6323
|
-
limit: currentConfig.limit || 5
|
|
6324
|
-
};
|
|
6325
|
-
const response = await searchKnowledgeBase(
|
|
6326
|
-
query,
|
|
6327
|
-
kbConfig
|
|
6328
|
-
);
|
|
6329
|
-
if (!response.success) {
|
|
6330
|
-
return {
|
|
6331
|
-
success: false,
|
|
6332
|
-
error: response.error || "Knowledge base search failed"
|
|
6333
|
-
};
|
|
6334
|
-
}
|
|
6335
|
-
const formattedResults = formatKnowledgeResultsForAI(response.results);
|
|
6336
|
-
return {
|
|
6337
|
-
success: true,
|
|
6338
|
-
message: formattedResults,
|
|
6339
|
-
data: {
|
|
6340
|
-
resultCount: response.results.length,
|
|
6341
|
-
total: response.total
|
|
6342
|
-
}
|
|
6343
|
-
};
|
|
6344
|
-
},
|
|
6345
|
-
[]
|
|
6346
|
-
);
|
|
6347
|
-
React2.useEffect(() => {
|
|
6348
|
-
if (config.enabled === false) {
|
|
6349
|
-
return;
|
|
6350
|
-
}
|
|
6351
|
-
registerTool({
|
|
6352
|
-
name: "search_knowledge",
|
|
6353
|
-
description: "Search the knowledge base for relevant information about the product, documentation, or company. Use this to answer questions about features, pricing, policies, guides, or any factual information.",
|
|
6354
|
-
location: "client",
|
|
6355
|
-
inputSchema: {
|
|
6356
|
-
type: "object",
|
|
6357
|
-
properties: {
|
|
6358
|
-
query: {
|
|
6359
|
-
type: "string",
|
|
6360
|
-
description: "The search query to find relevant information in the knowledge base"
|
|
6361
|
-
}
|
|
6362
|
-
},
|
|
6363
|
-
required: ["query"]
|
|
6364
|
-
},
|
|
6365
|
-
handler: handleSearch
|
|
6366
|
-
});
|
|
6367
|
-
return () => {
|
|
6368
|
-
unregisterTool("search_knowledge");
|
|
6369
|
-
};
|
|
6370
|
-
}, [
|
|
6371
|
-
config.enabled,
|
|
6372
|
-
config.projectUid,
|
|
6373
|
-
config.token,
|
|
6374
|
-
registerTool,
|
|
6375
|
-
unregisterTool,
|
|
6376
|
-
handleSearch
|
|
6377
|
-
]);
|
|
6378
|
-
}
|
|
6379
|
-
var DEFAULT_CAPABILITIES = {
|
|
6380
|
-
supportsVision: false,
|
|
6381
|
-
supportsTools: true,
|
|
6382
|
-
supportsThinking: false,
|
|
6383
|
-
supportsStreaming: true,
|
|
6384
|
-
supportsPDF: false,
|
|
6385
|
-
supportsAudio: false,
|
|
6386
|
-
supportsVideo: false,
|
|
6387
|
-
maxTokens: 8192,
|
|
6388
|
-
supportedImageTypes: [],
|
|
6389
|
-
supportsJsonMode: false,
|
|
6390
|
-
supportsSystemMessages: true
|
|
6391
|
-
};
|
|
6392
|
-
function useCapabilities() {
|
|
6393
|
-
const { config } = useCopilotContext();
|
|
6394
|
-
const [capabilities, setCapabilities] = React2.useState(DEFAULT_CAPABILITIES);
|
|
6395
|
-
const [provider, setProvider] = React2.useState("unknown");
|
|
6396
|
-
const [model, setModel] = React2.useState("unknown");
|
|
6397
|
-
const [supportedModels, setSupportedModels] = React2.useState([]);
|
|
6398
|
-
const [isLoading, setIsLoading] = React2.useState(true);
|
|
6399
|
-
const [error, setError] = React2.useState(null);
|
|
6400
|
-
const capabilitiesUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/chat\/?$/, "/capabilities") : null;
|
|
6401
|
-
const fetchCapabilities = React2.useCallback(async () => {
|
|
6402
|
-
if (!capabilitiesUrl) {
|
|
6403
|
-
setIsLoading(false);
|
|
6404
|
-
return;
|
|
6405
|
-
}
|
|
6406
|
-
try {
|
|
6407
|
-
setIsLoading(true);
|
|
6408
|
-
setError(null);
|
|
6409
|
-
const response = await fetch(capabilitiesUrl);
|
|
6410
|
-
if (!response.ok) {
|
|
6411
|
-
throw new Error(`Failed to fetch capabilities: ${response.status}`);
|
|
6412
|
-
}
|
|
6413
|
-
const data = await response.json();
|
|
6414
|
-
setCapabilities(data.capabilities);
|
|
6415
|
-
setProvider(data.provider);
|
|
6416
|
-
setModel(data.model);
|
|
6417
|
-
setSupportedModels(data.supportedModels);
|
|
6418
|
-
} catch (err) {
|
|
6419
|
-
setError(err instanceof Error ? err : new Error("Unknown error"));
|
|
6420
|
-
} finally {
|
|
6421
|
-
setIsLoading(false);
|
|
6422
|
-
}
|
|
6423
|
-
}, [capabilitiesUrl]);
|
|
6424
|
-
React2.useEffect(() => {
|
|
6425
|
-
fetchCapabilities();
|
|
6426
|
-
}, [fetchCapabilities]);
|
|
6427
|
-
return {
|
|
6428
|
-
/** Current model capabilities */
|
|
6429
|
-
capabilities,
|
|
6430
|
-
/** Current provider name */
|
|
6431
|
-
provider,
|
|
6432
|
-
/** Current model ID */
|
|
6433
|
-
model,
|
|
6434
|
-
/** List of supported models for current provider */
|
|
6435
|
-
supportedModels,
|
|
6436
|
-
/** Whether capabilities are being loaded */
|
|
6437
|
-
isLoading,
|
|
6438
|
-
/** Error if fetch failed */
|
|
6439
|
-
error,
|
|
6440
|
-
/** Refetch capabilities */
|
|
6441
|
-
refetch: fetchCapabilities
|
|
6442
|
-
};
|
|
6443
|
-
}
|
|
6444
|
-
function useFeatureSupport(feature) {
|
|
6445
|
-
const { capabilities } = useCapabilities();
|
|
6446
|
-
return capabilities[feature] ?? false;
|
|
6447
|
-
}
|
|
6448
|
-
function useSupportedMediaTypes() {
|
|
6449
|
-
const { capabilities } = useCapabilities();
|
|
6450
|
-
return {
|
|
6451
|
-
/** Supported image MIME types */
|
|
6452
|
-
imageTypes: capabilities.supportedImageTypes || [],
|
|
6453
|
-
/** Supported audio MIME types */
|
|
6454
|
-
audioTypes: capabilities.supportedAudioTypes || [],
|
|
6455
|
-
/** Supported video MIME types */
|
|
6456
|
-
videoTypes: capabilities.supportedVideoTypes || [],
|
|
6457
|
-
/** Whether any image types are supported */
|
|
6458
|
-
hasImageSupport: (capabilities.supportedImageTypes?.length ?? 0) > 0,
|
|
6459
|
-
/** Whether any audio types are supported */
|
|
6460
|
-
hasAudioSupport: (capabilities.supportedAudioTypes?.length ?? 0) > 0,
|
|
6461
|
-
/** Whether any video types are supported */
|
|
6462
|
-
hasVideoSupport: (capabilities.supportedVideoTypes?.length ?? 0) > 0
|
|
6463
|
-
};
|
|
6464
|
-
}
|
|
6465
|
-
function useDevLogger() {
|
|
6466
|
-
const ctx = useCopilotContext();
|
|
6467
|
-
return React2.useMemo(() => {
|
|
6468
|
-
const toolExecutions = (ctx.agentLoop?.toolExecutions || []).map(
|
|
6469
|
-
(exec) => ({
|
|
6470
|
-
id: exec.id,
|
|
6471
|
-
name: exec.name,
|
|
6472
|
-
status: exec.status,
|
|
6473
|
-
approvalStatus: exec.approvalStatus || "not_required"
|
|
6474
|
-
})
|
|
6475
|
-
);
|
|
6476
|
-
const pendingApprovalsCount = ctx.pendingApprovals?.length || 0;
|
|
6477
|
-
const registeredTools = (ctx.registeredTools || []).map((tool2) => ({
|
|
6478
|
-
name: tool2.name,
|
|
6479
|
-
location: tool2.location || "client"
|
|
6480
|
-
}));
|
|
6481
|
-
const registeredActions = (ctx.registeredActions || []).map((action) => ({
|
|
6482
|
-
name: action.name
|
|
6483
|
-
}));
|
|
6484
|
-
const storedPermissions = (ctx.storedPermissions || []).map((p) => ({
|
|
6485
|
-
toolName: p.toolName,
|
|
6486
|
-
level: p.level
|
|
6487
|
-
}));
|
|
6488
|
-
return {
|
|
6489
|
-
chat: {
|
|
6490
|
-
isLoading: ctx.chat?.isLoading || false,
|
|
6491
|
-
messageCount: ctx.chat?.messages?.length || 0,
|
|
6492
|
-
threadId: ctx.chat?.threadId || "none",
|
|
6493
|
-
error: ctx.chat?.error?.message || null
|
|
6494
|
-
},
|
|
6495
|
-
tools: {
|
|
6496
|
-
isEnabled: !!ctx.toolsConfig,
|
|
6497
|
-
isCapturing: ctx.tools?.isCapturing || false,
|
|
6498
|
-
pendingConsent: !!ctx.tools?.pendingConsent
|
|
6499
|
-
},
|
|
6500
|
-
agentLoop: {
|
|
6501
|
-
toolExecutions,
|
|
6502
|
-
pendingApprovals: pendingApprovalsCount,
|
|
6503
|
-
iteration: ctx.agentLoop?.iteration || 0,
|
|
6504
|
-
maxIterations: ctx.agentLoop?.maxIterations || 10
|
|
6505
|
-
},
|
|
6506
|
-
registered: {
|
|
6507
|
-
tools: registeredTools,
|
|
6508
|
-
actions: registeredActions,
|
|
6509
|
-
contextCount: ctx.contextTree?.length || 0
|
|
6510
|
-
},
|
|
6511
|
-
permissions: {
|
|
6512
|
-
stored: storedPermissions,
|
|
6513
|
-
loaded: ctx.permissionsLoaded || false
|
|
6514
|
-
},
|
|
6515
|
-
config: {
|
|
6516
|
-
runtimeUrl: ctx.config?.runtimeUrl || ctx.config?.cloud?.endpoint || ""
|
|
6517
|
-
}
|
|
6518
|
-
};
|
|
6519
|
-
}, [
|
|
6520
|
-
ctx.chat,
|
|
6521
|
-
ctx.tools,
|
|
6522
|
-
ctx.toolsConfig,
|
|
6523
|
-
ctx.agentLoop,
|
|
6524
|
-
ctx.pendingApprovals,
|
|
6525
|
-
ctx.registeredTools,
|
|
6526
|
-
ctx.registeredActions,
|
|
6527
|
-
ctx.contextTree,
|
|
6528
|
-
ctx.storedPermissions,
|
|
6529
|
-
ctx.permissionsLoaded,
|
|
6530
|
-
ctx.config
|
|
6531
|
-
]);
|
|
6532
|
-
}
|
|
6533
|
-
|
|
6534
|
-
// src/react/internal/ReactThreadManagerState.ts
|
|
6535
|
-
var ReactThreadManagerState = class {
|
|
6536
|
-
constructor(initialThreads) {
|
|
6537
|
-
this._threads = [];
|
|
6538
|
-
this._currentThreadId = null;
|
|
6539
|
-
this._currentThread = null;
|
|
6540
|
-
this._loadStatus = "idle";
|
|
6541
|
-
this._error = void 0;
|
|
6542
|
-
// Callbacks for React subscriptions (useSyncExternalStore)
|
|
6543
|
-
this.subscribers = /* @__PURE__ */ new Set();
|
|
6544
|
-
// ============================================
|
|
6545
|
-
// Subscription (for useSyncExternalStore)
|
|
6546
|
-
// ============================================
|
|
6547
|
-
/**
|
|
6548
|
-
* Subscribe to state changes.
|
|
6549
|
-
* Returns an unsubscribe function.
|
|
6550
|
-
*
|
|
6551
|
-
* @example
|
|
6552
|
-
* ```tsx
|
|
6553
|
-
* const threads = useSyncExternalStore(
|
|
6554
|
-
* state.subscribe,
|
|
6555
|
-
* () => state.threads
|
|
6556
|
-
* );
|
|
6557
|
-
* ```
|
|
6558
|
-
*/
|
|
6559
|
-
this.subscribe = (callback) => {
|
|
6560
|
-
this.subscribers.add(callback);
|
|
6561
|
-
return () => {
|
|
6562
|
-
this.subscribers.delete(callback);
|
|
6563
|
-
};
|
|
6564
|
-
};
|
|
6565
|
-
if (initialThreads) {
|
|
6566
|
-
this._threads = initialThreads;
|
|
6567
|
-
}
|
|
6568
|
-
}
|
|
6569
|
-
// ============================================
|
|
6570
|
-
// Getters
|
|
6571
|
-
// ============================================
|
|
6572
|
-
get threads() {
|
|
6573
|
-
return this._threads;
|
|
6574
|
-
}
|
|
6575
|
-
get currentThreadId() {
|
|
6576
|
-
return this._currentThreadId;
|
|
6577
|
-
}
|
|
6578
|
-
get currentThread() {
|
|
6579
|
-
return this._currentThread;
|
|
6580
|
-
}
|
|
6581
|
-
get loadStatus() {
|
|
6582
|
-
return this._loadStatus;
|
|
6583
|
-
}
|
|
6584
|
-
get error() {
|
|
6585
|
-
return this._error;
|
|
6586
|
-
}
|
|
6587
|
-
// ============================================
|
|
6588
|
-
// Setters (trigger reactivity)
|
|
6589
|
-
// ============================================
|
|
6590
|
-
set threads(value) {
|
|
6591
|
-
this._threads = value;
|
|
6592
|
-
this.notify();
|
|
6593
|
-
}
|
|
6594
|
-
// ============================================
|
|
6595
|
-
// Mutations
|
|
6596
|
-
// ============================================
|
|
6597
|
-
setThreads(threads) {
|
|
6598
|
-
this._threads = threads;
|
|
6599
|
-
this.notify();
|
|
6600
|
-
}
|
|
6601
|
-
setCurrentThread(thread) {
|
|
6602
|
-
this._currentThread = thread;
|
|
6603
|
-
this._currentThreadId = thread?.id ?? null;
|
|
6604
|
-
this.notify();
|
|
6605
|
-
}
|
|
6606
|
-
setCurrentThreadId(id) {
|
|
6607
|
-
this._currentThreadId = id;
|
|
6608
|
-
this.notify();
|
|
6609
|
-
}
|
|
6610
|
-
addThread(thread) {
|
|
6611
|
-
this._threads = [thread, ...this._threads];
|
|
6612
|
-
this.notify();
|
|
6613
|
-
}
|
|
6614
|
-
updateThread(id, updates) {
|
|
6615
|
-
this._threads = this._threads.map(
|
|
6616
|
-
(t) => t.id === id ? { ...t, ...updates } : t
|
|
6617
|
-
);
|
|
6618
|
-
if (updates.updatedAt) {
|
|
6619
|
-
this._threads = [...this._threads].sort(
|
|
6620
|
-
(a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
|
|
6621
|
-
);
|
|
6622
|
-
}
|
|
6623
|
-
if (this._currentThread?.id === id) {
|
|
6624
|
-
this._currentThread = { ...this._currentThread, ...updates };
|
|
6625
|
-
}
|
|
6626
|
-
this.notify();
|
|
6627
|
-
}
|
|
6628
|
-
removeThread(id) {
|
|
6629
|
-
this._threads = this._threads.filter((t) => t.id !== id);
|
|
6630
|
-
if (this._currentThreadId === id) {
|
|
6631
|
-
this._currentThreadId = null;
|
|
6632
|
-
this._currentThread = null;
|
|
6633
|
-
}
|
|
6634
|
-
this.notify();
|
|
6635
|
-
}
|
|
6636
|
-
setLoadStatus(status) {
|
|
6637
|
-
this._loadStatus = status;
|
|
6638
|
-
this.notify();
|
|
6639
|
-
}
|
|
6640
|
-
setError(error) {
|
|
6641
|
-
this._error = error;
|
|
6642
|
-
this.notify();
|
|
6643
|
-
}
|
|
6644
|
-
// ============================================
|
|
6645
|
-
// Snapshots (for useSyncExternalStore)
|
|
6646
|
-
// ============================================
|
|
6647
|
-
getThreadsSnapshot() {
|
|
6648
|
-
return this._threads;
|
|
6649
|
-
}
|
|
6650
|
-
getCurrentThreadSnapshot() {
|
|
6651
|
-
return this._currentThread;
|
|
6652
|
-
}
|
|
6653
|
-
getLoadStatusSnapshot() {
|
|
6654
|
-
return this._loadStatus;
|
|
6655
|
-
}
|
|
6656
|
-
getErrorSnapshot() {
|
|
6657
|
-
return this._error;
|
|
6658
|
-
}
|
|
6659
|
-
// ============================================
|
|
6660
|
-
// Private Methods
|
|
6661
|
-
// ============================================
|
|
6662
|
-
notify() {
|
|
6663
|
-
this.subscribers.forEach((cb) => cb());
|
|
6664
|
-
}
|
|
6665
|
-
/**
|
|
6666
|
-
* Cleanup subscriptions
|
|
6667
|
-
*/
|
|
6668
|
-
dispose() {
|
|
6669
|
-
this.subscribers.clear();
|
|
6670
|
-
}
|
|
6671
|
-
};
|
|
6672
|
-
function createReactThreadManagerState(initialThreads) {
|
|
6673
|
-
return new ReactThreadManagerState(initialThreads);
|
|
6674
|
-
}
|
|
6675
|
-
|
|
6676
|
-
// src/react/internal/ReactThreadManager.ts
|
|
6677
|
-
var _ReactThreadManager = class _ReactThreadManager extends chunkB4YDIMP3_cjs.ThreadManager {
|
|
6678
|
-
constructor(config = {}, callbacks = {}) {
|
|
6679
|
-
const reactState = new ReactThreadManagerState();
|
|
6680
|
-
super({ ...config, state: reactState }, callbacks);
|
|
6681
|
-
// ============================================
|
|
6682
|
-
// Subscription Methods (for useSyncExternalStore)
|
|
6683
|
-
// ============================================
|
|
6684
|
-
/**
|
|
6685
|
-
* Subscribe to state changes
|
|
6686
|
-
* Use with useSyncExternalStore
|
|
6687
|
-
*/
|
|
6688
|
-
this.subscribe = (callback) => {
|
|
6689
|
-
return this.state.subscribe(callback);
|
|
6690
|
-
};
|
|
6691
|
-
// ============================================
|
|
6692
|
-
// Snapshot Getters (for useSyncExternalStore)
|
|
6693
|
-
// ============================================
|
|
6694
|
-
/**
|
|
6695
|
-
* Get threads snapshot
|
|
6696
|
-
*/
|
|
6697
|
-
this.getThreadsSnapshot = () => {
|
|
6698
|
-
return this.state.getThreadsSnapshot();
|
|
6699
|
-
};
|
|
6700
|
-
/**
|
|
6701
|
-
* Get current thread snapshot
|
|
6702
|
-
*/
|
|
6703
|
-
this.getCurrentThreadSnapshot = () => {
|
|
6704
|
-
return this.state.getCurrentThreadSnapshot();
|
|
6705
|
-
};
|
|
6706
|
-
/**
|
|
6707
|
-
* Get current thread ID snapshot
|
|
6708
|
-
*/
|
|
6709
|
-
this.getCurrentThreadIdSnapshot = () => {
|
|
6710
|
-
return this.state.currentThreadId;
|
|
6711
|
-
};
|
|
6712
|
-
/**
|
|
6713
|
-
* Get load status snapshot
|
|
6714
|
-
*/
|
|
6715
|
-
this.getLoadStatusSnapshot = () => {
|
|
6716
|
-
return this.state.getLoadStatusSnapshot();
|
|
6717
|
-
};
|
|
6718
|
-
/**
|
|
6719
|
-
* Get error snapshot
|
|
6720
|
-
*/
|
|
6721
|
-
this.getErrorSnapshot = () => {
|
|
6722
|
-
return this.state.getErrorSnapshot();
|
|
6723
|
-
};
|
|
6724
|
-
/**
|
|
6725
|
-
* Get isLoading snapshot
|
|
6726
|
-
*/
|
|
6727
|
-
this.getIsLoadingSnapshot = () => {
|
|
6728
|
-
return this.state.getLoadStatusSnapshot() === "loading";
|
|
6729
|
-
};
|
|
6730
|
-
/**
|
|
6731
|
-
* Get threads snapshot for server (always empty for hydration consistency)
|
|
6732
|
-
*/
|
|
6733
|
-
this.getThreadsServerSnapshot = () => {
|
|
6734
|
-
return _ReactThreadManager.EMPTY_THREADS;
|
|
6735
|
-
};
|
|
6736
|
-
/**
|
|
6737
|
-
* Get current thread snapshot for server (always null)
|
|
6738
|
-
*/
|
|
6739
|
-
this.getCurrentThreadServerSnapshot = () => {
|
|
6740
|
-
return null;
|
|
6741
|
-
};
|
|
6742
|
-
/**
|
|
6743
|
-
* Get current thread ID snapshot for server (always null)
|
|
6744
|
-
*/
|
|
6745
|
-
this.getCurrentThreadIdServerSnapshot = () => {
|
|
6746
|
-
return null;
|
|
6747
|
-
};
|
|
6748
|
-
/**
|
|
6749
|
-
* Get load status snapshot for server (always "idle")
|
|
6750
|
-
*/
|
|
6751
|
-
this.getLoadStatusServerSnapshot = () => {
|
|
6752
|
-
return _ReactThreadManager.IDLE_STATUS;
|
|
6753
|
-
};
|
|
6754
|
-
/**
|
|
6755
|
-
* Get error snapshot for server (always undefined)
|
|
6756
|
-
*/
|
|
6757
|
-
this.getErrorServerSnapshot = () => {
|
|
6758
|
-
return void 0;
|
|
6759
|
-
};
|
|
6760
|
-
/**
|
|
6761
|
-
* Get isLoading snapshot for server (always false)
|
|
6762
|
-
*/
|
|
6763
|
-
this.getIsLoadingServerSnapshot = () => {
|
|
6764
|
-
return false;
|
|
6765
|
-
};
|
|
6766
|
-
}
|
|
6767
|
-
// ============================================
|
|
6768
|
-
// Cleanup
|
|
6769
|
-
// ============================================
|
|
6770
|
-
/**
|
|
6771
|
-
* Dispose of the manager
|
|
6772
|
-
*/
|
|
6773
|
-
async dispose() {
|
|
6774
|
-
this.state.dispose();
|
|
6775
|
-
await super.dispose();
|
|
6776
|
-
}
|
|
6777
|
-
};
|
|
6778
|
-
// ============================================
|
|
6779
|
-
// Server Snapshots (for SSR - stable cached values)
|
|
6780
|
-
// ============================================
|
|
6781
|
-
// Cached values for server snapshots (must be stable references)
|
|
6782
|
-
_ReactThreadManager.EMPTY_THREADS = [];
|
|
6783
|
-
_ReactThreadManager.IDLE_STATUS = "idle";
|
|
6784
|
-
var ReactThreadManager = _ReactThreadManager;
|
|
6785
|
-
function createReactThreadManager(config, callbacks) {
|
|
6786
|
-
return new ReactThreadManager(config, callbacks);
|
|
6787
|
-
}
|
|
6788
|
-
|
|
6789
|
-
// src/react/hooks/useThreadManager.ts
|
|
6790
|
-
var defaultManager = null;
|
|
6791
|
-
function getDefaultManager() {
|
|
6792
|
-
if (!defaultManager) {
|
|
6793
|
-
defaultManager = createReactThreadManager();
|
|
6794
|
-
}
|
|
6795
|
-
return defaultManager;
|
|
6796
|
-
}
|
|
6797
|
-
var internalManager = null;
|
|
6798
|
-
function getInternalManager(config) {
|
|
6799
|
-
if (!internalManager) {
|
|
6800
|
-
internalManager = createReactThreadManager(
|
|
6801
|
-
{
|
|
6802
|
-
adapter: config.adapter,
|
|
6803
|
-
saveDebounce: config.saveDebounce,
|
|
6804
|
-
autoLoad: config.autoLoad,
|
|
6805
|
-
autoRestoreLastThread: config.autoRestoreLastThread
|
|
6806
|
-
},
|
|
6807
|
-
config.callbacks
|
|
6808
|
-
);
|
|
6809
|
-
}
|
|
6810
|
-
return internalManager;
|
|
6811
|
-
}
|
|
6812
|
-
function useThreadManager(config) {
|
|
6813
|
-
const manager = React2.useMemo(() => {
|
|
6814
|
-
if (!config) {
|
|
6815
|
-
return getDefaultManager();
|
|
6816
|
-
}
|
|
6817
|
-
if (!config.adapter) {
|
|
6818
|
-
return getInternalManager(config);
|
|
6819
|
-
}
|
|
6820
|
-
return createReactThreadManager(
|
|
6821
|
-
{
|
|
6822
|
-
adapter: config.adapter,
|
|
6823
|
-
saveDebounce: config.saveDebounce,
|
|
6824
|
-
autoLoad: config.autoLoad,
|
|
6825
|
-
autoRestoreLastThread: config.autoRestoreLastThread
|
|
6826
|
-
},
|
|
6827
|
-
config.callbacks
|
|
6828
|
-
);
|
|
6829
|
-
}, [
|
|
6830
|
-
config?.adapter,
|
|
6831
|
-
config?.saveDebounce,
|
|
6832
|
-
config?.autoLoad,
|
|
6833
|
-
config?.autoRestoreLastThread
|
|
6834
|
-
// Note: callbacks are intentionally not in deps to avoid recreating manager
|
|
6835
|
-
]);
|
|
6836
|
-
const threads = React2.useSyncExternalStore(
|
|
6837
|
-
manager.subscribe,
|
|
6838
|
-
manager.getThreadsSnapshot,
|
|
6839
|
-
manager.getThreadsServerSnapshot
|
|
6840
|
-
// SSR - always empty array
|
|
6841
|
-
);
|
|
6842
|
-
const currentThread = React2.useSyncExternalStore(
|
|
6843
|
-
manager.subscribe,
|
|
6844
|
-
manager.getCurrentThreadSnapshot,
|
|
6845
|
-
manager.getCurrentThreadServerSnapshot
|
|
6846
|
-
// SSR - always null
|
|
6847
|
-
);
|
|
6848
|
-
const currentThreadId = React2.useSyncExternalStore(
|
|
6849
|
-
manager.subscribe,
|
|
6850
|
-
manager.getCurrentThreadIdSnapshot,
|
|
6851
|
-
manager.getCurrentThreadIdServerSnapshot
|
|
6852
|
-
// SSR - always null
|
|
6853
|
-
);
|
|
6854
|
-
const loadStatus = React2.useSyncExternalStore(
|
|
6855
|
-
manager.subscribe,
|
|
6856
|
-
manager.getLoadStatusSnapshot,
|
|
6857
|
-
manager.getLoadStatusServerSnapshot
|
|
6858
|
-
// SSR - always "idle"
|
|
6859
|
-
);
|
|
6860
|
-
const error = React2.useSyncExternalStore(
|
|
6861
|
-
manager.subscribe,
|
|
6862
|
-
manager.getErrorSnapshot,
|
|
6863
|
-
manager.getErrorServerSnapshot
|
|
6864
|
-
// SSR - always undefined
|
|
6865
|
-
);
|
|
6866
|
-
const isLoading = React2.useSyncExternalStore(
|
|
6867
|
-
manager.subscribe,
|
|
6868
|
-
manager.getIsLoadingSnapshot,
|
|
6869
|
-
manager.getIsLoadingServerSnapshot
|
|
6870
|
-
// SSR - always false
|
|
6871
|
-
);
|
|
6872
|
-
React2.useEffect(() => {
|
|
6873
|
-
return () => {
|
|
6874
|
-
if (config?.adapter && manager !== defaultManager && manager !== internalManager) {
|
|
6875
|
-
manager.dispose();
|
|
6876
|
-
}
|
|
6877
|
-
};
|
|
6878
|
-
}, [manager, config]);
|
|
6879
|
-
React2.useEffect(() => {
|
|
6880
|
-
const handleBeforeUnload = () => {
|
|
6881
|
-
if (manager.hasPendingChanges) {
|
|
6882
|
-
manager.saveNow().catch(() => {
|
|
6883
|
-
});
|
|
6884
|
-
}
|
|
6885
|
-
};
|
|
6886
|
-
if (typeof window !== "undefined") {
|
|
6887
|
-
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
6888
|
-
return () => {
|
|
6889
|
-
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
6890
|
-
};
|
|
6891
|
-
}
|
|
6892
|
-
}, [manager]);
|
|
6893
|
-
const createThread = React2.useCallback(
|
|
6894
|
-
(options) => manager.createThread(options),
|
|
6895
|
-
[manager]
|
|
6896
|
-
);
|
|
6897
|
-
const switchThread = React2.useCallback(
|
|
6898
|
-
(id) => manager.switchThread(id),
|
|
6899
|
-
[manager]
|
|
6900
|
-
);
|
|
6901
|
-
const updateCurrentThread = React2.useCallback(
|
|
6902
|
-
(updates) => manager.updateCurrentThread(updates),
|
|
6903
|
-
[manager]
|
|
6904
|
-
);
|
|
6905
|
-
const deleteThread = React2.useCallback(
|
|
6906
|
-
(id) => manager.deleteThread(id),
|
|
6907
|
-
[manager]
|
|
6908
|
-
);
|
|
6909
|
-
const clearCurrentThread = React2.useCallback(
|
|
6910
|
-
() => manager.clearCurrentThread(),
|
|
6911
|
-
[manager]
|
|
6912
|
-
);
|
|
6913
|
-
const refreshThreads = React2.useCallback(() => manager.loadThreads(), [manager]);
|
|
6914
|
-
const saveNow = React2.useCallback(() => manager.saveNow(), [manager]);
|
|
6915
|
-
const clearAllThreads = React2.useCallback(
|
|
6916
|
-
() => manager.clearAllThreads(),
|
|
6917
|
-
[manager]
|
|
6918
|
-
);
|
|
6919
|
-
const messages = React2.useMemo(
|
|
6920
|
-
() => currentThread?.messages ?? [],
|
|
6921
|
-
[currentThread]
|
|
6922
|
-
);
|
|
6923
|
-
const setMessages = React2.useCallback(
|
|
6924
|
-
(newMessages) => updateCurrentThread({ messages: newMessages }),
|
|
6925
|
-
[updateCurrentThread]
|
|
6926
|
-
);
|
|
6927
|
-
const hasPendingChanges = manager.hasPendingChanges;
|
|
6928
|
-
return {
|
|
6929
|
-
// State
|
|
6930
|
-
threads,
|
|
6931
|
-
currentThread,
|
|
6932
|
-
currentThreadId,
|
|
6933
|
-
isLoading,
|
|
6934
|
-
loadStatus,
|
|
6935
|
-
error,
|
|
6936
|
-
// Actions
|
|
6937
|
-
createThread,
|
|
6938
|
-
switchThread,
|
|
6939
|
-
updateCurrentThread,
|
|
6940
|
-
deleteThread,
|
|
6941
|
-
clearCurrentThread,
|
|
6942
|
-
refreshThreads,
|
|
6943
|
-
saveNow,
|
|
6944
|
-
clearAllThreads,
|
|
6945
|
-
// Utilities
|
|
6946
|
-
messages,
|
|
6947
|
-
setMessages,
|
|
6948
|
-
hasPendingChanges
|
|
6949
|
-
};
|
|
6950
|
-
}
|
|
6951
|
-
function useMCPUIIntents(config = {}) {
|
|
6952
|
-
const {
|
|
6953
|
-
onToolCall,
|
|
6954
|
-
onIntent,
|
|
6955
|
-
onPrompt,
|
|
6956
|
-
onNotify,
|
|
6957
|
-
onLink,
|
|
6958
|
-
requireConsent = { tool: false, link: true }
|
|
6959
|
-
} = config;
|
|
6960
|
-
const handleIntent = React2.useCallback(
|
|
6961
|
-
async (intent, context) => {
|
|
6962
|
-
switch (intent.type) {
|
|
6963
|
-
case "tool": {
|
|
6964
|
-
if (requireConsent.tool) ;
|
|
6965
|
-
await onToolCall?.(intent.name, intent.arguments, context);
|
|
6966
|
-
break;
|
|
6967
|
-
}
|
|
6968
|
-
case "intent": {
|
|
6969
|
-
await onIntent?.(intent.action, intent.data, context);
|
|
6970
|
-
break;
|
|
6971
|
-
}
|
|
6972
|
-
case "prompt": {
|
|
6973
|
-
onPrompt?.(intent.text, context);
|
|
6974
|
-
break;
|
|
6975
|
-
}
|
|
6976
|
-
case "notify": {
|
|
6977
|
-
onNotify?.(intent.message, intent.level, context);
|
|
6978
|
-
break;
|
|
6979
|
-
}
|
|
6980
|
-
case "link": {
|
|
6981
|
-
const shouldContinue = onLink?.(intent.url, intent.newTab, context);
|
|
6982
|
-
if (shouldContinue === false) {
|
|
6983
|
-
break;
|
|
6984
|
-
}
|
|
6985
|
-
if (requireConsent.link) {
|
|
6986
|
-
const isSafeUrl = intent.url.startsWith("https://") || intent.url.startsWith("http://localhost");
|
|
6987
|
-
if (!isSafeUrl) {
|
|
6988
|
-
console.warn(
|
|
6989
|
-
"[MCP-UI] Blocked potentially unsafe link:",
|
|
6990
|
-
intent.url
|
|
6991
|
-
);
|
|
6992
|
-
break;
|
|
6993
|
-
}
|
|
6994
|
-
}
|
|
6995
|
-
if (typeof window !== "undefined") {
|
|
6996
|
-
if (intent.newTab !== false) {
|
|
6997
|
-
window.open(intent.url, "_blank", "noopener,noreferrer");
|
|
6998
|
-
} else {
|
|
6999
|
-
window.location.href = intent.url;
|
|
7000
|
-
}
|
|
7001
|
-
}
|
|
7002
|
-
break;
|
|
7003
|
-
}
|
|
7004
|
-
default: {
|
|
7005
|
-
console.warn(
|
|
7006
|
-
"[MCP-UI] Unknown intent type:",
|
|
7007
|
-
intent.type
|
|
7008
|
-
);
|
|
7009
|
-
}
|
|
7010
|
-
}
|
|
7011
|
-
},
|
|
7012
|
-
[onToolCall, onIntent, onPrompt, onNotify, onLink, requireConsent]
|
|
7013
|
-
);
|
|
7014
|
-
return React2.useMemo(
|
|
7015
|
-
() => ({
|
|
7016
|
-
handleIntent
|
|
7017
|
-
}),
|
|
7018
|
-
[handleIntent]
|
|
7019
|
-
);
|
|
7020
|
-
}
|
|
7021
|
-
function createMessageIntentHandler(sendMessage) {
|
|
7022
|
-
return {
|
|
7023
|
-
onIntent: async (action, data) => {
|
|
7024
|
-
const dataStr = data ? ` with ${JSON.stringify(data)}` : "";
|
|
7025
|
-
await sendMessage(`User action: ${action}${dataStr}`);
|
|
7026
|
-
},
|
|
7027
|
-
onPrompt: (text) => {
|
|
7028
|
-
sendMessage(text);
|
|
7029
|
-
},
|
|
7030
|
-
onNotify: (message, level) => {
|
|
7031
|
-
if (level === "error") {
|
|
7032
|
-
sendMessage(`Error: ${message}`);
|
|
7033
|
-
}
|
|
7034
|
-
}
|
|
7035
|
-
};
|
|
7036
|
-
}
|
|
7037
|
-
function createToolIntentHandler(callTool) {
|
|
7038
|
-
return {
|
|
7039
|
-
onToolCall: async (name, args) => {
|
|
7040
|
-
await callTool(name, args);
|
|
7041
|
-
}
|
|
7042
|
-
};
|
|
7043
|
-
}
|
|
7044
|
-
function getLastResponseUsage(messages) {
|
|
7045
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
7046
|
-
const msg = messages[i];
|
|
7047
|
-
if (msg.role === "assistant" && msg.metadata?.usage) {
|
|
7048
|
-
const u = msg.metadata.usage;
|
|
7049
|
-
const prompt = u.prompt_tokens ?? 0;
|
|
7050
|
-
const completion = u.completion_tokens ?? 0;
|
|
7051
|
-
return {
|
|
7052
|
-
prompt_tokens: prompt,
|
|
7053
|
-
completion_tokens: completion,
|
|
7054
|
-
total_tokens: u.total_tokens ?? prompt + completion
|
|
7055
|
-
};
|
|
7056
|
-
}
|
|
7057
|
-
}
|
|
7058
|
-
return null;
|
|
7059
|
-
}
|
|
7060
|
-
function useContextStats() {
|
|
7061
|
-
const { contextChars, contextUsage, registeredTools, messages } = useCopilot();
|
|
7062
|
-
const toolCount = React2.useMemo(() => registeredTools.length, [registeredTools]);
|
|
7063
|
-
const messageCount = React2.useMemo(
|
|
7064
|
-
() => messages.filter((m) => m.role !== "system").length,
|
|
7065
|
-
[messages]
|
|
7066
|
-
);
|
|
7067
|
-
const totalTokens = React2.useMemo(() => {
|
|
7068
|
-
if (contextUsage) return contextUsage.total.tokens;
|
|
7069
|
-
return Math.ceil(contextChars / 3.5);
|
|
7070
|
-
}, [contextUsage, contextChars]);
|
|
7071
|
-
const usagePercent = React2.useMemo(() => {
|
|
7072
|
-
if (contextUsage) return contextUsage.total.percent;
|
|
7073
|
-
return 0;
|
|
7074
|
-
}, [contextUsage]);
|
|
7075
|
-
const lastResponseUsage = React2.useMemo(
|
|
7076
|
-
() => getLastResponseUsage(messages),
|
|
7077
|
-
[messages]
|
|
7078
|
-
);
|
|
7079
|
-
return {
|
|
7080
|
-
contextUsage,
|
|
7081
|
-
totalTokens,
|
|
7082
|
-
usagePercent,
|
|
7083
|
-
contextChars,
|
|
7084
|
-
toolCount,
|
|
7085
|
-
messageCount,
|
|
7086
|
-
lastResponseUsage
|
|
7087
|
-
};
|
|
7088
|
-
}
|
|
7089
|
-
var DEV_CONTENT_WARN_THRESHOLD = 2e3;
|
|
7090
|
-
function useSkill(skill) {
|
|
7091
|
-
const { register, unregister } = useSkillContext();
|
|
7092
|
-
if (process.env.NODE_ENV !== "production" && skill.source.type === "inline" && skill.source.content.length > DEV_CONTENT_WARN_THRESHOLD) {
|
|
7093
|
-
console.warn(
|
|
7094
|
-
`[copilot-sdk/skills] Inline skill "${skill.name}" has ${skill.source.content.length} characters. Inline skills are sent on every request \u2014 keep them under ${DEV_CONTENT_WARN_THRESHOLD} characters. Consider using a file or URL skill instead.`
|
|
7095
|
-
);
|
|
7096
|
-
}
|
|
7097
|
-
React2.useEffect(() => {
|
|
7098
|
-
if (skill.source.type !== "inline") {
|
|
7099
|
-
console.warn(
|
|
7100
|
-
`[copilot-sdk/skills] useSkill only supports inline skills client-side. Skill "${skill.name}" has source type "${skill.source.type}" and will be skipped.`
|
|
7101
|
-
);
|
|
7102
|
-
return;
|
|
7103
|
-
}
|
|
7104
|
-
const resolved = {
|
|
7105
|
-
...skill,
|
|
7106
|
-
content: skill.source.content
|
|
7107
|
-
};
|
|
7108
|
-
register(resolved);
|
|
7109
|
-
return () => {
|
|
7110
|
-
unregister(skill.name);
|
|
7111
|
-
};
|
|
7112
|
-
}, [
|
|
7113
|
-
skill.name,
|
|
7114
|
-
skill.source.type === "inline" ? skill.source.content : "",
|
|
7115
|
-
skill.strategy,
|
|
7116
|
-
skill.description
|
|
7117
|
-
]);
|
|
7118
|
-
}
|
|
7119
|
-
function useSkillStatus() {
|
|
7120
|
-
const { skills, registry } = useSkillContext();
|
|
7121
|
-
const has = React2.useCallback(
|
|
7122
|
-
(name) => registry.has(name),
|
|
7123
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
7124
|
-
[skills]
|
|
7125
|
-
);
|
|
7126
|
-
return {
|
|
7127
|
-
skills,
|
|
7128
|
-
count: skills.length,
|
|
7129
|
-
has
|
|
7130
|
-
};
|
|
7131
|
-
}
|
|
7132
|
-
|
|
7133
|
-
// src/react/utils/permission-storage.ts
|
|
7134
|
-
var DEFAULT_KEY_PREFIX = "yourgpt-permissions";
|
|
7135
|
-
function createPermissionStorage(config) {
|
|
7136
|
-
switch (config.type) {
|
|
7137
|
-
case "localStorage":
|
|
7138
|
-
return createBrowserStorageAdapter(
|
|
7139
|
-
typeof window !== "undefined" ? localStorage : null,
|
|
7140
|
-
config.keyPrefix
|
|
7141
|
-
);
|
|
7142
|
-
case "sessionStorage":
|
|
7143
|
-
return createBrowserStorageAdapter(
|
|
7144
|
-
typeof window !== "undefined" ? sessionStorage : null,
|
|
7145
|
-
config.keyPrefix
|
|
7146
|
-
);
|
|
7147
|
-
case "memory":
|
|
7148
|
-
default:
|
|
7149
|
-
return createMemoryStorageAdapter();
|
|
7150
|
-
}
|
|
7151
|
-
}
|
|
7152
|
-
function createBrowserStorageAdapter(storage, keyPrefix = DEFAULT_KEY_PREFIX) {
|
|
7153
|
-
const getStorageKey = () => keyPrefix;
|
|
7154
|
-
const loadPermissions = () => {
|
|
7155
|
-
if (!storage) return /* @__PURE__ */ new Map();
|
|
7156
|
-
try {
|
|
7157
|
-
const data = storage.getItem(getStorageKey());
|
|
7158
|
-
if (!data) return /* @__PURE__ */ new Map();
|
|
7159
|
-
const parsed = JSON.parse(data);
|
|
7160
|
-
return new Map(parsed.map((p) => [p.toolName, p]));
|
|
7161
|
-
} catch {
|
|
7162
|
-
return /* @__PURE__ */ new Map();
|
|
7163
|
-
}
|
|
7164
|
-
};
|
|
7165
|
-
const savePermissions = (permissions) => {
|
|
7166
|
-
if (!storage) return;
|
|
7167
|
-
try {
|
|
7168
|
-
storage.setItem(
|
|
7169
|
-
getStorageKey(),
|
|
7170
|
-
JSON.stringify(Array.from(permissions.values()))
|
|
7171
|
-
);
|
|
7172
|
-
} catch (e) {
|
|
7173
|
-
console.warn("[PermissionStorage] Failed to save permissions:", e);
|
|
7174
|
-
}
|
|
7175
|
-
};
|
|
7176
|
-
return {
|
|
7177
|
-
async get(toolName) {
|
|
7178
|
-
const permissions = loadPermissions();
|
|
7179
|
-
return permissions.get(toolName) || null;
|
|
7180
|
-
},
|
|
7181
|
-
async set(permission) {
|
|
7182
|
-
const permissions = loadPermissions();
|
|
7183
|
-
permissions.set(permission.toolName, permission);
|
|
7184
|
-
savePermissions(permissions);
|
|
7185
|
-
},
|
|
7186
|
-
async remove(toolName) {
|
|
7187
|
-
const permissions = loadPermissions();
|
|
7188
|
-
permissions.delete(toolName);
|
|
7189
|
-
savePermissions(permissions);
|
|
7190
|
-
},
|
|
7191
|
-
async getAll() {
|
|
7192
|
-
const permissions = loadPermissions();
|
|
7193
|
-
return Array.from(permissions.values());
|
|
7194
|
-
},
|
|
7195
|
-
async clear() {
|
|
7196
|
-
if (!storage) return;
|
|
7197
|
-
storage.removeItem(getStorageKey());
|
|
7198
|
-
}
|
|
7199
|
-
};
|
|
7200
|
-
}
|
|
7201
|
-
function createMemoryStorageAdapter() {
|
|
7202
|
-
const permissions = /* @__PURE__ */ new Map();
|
|
7203
|
-
return {
|
|
7204
|
-
async get(toolName) {
|
|
7205
|
-
return permissions.get(toolName) || null;
|
|
7206
|
-
},
|
|
7207
|
-
async set(permission) {
|
|
7208
|
-
permissions.set(permission.toolName, permission);
|
|
7209
|
-
},
|
|
7210
|
-
async remove(toolName) {
|
|
7211
|
-
permissions.delete(toolName);
|
|
7212
|
-
},
|
|
7213
|
-
async getAll() {
|
|
7214
|
-
return Array.from(permissions.values());
|
|
7215
|
-
},
|
|
7216
|
-
async clear() {
|
|
7217
|
-
permissions.clear();
|
|
7218
|
-
}
|
|
7219
|
-
};
|
|
7220
|
-
}
|
|
7221
|
-
function createSessionPermissionCache() {
|
|
7222
|
-
return /* @__PURE__ */ new Map();
|
|
7223
|
-
}
|
|
7224
|
-
|
|
7225
|
-
// src/react/internal/ReactChat.ts
|
|
7226
|
-
var ReactChat = class extends AbstractChat {
|
|
7227
|
-
constructor(config) {
|
|
7228
|
-
const reactState = new ReactChatState(config.initialMessages);
|
|
7229
|
-
const init = {
|
|
7230
|
-
runtimeUrl: config.runtimeUrl,
|
|
7231
|
-
systemPrompt: config.systemPrompt,
|
|
7232
|
-
llm: config.llm,
|
|
7233
|
-
threadId: config.threadId,
|
|
7234
|
-
streaming: config.streaming ?? true,
|
|
7235
|
-
headers: config.headers,
|
|
7236
|
-
initialMessages: config.initialMessages,
|
|
7237
|
-
state: reactState,
|
|
7238
|
-
callbacks: config.callbacks,
|
|
7239
|
-
debug: config.debug
|
|
7240
|
-
};
|
|
7241
|
-
super(init);
|
|
7242
|
-
// ============================================
|
|
7243
|
-
// Subscribe (for useSyncExternalStore)
|
|
7244
|
-
// ============================================
|
|
7245
|
-
/**
|
|
7246
|
-
* Subscribe to state changes.
|
|
7247
|
-
* Returns an unsubscribe function.
|
|
7248
|
-
*
|
|
7249
|
-
* @example
|
|
7250
|
-
* ```tsx
|
|
7251
|
-
* const messages = useSyncExternalStore(
|
|
7252
|
-
* chat.subscribe,
|
|
7253
|
-
* () => chat.messages
|
|
7254
|
-
* );
|
|
7255
|
-
* ```
|
|
7256
|
-
*/
|
|
7257
|
-
this.subscribe = (callback) => {
|
|
7258
|
-
return this.reactState.subscribe(callback);
|
|
7259
|
-
};
|
|
7260
|
-
this.reactState = reactState;
|
|
7261
|
-
}
|
|
7262
|
-
// ============================================
|
|
7263
|
-
// Event handling shortcuts
|
|
7264
|
-
// ============================================
|
|
7265
|
-
/**
|
|
7266
|
-
* Subscribe to tool calls events
|
|
7267
|
-
*/
|
|
7268
|
-
onToolCalls(handler) {
|
|
7269
|
-
return this.on("toolCalls", handler);
|
|
7270
|
-
}
|
|
7271
|
-
/**
|
|
7272
|
-
* Subscribe to done events
|
|
7273
|
-
*/
|
|
7274
|
-
onDone(handler) {
|
|
7275
|
-
return this.on("done", handler);
|
|
7276
|
-
}
|
|
7277
|
-
/**
|
|
7278
|
-
* Subscribe to error events
|
|
7279
|
-
*/
|
|
7280
|
-
onError(handler) {
|
|
7281
|
-
return this.on("error", handler);
|
|
7282
|
-
}
|
|
7283
|
-
// ============================================
|
|
7284
|
-
// Branching API — pass-throughs to ReactChatState
|
|
7285
|
-
// ============================================
|
|
7286
|
-
/**
|
|
7287
|
-
* Navigate to a sibling branch (makes it the active path).
|
|
7288
|
-
*/
|
|
7289
|
-
switchBranch(messageId) {
|
|
7290
|
-
this.reactState.switchBranch(messageId);
|
|
7291
|
-
}
|
|
7292
|
-
/**
|
|
7293
|
-
* Get branch navigation info for a message.
|
|
7294
|
-
* Returns null if the message has no siblings.
|
|
7295
|
-
*/
|
|
7296
|
-
getBranchInfo(messageId) {
|
|
7297
|
-
return this.reactState.getBranchInfo(messageId);
|
|
7298
|
-
}
|
|
7299
|
-
/**
|
|
7300
|
-
* Get all messages across all branches (for persistence).
|
|
7301
|
-
*/
|
|
7302
|
-
getAllMessages() {
|
|
7303
|
-
return this.reactState.getAllMessages();
|
|
7304
|
-
}
|
|
7305
|
-
/**
|
|
7306
|
-
* Whether any message has siblings (branching has occurred).
|
|
7307
|
-
*/
|
|
7308
|
-
get hasBranches() {
|
|
7309
|
-
return this.reactState.hasBranches;
|
|
7310
|
-
}
|
|
7311
|
-
// ============================================
|
|
7312
|
-
// Override dispose to clean up state
|
|
7313
|
-
// ============================================
|
|
7314
|
-
dispose() {
|
|
7315
|
-
super.dispose();
|
|
7316
|
-
this.reactState.dispose();
|
|
7317
|
-
}
|
|
7318
|
-
/**
|
|
7319
|
-
* Revive a disposed instance (for React StrictMode compatibility)
|
|
7320
|
-
*/
|
|
7321
|
-
revive() {
|
|
7322
|
-
super.revive();
|
|
7323
|
-
this.reactState.revive();
|
|
7324
|
-
}
|
|
7325
|
-
};
|
|
7326
|
-
function createReactChat(config) {
|
|
7327
|
-
return new ReactChat(config);
|
|
7328
|
-
}
|
|
7329
|
-
function useChat(config) {
|
|
7330
|
-
const chatRef = React2.useRef(null);
|
|
7331
|
-
const [input, setInput] = React2.useState("");
|
|
7332
|
-
if (chatRef.current !== null && chatRef.current.disposed) {
|
|
7333
|
-
chatRef.current.revive();
|
|
7334
|
-
}
|
|
7335
|
-
if (chatRef.current === null) {
|
|
7336
|
-
chatRef.current = createReactChat({
|
|
7337
|
-
runtimeUrl: config.runtimeUrl,
|
|
7338
|
-
systemPrompt: config.systemPrompt,
|
|
7339
|
-
llm: config.llm,
|
|
7340
|
-
threadId: config.threadId,
|
|
7341
|
-
streaming: config.streaming,
|
|
7342
|
-
headers: config.headers,
|
|
7343
|
-
initialMessages: config.initialMessages,
|
|
7344
|
-
debug: config.debug,
|
|
7345
|
-
callbacks: {
|
|
7346
|
-
onMessagesChange: config.onMessagesChange,
|
|
7347
|
-
onError: config.onError,
|
|
7348
|
-
onFinish: config.onFinish,
|
|
7349
|
-
onToolCalls: config.onToolCalls
|
|
7350
|
-
}
|
|
7351
|
-
});
|
|
7352
|
-
}
|
|
7353
|
-
const messages = React2.useSyncExternalStore(
|
|
7354
|
-
chatRef.current.subscribe,
|
|
7355
|
-
() => chatRef.current.messages,
|
|
7356
|
-
() => chatRef.current.messages
|
|
7357
|
-
// Server snapshot
|
|
5425
|
+
return id;
|
|
5426
|
+
},
|
|
5427
|
+
[debugLog]
|
|
7358
5428
|
);
|
|
7359
|
-
const
|
|
7360
|
-
|
|
7361
|
-
|
|
7362
|
-
|
|
7363
|
-
|
|
5429
|
+
const removeContext = React2.useCallback(
|
|
5430
|
+
(id) => {
|
|
5431
|
+
contextTreeRef.current = removeNode(contextTreeRef.current, id);
|
|
5432
|
+
const contextString = printTree(contextTreeRef.current);
|
|
5433
|
+
chatRef.current?.setContext(contextString);
|
|
5434
|
+
setContextChars(contextString.length);
|
|
5435
|
+
debugLog("Context removed:", id);
|
|
5436
|
+
},
|
|
5437
|
+
[debugLog]
|
|
7364
5438
|
);
|
|
7365
|
-
const
|
|
7366
|
-
|
|
7367
|
-
|
|
7368
|
-
|
|
7369
|
-
|
|
5439
|
+
const setSystemPrompt = React2.useCallback(
|
|
5440
|
+
(prompt) => {
|
|
5441
|
+
chatRef.current?.setSystemPrompt(prompt);
|
|
5442
|
+
debugLog("System prompt updated via function");
|
|
5443
|
+
},
|
|
5444
|
+
[debugLog]
|
|
7370
5445
|
);
|
|
7371
|
-
const
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
5446
|
+
const setInlineSkills = React2.useCallback(
|
|
5447
|
+
(skills2) => {
|
|
5448
|
+
chatRef.current?.setInlineSkills(skills2);
|
|
5449
|
+
debugLog("Inline skills updated", { count: skills2.length });
|
|
5450
|
+
},
|
|
5451
|
+
[debugLog]
|
|
7375
5452
|
);
|
|
7376
|
-
const isLoading = status === "streaming" || status === "submitted";
|
|
7377
5453
|
const sendMessage = React2.useCallback(
|
|
7378
5454
|
async (content, attachments) => {
|
|
5455
|
+
debugLog("Sending message:", content);
|
|
5456
|
+
setAgentIteration(0);
|
|
7379
5457
|
await chatRef.current?.sendMessage(content, attachments);
|
|
7380
|
-
setInput("");
|
|
7381
5458
|
},
|
|
7382
|
-
[]
|
|
5459
|
+
[debugLog]
|
|
7383
5460
|
);
|
|
7384
5461
|
const stop = React2.useCallback(() => {
|
|
7385
5462
|
chatRef.current?.stop();
|
|
@@ -7393,19 +5470,11 @@ function useChat(config) {
|
|
|
7393
5470
|
const regenerate = React2.useCallback(async (messageId) => {
|
|
7394
5471
|
await chatRef.current?.regenerate(messageId);
|
|
7395
5472
|
}, []);
|
|
7396
|
-
const continueWithToolResults = React2.useCallback(
|
|
7397
|
-
async (toolResults) => {
|
|
7398
|
-
await chatRef.current?.continueWithToolResults(toolResults);
|
|
7399
|
-
},
|
|
7400
|
-
[]
|
|
7401
|
-
);
|
|
7402
5473
|
const switchBranch = React2.useCallback((messageId) => {
|
|
7403
5474
|
chatRef.current?.switchBranch(messageId);
|
|
7404
5475
|
}, []);
|
|
7405
5476
|
const getBranchInfo = React2.useCallback(
|
|
7406
|
-
(messageId) =>
|
|
7407
|
-
return chatRef.current?.getBranchInfo(messageId) ?? null;
|
|
7408
|
-
},
|
|
5477
|
+
(messageId) => chatRef.current?.getBranchInfo(messageId) ?? null,
|
|
7409
5478
|
[]
|
|
7410
5479
|
);
|
|
7411
5480
|
const editMessage = React2.useCallback(
|
|
@@ -7413,40 +5482,238 @@ function useChat(config) {
|
|
|
7413
5482
|
await chatRef.current?.sendMessage(newContent, void 0, {
|
|
7414
5483
|
editMessageId: messageId
|
|
7415
5484
|
});
|
|
7416
|
-
setInput("");
|
|
7417
5485
|
},
|
|
7418
5486
|
[]
|
|
7419
5487
|
);
|
|
5488
|
+
const getHasBranchesSnapshot = React2.useCallback(
|
|
5489
|
+
() => chatRef.current.hasBranches,
|
|
5490
|
+
[]
|
|
5491
|
+
);
|
|
5492
|
+
const hasBranches = React2.useSyncExternalStore(
|
|
5493
|
+
chatRef.current.subscribe,
|
|
5494
|
+
getHasBranchesSnapshot,
|
|
5495
|
+
() => false
|
|
5496
|
+
);
|
|
5497
|
+
const getAllMessages = React2.useCallback(
|
|
5498
|
+
() => chatRef.current?.getAllMessages?.() ?? [],
|
|
5499
|
+
[]
|
|
5500
|
+
);
|
|
5501
|
+
React2.useEffect(() => {
|
|
5502
|
+
if (onMessagesChange && messages.length > 0) {
|
|
5503
|
+
const allUIMessages = chatRef.current?.getAllMessages?.() ?? messages;
|
|
5504
|
+
const coreMessages = allUIMessages.map((m) => ({
|
|
5505
|
+
id: m.id,
|
|
5506
|
+
role: m.role,
|
|
5507
|
+
content: m.content,
|
|
5508
|
+
created_at: m.createdAt,
|
|
5509
|
+
tool_calls: m.toolCalls,
|
|
5510
|
+
tool_call_id: m.toolCallId,
|
|
5511
|
+
parent_id: m.parentId,
|
|
5512
|
+
children_ids: m.childrenIds,
|
|
5513
|
+
metadata: {
|
|
5514
|
+
attachments: m.attachments,
|
|
5515
|
+
thinking: m.thinking
|
|
5516
|
+
}
|
|
5517
|
+
}));
|
|
5518
|
+
onMessagesChange(coreMessages);
|
|
5519
|
+
}
|
|
5520
|
+
}, [messages, onMessagesChange]);
|
|
5521
|
+
React2.useEffect(() => {
|
|
5522
|
+
if (error && onError) {
|
|
5523
|
+
onError(error);
|
|
5524
|
+
}
|
|
5525
|
+
}, [error, onError]);
|
|
7420
5526
|
React2.useEffect(() => {
|
|
7421
5527
|
return () => {
|
|
7422
5528
|
chatRef.current?.dispose();
|
|
7423
5529
|
};
|
|
7424
5530
|
}, []);
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
5531
|
+
const contextValue = React2.useMemo(
|
|
5532
|
+
() => ({
|
|
5533
|
+
// Chat state
|
|
5534
|
+
messages,
|
|
5535
|
+
status,
|
|
5536
|
+
error,
|
|
5537
|
+
isLoading,
|
|
5538
|
+
// Chat actions
|
|
5539
|
+
sendMessage,
|
|
5540
|
+
stop,
|
|
5541
|
+
clearMessages,
|
|
5542
|
+
setMessages,
|
|
5543
|
+
regenerate,
|
|
5544
|
+
// Branching
|
|
5545
|
+
switchBranch,
|
|
5546
|
+
getBranchInfo,
|
|
5547
|
+
editMessage,
|
|
5548
|
+
hasBranches,
|
|
5549
|
+
getAllMessages,
|
|
5550
|
+
// Tool execution
|
|
5551
|
+
registerTool,
|
|
5552
|
+
unregisterTool,
|
|
5553
|
+
registeredTools,
|
|
5554
|
+
toolExecutions,
|
|
5555
|
+
pendingApprovals,
|
|
5556
|
+
approveToolExecution,
|
|
5557
|
+
rejectToolExecution,
|
|
5558
|
+
agentIteration,
|
|
5559
|
+
// Actions
|
|
5560
|
+
registerAction,
|
|
5561
|
+
unregisterAction,
|
|
5562
|
+
registeredActions,
|
|
5563
|
+
// AI Context
|
|
5564
|
+
addContext,
|
|
5565
|
+
removeContext,
|
|
5566
|
+
contextChars,
|
|
5567
|
+
contextUsage,
|
|
5568
|
+
// System Prompt
|
|
5569
|
+
setSystemPrompt,
|
|
5570
|
+
// Skills
|
|
5571
|
+
setInlineSkills,
|
|
5572
|
+
// Config
|
|
5573
|
+
threadId,
|
|
5574
|
+
runtimeUrl,
|
|
5575
|
+
toolsConfig,
|
|
5576
|
+
// Headless primitives
|
|
5577
|
+
subscribeToStreamEvents,
|
|
5578
|
+
messageMeta: messageMetaStoreRef.current
|
|
5579
|
+
}),
|
|
5580
|
+
[
|
|
5581
|
+
messages,
|
|
5582
|
+
status,
|
|
5583
|
+
error,
|
|
5584
|
+
isLoading,
|
|
5585
|
+
sendMessage,
|
|
5586
|
+
stop,
|
|
5587
|
+
clearMessages,
|
|
5588
|
+
setMessages,
|
|
5589
|
+
regenerate,
|
|
5590
|
+
switchBranch,
|
|
5591
|
+
getBranchInfo,
|
|
5592
|
+
editMessage,
|
|
5593
|
+
hasBranches,
|
|
5594
|
+
getAllMessages,
|
|
5595
|
+
registerTool,
|
|
5596
|
+
unregisterTool,
|
|
5597
|
+
registeredTools,
|
|
5598
|
+
toolExecutions,
|
|
5599
|
+
pendingApprovals,
|
|
5600
|
+
approveToolExecution,
|
|
5601
|
+
rejectToolExecution,
|
|
5602
|
+
agentIteration,
|
|
5603
|
+
registerAction,
|
|
5604
|
+
unregisterAction,
|
|
5605
|
+
registeredActions,
|
|
5606
|
+
addContext,
|
|
5607
|
+
removeContext,
|
|
5608
|
+
contextChars,
|
|
5609
|
+
contextUsage,
|
|
5610
|
+
setSystemPrompt,
|
|
5611
|
+
setInlineSkills,
|
|
5612
|
+
threadId,
|
|
5613
|
+
runtimeUrl,
|
|
5614
|
+
toolsConfig
|
|
5615
|
+
]
|
|
5616
|
+
);
|
|
5617
|
+
const messageHistoryContextValue = React2__default.default.useMemo(
|
|
5618
|
+
() => ({
|
|
5619
|
+
config: { ...defaultMessageHistoryConfig, ...messageHistory },
|
|
5620
|
+
tokenUsage: {
|
|
5621
|
+
current: 0,
|
|
5622
|
+
max: messageHistory?.maxContextTokens ?? 128e3,
|
|
5623
|
+
percentage: 0,
|
|
5624
|
+
isApproaching: false
|
|
5625
|
+
},
|
|
5626
|
+
compactionState: {
|
|
5627
|
+
rollingSummary: null,
|
|
5628
|
+
lastCompactionAt: null,
|
|
5629
|
+
compactionCount: 0,
|
|
5630
|
+
totalTokensSaved: 0,
|
|
5631
|
+
workingMemory: [],
|
|
5632
|
+
displayMessageCount: 0,
|
|
5633
|
+
llmMessageCount: 0
|
|
5634
|
+
}
|
|
5635
|
+
}),
|
|
5636
|
+
[messageHistory]
|
|
5637
|
+
);
|
|
5638
|
+
return /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryContext.Provider, { value: messageHistoryContextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(CopilotContext.Provider, { value: contextValue, children: [
|
|
5639
|
+
mcpServers?.map((config) => /* @__PURE__ */ jsxRuntime.jsx(MCPConnection, { config }, config.name)),
|
|
5640
|
+
messageHistory?.strategy && messageHistory.strategy !== "none" && /* @__PURE__ */ jsxRuntime.jsx(MessageHistoryBridge, { chatRef }),
|
|
5641
|
+
skills ? /* @__PURE__ */ jsxRuntime.jsx(SkillProvider, { skills, children }) : children
|
|
5642
|
+
] }) });
|
|
7445
5643
|
}
|
|
7446
5644
|
|
|
7447
|
-
// src/react/
|
|
7448
|
-
function
|
|
7449
|
-
|
|
5645
|
+
// src/react/hooks/useMCPTools.ts
|
|
5646
|
+
function useMCPTools(config) {
|
|
5647
|
+
const {
|
|
5648
|
+
prefixToolNames = true,
|
|
5649
|
+
autoRegister = true,
|
|
5650
|
+
hidden = false,
|
|
5651
|
+
source = "mcp",
|
|
5652
|
+
...clientConfig
|
|
5653
|
+
} = config;
|
|
5654
|
+
const { registerTool, unregisterTool } = useCopilot();
|
|
5655
|
+
const registeredToolsRef = React2.useRef([]);
|
|
5656
|
+
const mcpClient = useMCPClient(clientConfig);
|
|
5657
|
+
const toolAdapter = React2.useMemo(
|
|
5658
|
+
() => new chunkJGPDQDY4_cjs.MCPToolAdapter(clientConfig.name),
|
|
5659
|
+
[clientConfig.name]
|
|
5660
|
+
);
|
|
5661
|
+
const toolDefinitions = React2.useMemo(() => {
|
|
5662
|
+
if (!mcpClient.isConnected || mcpClient.state.tools.length === 0) {
|
|
5663
|
+
return [];
|
|
5664
|
+
}
|
|
5665
|
+
return mcpClient.state.tools.map(
|
|
5666
|
+
(tool) => toolAdapter.toToolDefinition(tool, {
|
|
5667
|
+
prefix: prefixToolNames,
|
|
5668
|
+
asServerTool: true,
|
|
5669
|
+
// MCP tools execute remotely
|
|
5670
|
+
callTool: mcpClient.callTool,
|
|
5671
|
+
hidden,
|
|
5672
|
+
// Hide from chat UI
|
|
5673
|
+
source
|
|
5674
|
+
// Tool source for UI differentiation
|
|
5675
|
+
})
|
|
5676
|
+
);
|
|
5677
|
+
}, [
|
|
5678
|
+
mcpClient.isConnected,
|
|
5679
|
+
mcpClient.state.tools,
|
|
5680
|
+
mcpClient.callTool,
|
|
5681
|
+
toolAdapter,
|
|
5682
|
+
prefixToolNames,
|
|
5683
|
+
hidden,
|
|
5684
|
+
source
|
|
5685
|
+
]);
|
|
5686
|
+
React2.useEffect(() => {
|
|
5687
|
+
if (!autoRegister) {
|
|
5688
|
+
return;
|
|
5689
|
+
}
|
|
5690
|
+
for (const toolName of registeredToolsRef.current) {
|
|
5691
|
+
unregisterTool(toolName);
|
|
5692
|
+
}
|
|
5693
|
+
registeredToolsRef.current = [];
|
|
5694
|
+
if (mcpClient.isConnected && toolDefinitions.length > 0) {
|
|
5695
|
+
for (const tool of toolDefinitions) {
|
|
5696
|
+
registerTool(tool);
|
|
5697
|
+
registeredToolsRef.current.push(tool.name);
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
return () => {
|
|
5701
|
+
for (const toolName of registeredToolsRef.current) {
|
|
5702
|
+
unregisterTool(toolName);
|
|
5703
|
+
}
|
|
5704
|
+
registeredToolsRef.current = [];
|
|
5705
|
+
};
|
|
5706
|
+
}, [
|
|
5707
|
+
autoRegister,
|
|
5708
|
+
mcpClient.isConnected,
|
|
5709
|
+
toolDefinitions,
|
|
5710
|
+
registerTool,
|
|
5711
|
+
unregisterTool
|
|
5712
|
+
]);
|
|
5713
|
+
return {
|
|
5714
|
+
...mcpClient,
|
|
5715
|
+
toolDefinitions
|
|
5716
|
+
};
|
|
7450
5717
|
}
|
|
7451
5718
|
|
|
7452
5719
|
exports.AbstractAgentLoop = AbstractAgentLoop;
|
|
@@ -7454,56 +5721,25 @@ exports.AbstractChat = AbstractChat;
|
|
|
7454
5721
|
exports.CopilotProvider = CopilotProvider;
|
|
7455
5722
|
exports.MessageHistoryContext = MessageHistoryContext;
|
|
7456
5723
|
exports.MessageTree = MessageTree;
|
|
7457
|
-
exports.ReactChat = ReactChat;
|
|
7458
5724
|
exports.ReactChatState = ReactChatState;
|
|
7459
|
-
exports.ReactThreadManager = ReactThreadManager;
|
|
7460
|
-
exports.ReactThreadManagerState = ReactThreadManagerState;
|
|
7461
5725
|
exports.SkillProvider = SkillProvider;
|
|
7462
|
-
exports.createMessageIntentHandler = createMessageIntentHandler;
|
|
7463
|
-
exports.createPermissionStorage = createPermissionStorage;
|
|
7464
|
-
exports.createReactChat = createReactChat;
|
|
7465
5726
|
exports.createReactChatState = createReactChatState;
|
|
7466
|
-
exports.createReactThreadManager = createReactThreadManager;
|
|
7467
|
-
exports.createReactThreadManagerState = createReactThreadManagerState;
|
|
7468
|
-
exports.createSessionPermissionCache = createSessionPermissionCache;
|
|
7469
|
-
exports.createToolIntentHandler = createToolIntentHandler;
|
|
7470
5727
|
exports.defaultMessageHistoryConfig = defaultMessageHistoryConfig;
|
|
7471
|
-
exports.defineSkill = defineSkill;
|
|
7472
|
-
exports.formatKnowledgeResultsForAI = formatKnowledgeResultsForAI;
|
|
7473
5728
|
exports.initialAgentLoopState = initialAgentLoopState;
|
|
7474
5729
|
exports.isCompactionMarker = isCompactionMarker;
|
|
7475
5730
|
exports.keepToolPairsAtomic = keepToolPairsAtomic;
|
|
7476
|
-
exports.searchKnowledgeBase = searchKnowledgeBase;
|
|
7477
5731
|
exports.toDisplayMessage = toDisplayMessage;
|
|
7478
5732
|
exports.toLLMMessage = toLLMMessage;
|
|
7479
5733
|
exports.toLLMMessages = toLLMMessages;
|
|
7480
|
-
exports.useAIAction = useAIAction;
|
|
7481
|
-
exports.useAIActions = useAIActions;
|
|
7482
5734
|
exports.useAIContext = useAIContext;
|
|
7483
5735
|
exports.useAIContexts = useAIContexts;
|
|
7484
|
-
exports.useAITools = useAITools;
|
|
7485
|
-
exports.useAgent = useAgent;
|
|
7486
|
-
exports.useCapabilities = useCapabilities;
|
|
7487
|
-
exports.useChat = useChat;
|
|
7488
|
-
exports.useContextStats = useContextStats;
|
|
7489
5736
|
exports.useCopilot = useCopilot;
|
|
7490
|
-
exports.useDevLogger = useDevLogger;
|
|
7491
|
-
exports.useFeatureSupport = useFeatureSupport;
|
|
7492
|
-
exports.useKnowledgeBase = useKnowledgeBase;
|
|
7493
5737
|
exports.useMCPClient = useMCPClient;
|
|
7494
5738
|
exports.useMCPTools = useMCPTools;
|
|
7495
|
-
exports.useMCPUIIntents = useMCPUIIntents;
|
|
7496
5739
|
exports.useMessageHistory = useMessageHistory;
|
|
7497
5740
|
exports.useMessageHistoryContext = useMessageHistoryContext;
|
|
7498
|
-
exports.
|
|
7499
|
-
exports.useSkillStatus = useSkillStatus;
|
|
7500
|
-
exports.useSuggestions = useSuggestions;
|
|
7501
|
-
exports.useSupportedMediaTypes = useSupportedMediaTypes;
|
|
7502
|
-
exports.useThreadManager = useThreadManager;
|
|
5741
|
+
exports.useSkillContext = useSkillContext;
|
|
7503
5742
|
exports.useTool = useTool;
|
|
7504
|
-
exports.useToolExecutor = useToolExecutor;
|
|
7505
|
-
exports.useToolWithSchema = useToolWithSchema;
|
|
7506
5743
|
exports.useTools = useTools;
|
|
7507
|
-
|
|
7508
|
-
//# sourceMappingURL=chunk-
|
|
7509
|
-
//# sourceMappingURL=chunk-XUR3IOPX.cjs.map
|
|
5744
|
+
//# sourceMappingURL=chunk-LHLVTGIP.cjs.map
|
|
5745
|
+
//# sourceMappingURL=chunk-LHLVTGIP.cjs.map
|