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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/{MessageTree-CSIHErPK.d.ts → MessageTree-Clhiv_k2.d.ts} +4 -3
  2. package/dist/{MessageTree-B0JGQOCi.d.cts → MessageTree-Dt9qfJ55.d.cts} +4 -3
  3. package/dist/{chunk-XUR3IOPX.cjs → chunk-2QLF7XM7.cjs} +1557 -3120
  4. package/dist/chunk-2QLF7XM7.cjs.map +1 -0
  5. package/dist/{chunk-NUXLAZOE.cjs → chunk-3ZDRX7J2.cjs} +2 -2
  6. package/dist/{chunk-NUXLAZOE.cjs.map → chunk-3ZDRX7J2.cjs.map} +1 -1
  7. package/dist/{chunk-RKGRQRZU.js → chunk-533K2Z7C.js} +4 -4
  8. package/dist/{chunk-RKGRQRZU.js.map → chunk-533K2Z7C.js.map} +1 -1
  9. package/dist/chunk-5EGBIQYS.cjs +292 -0
  10. package/dist/chunk-5EGBIQYS.cjs.map +1 -0
  11. package/dist/{chunk-3AONOZLY.js → chunk-AIVXGTWS.js} +2 -2
  12. package/dist/chunk-AIVXGTWS.js.map +1 -0
  13. package/dist/{chunk-LLM7AHMO.js → chunk-DDZLRCVX.js} +2 -2
  14. package/dist/{chunk-LLM7AHMO.js.map → chunk-DDZLRCVX.js.map} +1 -1
  15. package/dist/{chunk-FLZO2FO3.js → chunk-I2XOCFHG.js} +1558 -3071
  16. package/dist/chunk-I2XOCFHG.js.map +1 -0
  17. package/dist/{chunk-EEH3L64W.js → chunk-PSNLKMZH.js} +73 -11
  18. package/dist/chunk-PSNLKMZH.js.map +1 -0
  19. package/dist/chunk-PURFAD2P.js +2020 -0
  20. package/dist/chunk-PURFAD2P.js.map +1 -0
  21. package/dist/chunk-QTGEEBRW.cjs +2077 -0
  22. package/dist/chunk-QTGEEBRW.cjs.map +1 -0
  23. package/dist/{chunk-TPB7XED6.cjs → chunk-TPDMBDQX.cjs} +2 -2
  24. package/dist/chunk-TPDMBDQX.cjs.map +1 -0
  25. package/dist/chunk-TXQ37MAO.js +287 -0
  26. package/dist/chunk-TXQ37MAO.js.map +1 -0
  27. package/dist/{chunk-B4YDIMP3.cjs → chunk-VION33GW.cjs} +92 -30
  28. package/dist/chunk-VION33GW.cjs.map +1 -0
  29. package/dist/{chunk-MDS23G2S.cjs → chunk-Y2A6AMGO.cjs} +10 -10
  30. package/dist/{chunk-MDS23G2S.cjs.map → chunk-Y2A6AMGO.cjs.map} +1 -1
  31. package/dist/core/index.cjs +93 -93
  32. package/dist/core/index.d.cts +3 -3
  33. package/dist/core/index.d.ts +3 -3
  34. package/dist/core/index.js +5 -5
  35. package/dist/experimental/index.cjs +644 -0
  36. package/dist/experimental/index.cjs.map +1 -0
  37. package/dist/experimental/index.d.cts +924 -0
  38. package/dist/experimental/index.d.ts +924 -0
  39. package/dist/experimental/index.js +611 -0
  40. package/dist/experimental/index.js.map +1 -0
  41. package/dist/{index-D7169xuR.d.ts → index-D8zza1Q8.d.ts} +1 -1
  42. package/dist/{index-CzJB8Ddo.d.cts → index-DCVjTdIZ.d.cts} +1 -1
  43. package/dist/mcp/index.d.cts +3 -3
  44. package/dist/mcp/index.d.ts +3 -3
  45. package/dist/react/index.cjs +140 -123
  46. package/dist/react/index.d.cts +378 -10
  47. package/dist/react/index.d.ts +378 -10
  48. package/dist/react/index.js +7 -6
  49. package/dist/styles.css +45 -0
  50. package/dist/tools/anthropic/index.cjs +3 -3
  51. package/dist/tools/anthropic/index.d.cts +1 -1
  52. package/dist/tools/anthropic/index.d.ts +1 -1
  53. package/dist/tools/anthropic/index.js +2 -2
  54. package/dist/tools/brave/index.cjs +6 -6
  55. package/dist/tools/brave/index.d.cts +1 -1
  56. package/dist/tools/brave/index.d.ts +1 -1
  57. package/dist/tools/brave/index.js +3 -3
  58. package/dist/tools/exa/index.cjs +6 -6
  59. package/dist/tools/exa/index.d.cts +1 -1
  60. package/dist/tools/exa/index.d.ts +1 -1
  61. package/dist/tools/exa/index.js +3 -3
  62. package/dist/tools/google/index.cjs +6 -6
  63. package/dist/tools/google/index.d.cts +1 -1
  64. package/dist/tools/google/index.d.ts +1 -1
  65. package/dist/tools/google/index.js +4 -4
  66. package/dist/tools/openai/index.cjs +6 -6
  67. package/dist/tools/openai/index.d.cts +1 -1
  68. package/dist/tools/openai/index.d.ts +1 -1
  69. package/dist/tools/openai/index.js +3 -3
  70. package/dist/tools/searxng/index.cjs +6 -6
  71. package/dist/tools/searxng/index.d.cts +1 -1
  72. package/dist/tools/searxng/index.d.ts +1 -1
  73. package/dist/tools/searxng/index.js +3 -3
  74. package/dist/tools/serper/index.cjs +6 -6
  75. package/dist/tools/serper/index.d.cts +1 -1
  76. package/dist/tools/serper/index.d.ts +1 -1
  77. package/dist/tools/serper/index.js +3 -3
  78. package/dist/tools/tavily/index.cjs +6 -6
  79. package/dist/tools/tavily/index.d.cts +1 -1
  80. package/dist/tools/tavily/index.d.ts +1 -1
  81. package/dist/tools/tavily/index.js +3 -3
  82. package/dist/tools/web-search/index.cjs +7 -7
  83. package/dist/tools/web-search/index.d.cts +2 -2
  84. package/dist/tools/web-search/index.d.ts +2 -2
  85. package/dist/tools/web-search/index.js +4 -4
  86. package/dist/{tools-tmksfhUo.d.cts → tools-DcS6Aeao.d.cts} +7 -3
  87. package/dist/{tools-tmksfhUo.d.ts → tools-DcS6Aeao.d.ts} +7 -3
  88. package/dist/{types-BqwW3Baj.d.ts → types-BUYni9B8.d.ts} +1 -1
  89. package/dist/{types-BLw7mxtW.d.cts → types-Cvg4DUoc.d.cts} +1 -1
  90. package/dist/ui/index.cjs +1297 -596
  91. package/dist/ui/index.cjs.map +1 -1
  92. package/dist/ui/index.d.cts +136 -9
  93. package/dist/ui/index.d.ts +136 -9
  94. package/dist/ui/index.js +1128 -436
  95. package/dist/ui/index.js.map +1 -1
  96. package/package.json +6 -1
  97. package/dist/chunk-3AONOZLY.js.map +0 -1
  98. package/dist/chunk-B4YDIMP3.cjs.map +0 -1
  99. package/dist/chunk-EEH3L64W.js.map +0 -1
  100. package/dist/chunk-FLZO2FO3.js.map +0 -1
  101. package/dist/chunk-TPB7XED6.cjs.map +0 -1
  102. package/dist/chunk-XUR3IOPX.cjs.map +0 -1
@@ -0,0 +1,2020 @@
1
+ import { useCopilot, useSkillContext, AbstractChat, ReactChatState } from './chunk-I2XOCFHG.js';
2
+ import { ThreadManager, isConsoleCaptureActive, startConsoleCapture, isNetworkCaptureActive, startNetworkCapture, stopConsoleCapture, stopNetworkCapture, isScreenshotSupported, captureScreenshot, getConsoleLogs, getNetworkRequests, clearConsoleLogs, clearNetworkRequests, formatLogsForAI, formatRequestsForAI, detectIntent, streamSSE, zodObjectToInputSchema } from './chunk-PSNLKMZH.js';
3
+ import { createContext, useEffect, useState, useRef, useCallback, useMemo, useSyncExternalStore, useReducer, useContext } from 'react';
4
+ import * as z from 'zod';
5
+
6
+ function useAIActions(actions) {
7
+ const { registerAction, unregisterAction } = useCopilot();
8
+ useEffect(() => {
9
+ for (const action of actions) {
10
+ registerAction(action);
11
+ }
12
+ return () => {
13
+ for (const action of actions) {
14
+ unregisterAction(action.name);
15
+ }
16
+ };
17
+ }, [actions, registerAction, unregisterAction]);
18
+ }
19
+ function useAIAction(action) {
20
+ useAIActions([action]);
21
+ }
22
+ function useAITools(options = {}) {
23
+ const {
24
+ screenshot = false,
25
+ console: consoleCapture = false,
26
+ network = false,
27
+ requireConsent = true,
28
+ screenshotOptions,
29
+ consoleOptions,
30
+ networkOptions,
31
+ onConsentRequest,
32
+ autoStart = true
33
+ } = options;
34
+ const [isEnabled] = useState(screenshot || consoleCapture || network);
35
+ const [activeCaptures, setActiveCaptures] = useState({
36
+ console: false,
37
+ network: false
38
+ });
39
+ const [pendingConsent, setPendingConsent] = useState(null);
40
+ const consentResolverRef = useRef(null);
41
+ const rememberedConsentRef = useRef(/* @__PURE__ */ new Set());
42
+ useEffect(() => {
43
+ if (!autoStart || !isEnabled) return;
44
+ if (consoleCapture && !isConsoleCaptureActive()) {
45
+ startConsoleCapture(consoleOptions);
46
+ setActiveCaptures((prev) => ({ ...prev, console: true }));
47
+ }
48
+ if (network && !isNetworkCaptureActive()) {
49
+ startNetworkCapture(networkOptions);
50
+ setActiveCaptures((prev) => ({ ...prev, network: true }));
51
+ }
52
+ return () => {
53
+ stopConsoleCapture();
54
+ stopNetworkCapture();
55
+ };
56
+ }, [
57
+ autoStart,
58
+ isEnabled,
59
+ consoleCapture,
60
+ network,
61
+ consoleOptions,
62
+ networkOptions
63
+ ]);
64
+ const captureScreenshotFn = useCallback(
65
+ async (opts) => {
66
+ if (!screenshot) {
67
+ throw new Error("Screenshot capture is not enabled");
68
+ }
69
+ if (!isScreenshotSupported()) {
70
+ throw new Error(
71
+ "Screenshot capture is not supported in this environment"
72
+ );
73
+ }
74
+ return captureScreenshot({ ...screenshotOptions, ...opts });
75
+ },
76
+ [screenshot, screenshotOptions]
77
+ );
78
+ const getConsoleLogsFn = useCallback(
79
+ (opts) => {
80
+ if (!consoleCapture) {
81
+ return { logs: [], totalCaptured: 0 };
82
+ }
83
+ return getConsoleLogs({ ...consoleOptions, ...opts });
84
+ },
85
+ [consoleCapture, consoleOptions]
86
+ );
87
+ const getNetworkRequestsFn = useCallback(
88
+ (opts) => {
89
+ if (!network) {
90
+ return { requests: [], totalCaptured: 0 };
91
+ }
92
+ return getNetworkRequests({ ...networkOptions, ...opts });
93
+ },
94
+ [network, networkOptions]
95
+ );
96
+ const requestConsent = useCallback(
97
+ async (tools, reason = "") => {
98
+ const enabledTools = tools.filter((tool2) => {
99
+ if (tool2 === "screenshot") return screenshot;
100
+ if (tool2 === "console") return consoleCapture;
101
+ if (tool2 === "network") return network;
102
+ return false;
103
+ });
104
+ if (enabledTools.length === 0) {
105
+ return { approved: [], denied: [] };
106
+ }
107
+ if (!requireConsent) {
108
+ return { approved: enabledTools, denied: [] };
109
+ }
110
+ const needsConsent = enabledTools.filter(
111
+ (tool2) => !rememberedConsentRef.current.has(tool2)
112
+ );
113
+ if (needsConsent.length === 0) {
114
+ return { approved: enabledTools, denied: [] };
115
+ }
116
+ const request = {
117
+ tools: needsConsent,
118
+ reason,
119
+ keywords: []
120
+ };
121
+ if (onConsentRequest) {
122
+ const response = await onConsentRequest(request);
123
+ if (response.remember) {
124
+ response.approved.forEach(
125
+ (tool2) => rememberedConsentRef.current.add(tool2)
126
+ );
127
+ }
128
+ return response;
129
+ }
130
+ return new Promise((resolve) => {
131
+ setPendingConsent(request);
132
+ consentResolverRef.current = (response) => {
133
+ if (response.remember) {
134
+ response.approved.forEach(
135
+ (tool2) => rememberedConsentRef.current.add(tool2)
136
+ );
137
+ }
138
+ resolve(response);
139
+ };
140
+ });
141
+ },
142
+ [screenshot, consoleCapture, network, requireConsent, onConsentRequest]
143
+ );
144
+ const respondToConsent = useCallback((response) => {
145
+ if (consentResolverRef.current) {
146
+ consentResolverRef.current(response);
147
+ consentResolverRef.current = null;
148
+ }
149
+ setPendingConsent(null);
150
+ }, []);
151
+ const captureContext = useCallback(
152
+ async (tools) => {
153
+ const toolsToCapture = tools || ["screenshot", "console", "network"];
154
+ const context = {
155
+ timestamp: Date.now()
156
+ };
157
+ const captures = [];
158
+ if (toolsToCapture.includes("screenshot") && screenshot) {
159
+ captures.push(
160
+ captureScreenshotFn().then((result) => {
161
+ context.screenshot = result;
162
+ }).catch(() => {
163
+ })
164
+ );
165
+ }
166
+ if (toolsToCapture.includes("console") && consoleCapture) {
167
+ context.consoleLogs = getConsoleLogsFn();
168
+ }
169
+ if (toolsToCapture.includes("network") && network) {
170
+ context.networkRequests = getNetworkRequestsFn();
171
+ }
172
+ await Promise.all(captures);
173
+ return context;
174
+ },
175
+ [
176
+ screenshot,
177
+ consoleCapture,
178
+ network,
179
+ captureScreenshotFn,
180
+ getConsoleLogsFn,
181
+ getNetworkRequestsFn
182
+ ]
183
+ );
184
+ const startCapturing = useCallback(() => {
185
+ if (consoleCapture && !isConsoleCaptureActive()) {
186
+ startConsoleCapture(consoleOptions);
187
+ setActiveCaptures((prev) => ({ ...prev, console: true }));
188
+ }
189
+ if (network && !isNetworkCaptureActive()) {
190
+ startNetworkCapture(networkOptions);
191
+ setActiveCaptures((prev) => ({ ...prev, network: true }));
192
+ }
193
+ }, [consoleCapture, network, consoleOptions, networkOptions]);
194
+ const stopCapturing = useCallback(() => {
195
+ stopConsoleCapture();
196
+ stopNetworkCapture();
197
+ setActiveCaptures({ console: false, network: false });
198
+ }, []);
199
+ const clearCaptured = useCallback(() => {
200
+ clearConsoleLogs();
201
+ clearNetworkRequests();
202
+ }, []);
203
+ const formatForAI = useCallback((context) => {
204
+ const parts = [];
205
+ if (context.screenshot) {
206
+ parts.push(
207
+ `Screenshot captured (${context.screenshot.width}x${context.screenshot.height}, ${context.screenshot.format})`
208
+ );
209
+ }
210
+ if (context.consoleLogs && context.consoleLogs.logs.length > 0) {
211
+ parts.push(formatLogsForAI(context.consoleLogs.logs));
212
+ }
213
+ if (context.networkRequests && context.networkRequests.requests.length > 0) {
214
+ parts.push(formatRequestsForAI(context.networkRequests.requests));
215
+ }
216
+ return parts.length > 0 ? parts.join("\n\n---\n\n") : "No context captured.";
217
+ }, []);
218
+ const detectIntentFn = useCallback(
219
+ (message) => {
220
+ const result = detectIntent(message);
221
+ result.suggestedTools = result.suggestedTools.filter((tool2) => {
222
+ if (tool2 === "screenshot") return screenshot;
223
+ if (tool2 === "console") return consoleCapture;
224
+ if (tool2 === "network") return network;
225
+ return false;
226
+ });
227
+ return result;
228
+ },
229
+ [screenshot, consoleCapture, network]
230
+ );
231
+ return useMemo(
232
+ () => ({
233
+ isEnabled,
234
+ activeCaptures,
235
+ captureScreenshot: captureScreenshotFn,
236
+ getConsoleLogs: getConsoleLogsFn,
237
+ getNetworkRequests: getNetworkRequestsFn,
238
+ captureContext,
239
+ detectIntent: detectIntentFn,
240
+ requestConsent,
241
+ startCapturing,
242
+ stopCapturing,
243
+ clearCaptured,
244
+ formatForAI,
245
+ pendingConsent,
246
+ respondToConsent
247
+ }),
248
+ [
249
+ isEnabled,
250
+ activeCaptures,
251
+ captureScreenshotFn,
252
+ getConsoleLogsFn,
253
+ getNetworkRequestsFn,
254
+ captureContext,
255
+ detectIntentFn,
256
+ requestConsent,
257
+ startCapturing,
258
+ stopCapturing,
259
+ clearCaptured,
260
+ formatForAI,
261
+ pendingConsent,
262
+ respondToConsent
263
+ ]
264
+ );
265
+ }
266
+ function convertZodSchema(schema, _toolName) {
267
+ try {
268
+ const zodWithJsonSchema = z;
269
+ if (typeof zodWithJsonSchema.toJSONSchema === "function") {
270
+ const jsonSchema = zodWithJsonSchema.toJSONSchema(
271
+ schema
272
+ );
273
+ if (jsonSchema.type === "object") {
274
+ return {
275
+ type: "object",
276
+ properties: jsonSchema.properties || {},
277
+ required: jsonSchema.required
278
+ };
279
+ }
280
+ }
281
+ } catch {
282
+ }
283
+ return zodObjectToInputSchema(schema);
284
+ }
285
+ function useToolWithSchema(config, dependencies = []) {
286
+ const { registerTool, unregisterTool } = useCopilot();
287
+ const configRef = useRef(config);
288
+ configRef.current = config;
289
+ const inputSchema = useMemo(() => {
290
+ try {
291
+ return convertZodSchema(config.schema, config.name);
292
+ } catch (error) {
293
+ console.warn(
294
+ `[useToolWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
295
+ error
296
+ );
297
+ return {
298
+ type: "object",
299
+ properties: {}
300
+ };
301
+ }
302
+ }, [config.schema, config.name]);
303
+ useEffect(() => {
304
+ const tool2 = {
305
+ name: config.name,
306
+ description: config.description,
307
+ location: "client",
308
+ inputSchema,
309
+ handler: async (params, context) => {
310
+ return configRef.current.handler(params, context);
311
+ },
312
+ render: config.render,
313
+ available: config.available ?? true
314
+ };
315
+ registerTool(tool2);
316
+ return () => {
317
+ unregisterTool(config.name);
318
+ };
319
+ }, [config.name, inputSchema, ...dependencies]);
320
+ }
321
+ function useToolsWithSchema(tools, dependencies = []) {
322
+ const { registerTool, unregisterTool } = useCopilot();
323
+ const toolsRef = useRef(tools);
324
+ toolsRef.current = tools;
325
+ useEffect(() => {
326
+ const toolNames = [];
327
+ for (const config of tools) {
328
+ let inputSchema;
329
+ try {
330
+ inputSchema = convertZodSchema(config.schema, config.name);
331
+ } catch (error) {
332
+ console.warn(
333
+ `[useToolsWithSchema] Failed to convert Zod schema for tool "${config.name}"`,
334
+ error
335
+ );
336
+ inputSchema = { type: "object", properties: {} };
337
+ }
338
+ const tool2 = {
339
+ name: config.name,
340
+ description: config.description,
341
+ location: "client",
342
+ inputSchema,
343
+ handler: async (params, context) => {
344
+ const currentConfig = toolsRef.current.find(
345
+ (t) => t.name === config.name
346
+ );
347
+ if (currentConfig) {
348
+ return currentConfig.handler(params, context);
349
+ }
350
+ return { success: false, error: "Tool handler not found" };
351
+ },
352
+ available: config.available ?? true
353
+ };
354
+ registerTool(tool2);
355
+ toolNames.push(config.name);
356
+ }
357
+ return () => {
358
+ for (const name of toolNames) {
359
+ unregisterTool(name);
360
+ }
361
+ };
362
+ }, [tools.map((t) => t.name).join(","), ...dependencies]);
363
+ }
364
+ var CopilotContext = createContext(null);
365
+ function useCopilotContext() {
366
+ const context = useContext(CopilotContext);
367
+ if (!context) {
368
+ throw new Error("useCopilotContext must be used within a CopilotProvider");
369
+ }
370
+ return context;
371
+ }
372
+
373
+ // src/react/hooks/useToolExecutor.ts
374
+ function useToolExecutor() {
375
+ const {
376
+ registeredTools,
377
+ config,
378
+ chat,
379
+ addToolExecution,
380
+ updateToolExecution
381
+ } = useCopilotContext();
382
+ const toolsRef = useRef(registeredTools);
383
+ toolsRef.current = registeredTools;
384
+ const executeTool = useCallback(
385
+ async (toolCall) => {
386
+ const tool2 = toolsRef.current.find((t) => t.name === toolCall.name);
387
+ if (!tool2) {
388
+ return {
389
+ success: false,
390
+ error: `Unknown tool: ${toolCall.name}`
391
+ };
392
+ }
393
+ if (!tool2.handler) {
394
+ return {
395
+ success: false,
396
+ error: `Tool "${toolCall.name}" has no handler`
397
+ };
398
+ }
399
+ const execution = {
400
+ id: toolCall.id,
401
+ name: toolCall.name,
402
+ args: toolCall.input,
403
+ status: "executing",
404
+ timestamp: Date.now(),
405
+ approvalStatus: "none",
406
+ hidden: tool2.hidden
407
+ };
408
+ addToolExecution?.(execution);
409
+ try {
410
+ const startTime = Date.now();
411
+ const result = await tool2.handler(toolCall.input);
412
+ const duration = Date.now() - startTime;
413
+ updateToolExecution?.(toolCall.id, {
414
+ status: result.success ? "completed" : "error",
415
+ result,
416
+ error: result.error,
417
+ duration
418
+ });
419
+ return result;
420
+ } catch (error) {
421
+ const errorMessage = error instanceof Error ? error.message : "Tool execution failed";
422
+ updateToolExecution?.(toolCall.id, {
423
+ status: "error",
424
+ error: errorMessage
425
+ });
426
+ return {
427
+ success: false,
428
+ error: errorMessage
429
+ };
430
+ }
431
+ },
432
+ [addToolExecution, updateToolExecution]
433
+ );
434
+ const sendToolResult = useCallback(
435
+ async (toolCallId, result) => {
436
+ const runtimeUrl = config.runtimeUrl || config.cloud?.endpoint;
437
+ if (!runtimeUrl) {
438
+ console.warn(
439
+ "[useToolExecutor] No runtime URL configured, cannot send tool result"
440
+ );
441
+ return;
442
+ }
443
+ const baseUrl = runtimeUrl.replace(/\/chat\/?$/, "");
444
+ try {
445
+ const response = await fetch(`${baseUrl}/tool-result`, {
446
+ method: "POST",
447
+ headers: {
448
+ "Content-Type": "application/json"
449
+ },
450
+ body: JSON.stringify({
451
+ threadId: chat.threadId || "default",
452
+ toolCallId,
453
+ result
454
+ })
455
+ });
456
+ if (!response.ok) {
457
+ console.error(
458
+ "[useToolExecutor] Failed to send tool result:",
459
+ await response.text()
460
+ );
461
+ }
462
+ } catch (error) {
463
+ console.error("[useToolExecutor] Error sending tool result:", error);
464
+ }
465
+ },
466
+ [config.runtimeUrl, config.cloud?.endpoint, chat.threadId]
467
+ );
468
+ const getTool = useCallback((name) => {
469
+ return toolsRef.current.find((t) => t.name === name);
470
+ }, []);
471
+ const hasTool = useCallback((name) => {
472
+ return toolsRef.current.some((t) => t.name === name);
473
+ }, []);
474
+ return {
475
+ executeTool,
476
+ sendToolResult,
477
+ getTool,
478
+ hasTool
479
+ };
480
+ }
481
+ function useSuggestions(options = {}) {
482
+ const {
483
+ count = 3,
484
+ context,
485
+ suggestions: staticSuggestions,
486
+ autoRefresh = true
487
+ } = options;
488
+ const { chat, actions, config } = useCopilotContext();
489
+ const [suggestions, setSuggestions] = useState([]);
490
+ const [isLoading, setIsLoading] = useState(false);
491
+ const normalizedStatic = useMemo(
492
+ () => staticSuggestions?.map((s) => typeof s === "string" ? { text: s } : s),
493
+ [staticSuggestions]
494
+ );
495
+ const refresh = useCallback(async () => {
496
+ if (normalizedStatic) {
497
+ setSuggestions(normalizedStatic.slice(0, count));
498
+ return;
499
+ }
500
+ if (!config.cloud) {
501
+ return;
502
+ }
503
+ setIsLoading(true);
504
+ try {
505
+ const endpoint = config.cloud.endpoint || "https://api.yourgpt.ai/v1";
506
+ const response = await fetch(`${endpoint}/suggestions`, {
507
+ method: "POST",
508
+ headers: {
509
+ "Content-Type": "application/json",
510
+ Authorization: `Bearer ${config.cloud.apiKey}`
511
+ },
512
+ body: JSON.stringify({
513
+ botId: config.cloud.botId,
514
+ count,
515
+ context,
516
+ messages: chat.messages.slice(-5)
517
+ // Last 5 messages for context
518
+ })
519
+ });
520
+ if (response.ok) {
521
+ const data = await response.json();
522
+ setSuggestions(
523
+ data.suggestions.map(
524
+ (s) => typeof s === "string" ? { text: s } : s
525
+ )
526
+ );
527
+ }
528
+ } catch (error) {
529
+ console.error("Failed to fetch suggestions:", error);
530
+ } finally {
531
+ setIsLoading(false);
532
+ }
533
+ }, [config.cloud, count, context, chat.messages, normalizedStatic]);
534
+ const select = useCallback(
535
+ (suggestion) => {
536
+ const text = typeof suggestion === "string" ? suggestion : suggestion.text;
537
+ actions.sendMessage(text);
538
+ },
539
+ [actions]
540
+ );
541
+ useEffect(() => {
542
+ if (autoRefresh && chat.messages.length === 0) {
543
+ refresh();
544
+ }
545
+ }, [autoRefresh, chat.messages.length, refresh]);
546
+ return {
547
+ suggestions: normalizedStatic?.slice(0, count) || suggestions,
548
+ isLoading,
549
+ refresh,
550
+ select
551
+ };
552
+ }
553
+ function useAgent(options) {
554
+ const { name, initialState = {}, onStateChange } = options;
555
+ const { config } = useCopilotContext();
556
+ const [state, setStateInternal] = useState(initialState);
557
+ const [isRunning, setIsRunning] = useState(false);
558
+ const [nodeName, setNodeName] = useState(null);
559
+ const [error, setError] = useState(null);
560
+ const abortControllerRef = useRef(null);
561
+ const getEndpoint = useCallback(() => {
562
+ if (config.cloud) {
563
+ return `${config.cloud.endpoint || "https://api.yourgpt.ai/v1"}/agents/${name}`;
564
+ }
565
+ return `${config.runtimeUrl || "/api"}/agents/${name}`;
566
+ }, [config, name]);
567
+ const start = useCallback(
568
+ async (input) => {
569
+ setIsRunning(true);
570
+ setError(null);
571
+ abortControllerRef.current = new AbortController();
572
+ try {
573
+ const endpoint = getEndpoint();
574
+ const headers = {
575
+ "Content-Type": "application/json"
576
+ };
577
+ if (config.cloud?.apiKey) {
578
+ headers["Authorization"] = `Bearer ${config.cloud.apiKey}`;
579
+ }
580
+ const response = await fetch(`${endpoint}/start`, {
581
+ method: "POST",
582
+ headers,
583
+ body: JSON.stringify({
584
+ input: typeof input === "string" ? { message: input } : input,
585
+ state
586
+ }),
587
+ signal: abortControllerRef.current.signal
588
+ });
589
+ if (!response.ok) {
590
+ throw new Error(`Agent error: ${response.status}`);
591
+ }
592
+ for await (const event of streamSSE(response)) {
593
+ handleAgentEvent(event);
594
+ }
595
+ } catch (err) {
596
+ if (err.name !== "AbortError") {
597
+ setError(err instanceof Error ? err : new Error("Unknown error"));
598
+ }
599
+ } finally {
600
+ setIsRunning(false);
601
+ abortControllerRef.current = null;
602
+ }
603
+ },
604
+ [config, getEndpoint, state]
605
+ );
606
+ const handleAgentEvent = useCallback(
607
+ (event) => {
608
+ if (event.type === "error") {
609
+ setError(new Error(event.message));
610
+ return;
611
+ }
612
+ if ("state" in event && event.state) {
613
+ setStateInternal(event.state);
614
+ onStateChange?.(event.state);
615
+ }
616
+ if ("nodeName" in event && event.nodeName) {
617
+ setNodeName(event.nodeName);
618
+ }
619
+ },
620
+ [onStateChange]
621
+ );
622
+ const stop = useCallback(() => {
623
+ abortControllerRef.current?.abort();
624
+ }, []);
625
+ const setState = useCallback(
626
+ (partialState) => {
627
+ setStateInternal((prev) => {
628
+ const newState = { ...prev, ...partialState };
629
+ onStateChange?.(newState);
630
+ return newState;
631
+ });
632
+ },
633
+ [onStateChange]
634
+ );
635
+ useEffect(() => {
636
+ return () => {
637
+ abortControllerRef.current?.abort();
638
+ };
639
+ }, []);
640
+ return {
641
+ state,
642
+ isRunning,
643
+ nodeName,
644
+ start,
645
+ stop,
646
+ setState,
647
+ error
648
+ };
649
+ }
650
+
651
+ // src/react/utils/knowledge-base.ts
652
+ var KNOWLEDGE_BASE_API = "https://api.yourgpt.ai/chatbot/v1/searchIndexDocument";
653
+ async function searchKnowledgeBase(query, config) {
654
+ try {
655
+ const response = await fetch(KNOWLEDGE_BASE_API, {
656
+ method: "POST",
657
+ headers: {
658
+ accept: "*/*",
659
+ "content-type": "application/json",
660
+ authorization: `Bearer ${config.token}`
661
+ },
662
+ body: JSON.stringify({
663
+ project_uid: config.projectUid,
664
+ query,
665
+ page: 1,
666
+ limit: String(config.limit || 10),
667
+ app_id: config.appId || "1"
668
+ })
669
+ });
670
+ if (!response.ok) {
671
+ return {
672
+ success: false,
673
+ results: [],
674
+ error: `API error: ${response.status} ${response.statusText}`
675
+ };
676
+ }
677
+ const data = await response.json();
678
+ const results = (data.data || data.results || []).map((item) => ({
679
+ id: item.id || item._id || String(Math.random()),
680
+ title: item.title || item.name || void 0,
681
+ content: item.content || item.text || item.snippet || "",
682
+ score: item.score || item.relevance || void 0,
683
+ url: item.url || item.source_url || void 0,
684
+ metadata: item.metadata || {}
685
+ }));
686
+ return {
687
+ success: true,
688
+ results,
689
+ total: data.total || results.length,
690
+ page: data.page || 1
691
+ };
692
+ } catch (error) {
693
+ return {
694
+ success: false,
695
+ results: [],
696
+ error: error instanceof Error ? error.message : "Unknown error"
697
+ };
698
+ }
699
+ }
700
+ function formatKnowledgeResultsForAI(results) {
701
+ if (results.length === 0) {
702
+ return "No relevant documents found in the knowledge base.";
703
+ }
704
+ return results.map((result, index) => {
705
+ const parts = [`[${index + 1}]`];
706
+ if (result.title) parts.push(`**${result.title}**`);
707
+ parts.push(result.content);
708
+ if (result.url) parts.push(`Source: ${result.url}`);
709
+ return parts.join("\n");
710
+ }).join("\n\n---\n\n");
711
+ }
712
+
713
+ // src/react/hooks/useKnowledgeBase.ts
714
+ function useKnowledgeBase(config) {
715
+ const { registerTool, unregisterTool } = useCopilot();
716
+ const configRef = useRef(config);
717
+ configRef.current = config;
718
+ const handleSearch = useCallback(
719
+ async (params) => {
720
+ const query = params.query;
721
+ if (!query) {
722
+ return {
723
+ success: false,
724
+ error: "Query is required"
725
+ };
726
+ }
727
+ const currentConfig = configRef.current;
728
+ const kbConfig = {
729
+ projectUid: currentConfig.projectUid,
730
+ token: currentConfig.token,
731
+ appId: currentConfig.appId,
732
+ limit: currentConfig.limit || 5
733
+ };
734
+ const response = await searchKnowledgeBase(
735
+ query,
736
+ kbConfig
737
+ );
738
+ if (!response.success) {
739
+ return {
740
+ success: false,
741
+ error: response.error || "Knowledge base search failed"
742
+ };
743
+ }
744
+ const formattedResults = formatKnowledgeResultsForAI(response.results);
745
+ return {
746
+ success: true,
747
+ message: formattedResults,
748
+ data: {
749
+ resultCount: response.results.length,
750
+ total: response.total
751
+ }
752
+ };
753
+ },
754
+ []
755
+ );
756
+ useEffect(() => {
757
+ if (config.enabled === false) {
758
+ return;
759
+ }
760
+ registerTool({
761
+ name: "search_knowledge",
762
+ 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.",
763
+ location: "client",
764
+ inputSchema: {
765
+ type: "object",
766
+ properties: {
767
+ query: {
768
+ type: "string",
769
+ description: "The search query to find relevant information in the knowledge base"
770
+ }
771
+ },
772
+ required: ["query"]
773
+ },
774
+ handler: handleSearch
775
+ });
776
+ return () => {
777
+ unregisterTool("search_knowledge");
778
+ };
779
+ }, [
780
+ config.enabled,
781
+ config.projectUid,
782
+ config.token,
783
+ registerTool,
784
+ unregisterTool,
785
+ handleSearch
786
+ ]);
787
+ }
788
+ var DEFAULT_CAPABILITIES = {
789
+ supportsVision: false,
790
+ supportsTools: true,
791
+ supportsThinking: false,
792
+ supportsStreaming: true,
793
+ supportsPDF: false,
794
+ supportsAudio: false,
795
+ supportsVideo: false,
796
+ maxTokens: 8192,
797
+ supportedImageTypes: [],
798
+ supportsJsonMode: false,
799
+ supportsSystemMessages: true
800
+ };
801
+ function useCapabilities() {
802
+ const { config } = useCopilotContext();
803
+ const [capabilities, setCapabilities] = useState(DEFAULT_CAPABILITIES);
804
+ const [provider, setProvider] = useState("unknown");
805
+ const [model, setModel] = useState("unknown");
806
+ const [supportedModels, setSupportedModels] = useState([]);
807
+ const [isLoading, setIsLoading] = useState(true);
808
+ const [error, setError] = useState(null);
809
+ const capabilitiesUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/chat\/?$/, "/capabilities") : null;
810
+ const fetchCapabilities = useCallback(async () => {
811
+ if (!capabilitiesUrl) {
812
+ setIsLoading(false);
813
+ return;
814
+ }
815
+ try {
816
+ setIsLoading(true);
817
+ setError(null);
818
+ const response = await fetch(capabilitiesUrl);
819
+ if (!response.ok) {
820
+ throw new Error(`Failed to fetch capabilities: ${response.status}`);
821
+ }
822
+ const data = await response.json();
823
+ setCapabilities(data.capabilities);
824
+ setProvider(data.provider);
825
+ setModel(data.model);
826
+ setSupportedModels(data.supportedModels);
827
+ } catch (err) {
828
+ setError(err instanceof Error ? err : new Error("Unknown error"));
829
+ } finally {
830
+ setIsLoading(false);
831
+ }
832
+ }, [capabilitiesUrl]);
833
+ useEffect(() => {
834
+ fetchCapabilities();
835
+ }, [fetchCapabilities]);
836
+ return {
837
+ /** Current model capabilities */
838
+ capabilities,
839
+ /** Current provider name */
840
+ provider,
841
+ /** Current model ID */
842
+ model,
843
+ /** List of supported models for current provider */
844
+ supportedModels,
845
+ /** Whether capabilities are being loaded */
846
+ isLoading,
847
+ /** Error if fetch failed */
848
+ error,
849
+ /** Refetch capabilities */
850
+ refetch: fetchCapabilities
851
+ };
852
+ }
853
+ function useFeatureSupport(feature) {
854
+ const { capabilities } = useCapabilities();
855
+ return capabilities[feature] ?? false;
856
+ }
857
+ function useSupportedMediaTypes() {
858
+ const { capabilities } = useCapabilities();
859
+ return {
860
+ /** Supported image MIME types */
861
+ imageTypes: capabilities.supportedImageTypes || [],
862
+ /** Supported audio MIME types */
863
+ audioTypes: capabilities.supportedAudioTypes || [],
864
+ /** Supported video MIME types */
865
+ videoTypes: capabilities.supportedVideoTypes || [],
866
+ /** Whether any image types are supported */
867
+ hasImageSupport: (capabilities.supportedImageTypes?.length ?? 0) > 0,
868
+ /** Whether any audio types are supported */
869
+ hasAudioSupport: (capabilities.supportedAudioTypes?.length ?? 0) > 0,
870
+ /** Whether any video types are supported */
871
+ hasVideoSupport: (capabilities.supportedVideoTypes?.length ?? 0) > 0
872
+ };
873
+ }
874
+ function useDevLogger() {
875
+ const ctx = useCopilotContext();
876
+ return useMemo(() => {
877
+ const toolExecutions = (ctx.agentLoop?.toolExecutions || []).map(
878
+ (exec) => ({
879
+ id: exec.id,
880
+ name: exec.name,
881
+ status: exec.status,
882
+ approvalStatus: exec.approvalStatus || "not_required"
883
+ })
884
+ );
885
+ const pendingApprovalsCount = ctx.pendingApprovals?.length || 0;
886
+ const registeredTools = (ctx.registeredTools || []).map((tool2) => ({
887
+ name: tool2.name,
888
+ location: tool2.location || "client"
889
+ }));
890
+ const registeredActions = (ctx.registeredActions || []).map((action) => ({
891
+ name: action.name
892
+ }));
893
+ const storedPermissions = (ctx.storedPermissions || []).map((p) => ({
894
+ toolName: p.toolName,
895
+ level: p.level
896
+ }));
897
+ return {
898
+ chat: {
899
+ isLoading: ctx.chat?.isLoading || false,
900
+ messageCount: ctx.chat?.messages?.length || 0,
901
+ threadId: ctx.chat?.threadId || "none",
902
+ error: ctx.chat?.error?.message || null
903
+ },
904
+ tools: {
905
+ isEnabled: !!ctx.toolsConfig,
906
+ isCapturing: ctx.tools?.isCapturing || false,
907
+ pendingConsent: !!ctx.tools?.pendingConsent
908
+ },
909
+ agentLoop: {
910
+ toolExecutions,
911
+ pendingApprovals: pendingApprovalsCount,
912
+ iteration: ctx.agentLoop?.iteration || 0,
913
+ maxIterations: ctx.agentLoop?.maxIterations || 10
914
+ },
915
+ registered: {
916
+ tools: registeredTools,
917
+ actions: registeredActions,
918
+ contextCount: ctx.contextTree?.length || 0
919
+ },
920
+ permissions: {
921
+ stored: storedPermissions,
922
+ loaded: ctx.permissionsLoaded || false
923
+ },
924
+ config: {
925
+ runtimeUrl: ctx.config?.runtimeUrl || ctx.config?.cloud?.endpoint || ""
926
+ }
927
+ };
928
+ }, [
929
+ ctx.chat,
930
+ ctx.tools,
931
+ ctx.toolsConfig,
932
+ ctx.agentLoop,
933
+ ctx.pendingApprovals,
934
+ ctx.registeredTools,
935
+ ctx.registeredActions,
936
+ ctx.contextTree,
937
+ ctx.storedPermissions,
938
+ ctx.permissionsLoaded,
939
+ ctx.config
940
+ ]);
941
+ }
942
+
943
+ // src/react/internal/ReactThreadManagerState.ts
944
+ var ReactThreadManagerState = class {
945
+ constructor(initialThreads) {
946
+ this._threads = [];
947
+ this._currentThreadId = null;
948
+ this._currentThread = null;
949
+ this._loadStatus = "idle";
950
+ this._error = void 0;
951
+ // Callbacks for React subscriptions (useSyncExternalStore)
952
+ this.subscribers = /* @__PURE__ */ new Set();
953
+ // ============================================
954
+ // Subscription (for useSyncExternalStore)
955
+ // ============================================
956
+ /**
957
+ * Subscribe to state changes.
958
+ * Returns an unsubscribe function.
959
+ *
960
+ * @example
961
+ * ```tsx
962
+ * const threads = useSyncExternalStore(
963
+ * state.subscribe,
964
+ * () => state.threads
965
+ * );
966
+ * ```
967
+ */
968
+ this.subscribe = (callback) => {
969
+ this.subscribers.add(callback);
970
+ return () => {
971
+ this.subscribers.delete(callback);
972
+ };
973
+ };
974
+ if (initialThreads) {
975
+ this._threads = initialThreads;
976
+ }
977
+ }
978
+ // ============================================
979
+ // Getters
980
+ // ============================================
981
+ get threads() {
982
+ return this._threads;
983
+ }
984
+ get currentThreadId() {
985
+ return this._currentThreadId;
986
+ }
987
+ get currentThread() {
988
+ return this._currentThread;
989
+ }
990
+ get loadStatus() {
991
+ return this._loadStatus;
992
+ }
993
+ get error() {
994
+ return this._error;
995
+ }
996
+ // ============================================
997
+ // Setters (trigger reactivity)
998
+ // ============================================
999
+ set threads(value) {
1000
+ this._threads = value;
1001
+ this.notify();
1002
+ }
1003
+ // ============================================
1004
+ // Mutations
1005
+ // ============================================
1006
+ setThreads(threads) {
1007
+ this._threads = threads;
1008
+ this.notify();
1009
+ }
1010
+ setCurrentThread(thread) {
1011
+ this._currentThread = thread;
1012
+ this._currentThreadId = thread?.id ?? null;
1013
+ this.notify();
1014
+ }
1015
+ setCurrentThreadId(id) {
1016
+ this._currentThreadId = id;
1017
+ this.notify();
1018
+ }
1019
+ addThread(thread) {
1020
+ this._threads = [thread, ...this._threads];
1021
+ this.notify();
1022
+ }
1023
+ updateThread(id, updates) {
1024
+ this._threads = this._threads.map(
1025
+ (t) => t.id === id ? { ...t, ...updates } : t
1026
+ );
1027
+ if (updates.updatedAt) {
1028
+ this._threads = [...this._threads].sort(
1029
+ (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
1030
+ );
1031
+ }
1032
+ if (this._currentThread?.id === id) {
1033
+ this._currentThread = { ...this._currentThread, ...updates };
1034
+ }
1035
+ this.notify();
1036
+ }
1037
+ removeThread(id) {
1038
+ this._threads = this._threads.filter((t) => t.id !== id);
1039
+ if (this._currentThreadId === id) {
1040
+ this._currentThreadId = null;
1041
+ this._currentThread = null;
1042
+ }
1043
+ this.notify();
1044
+ }
1045
+ setLoadStatus(status) {
1046
+ this._loadStatus = status;
1047
+ this.notify();
1048
+ }
1049
+ setError(error) {
1050
+ this._error = error;
1051
+ this.notify();
1052
+ }
1053
+ // ============================================
1054
+ // Snapshots (for useSyncExternalStore)
1055
+ // ============================================
1056
+ getThreadsSnapshot() {
1057
+ return this._threads;
1058
+ }
1059
+ getCurrentThreadSnapshot() {
1060
+ return this._currentThread;
1061
+ }
1062
+ getLoadStatusSnapshot() {
1063
+ return this._loadStatus;
1064
+ }
1065
+ getErrorSnapshot() {
1066
+ return this._error;
1067
+ }
1068
+ // ============================================
1069
+ // Private Methods
1070
+ // ============================================
1071
+ notify() {
1072
+ this.subscribers.forEach((cb) => cb());
1073
+ }
1074
+ /**
1075
+ * Cleanup subscriptions
1076
+ */
1077
+ dispose() {
1078
+ this.subscribers.clear();
1079
+ }
1080
+ };
1081
+ function createReactThreadManagerState(initialThreads) {
1082
+ return new ReactThreadManagerState(initialThreads);
1083
+ }
1084
+
1085
+ // src/react/internal/ReactThreadManager.ts
1086
+ var _ReactThreadManager = class _ReactThreadManager extends ThreadManager {
1087
+ constructor(config = {}, callbacks = {}) {
1088
+ const reactState = new ReactThreadManagerState();
1089
+ super({ ...config, state: reactState }, callbacks);
1090
+ // ============================================
1091
+ // Subscription Methods (for useSyncExternalStore)
1092
+ // ============================================
1093
+ /**
1094
+ * Subscribe to state changes
1095
+ * Use with useSyncExternalStore
1096
+ */
1097
+ this.subscribe = (callback) => {
1098
+ return this.state.subscribe(callback);
1099
+ };
1100
+ // ============================================
1101
+ // Snapshot Getters (for useSyncExternalStore)
1102
+ // ============================================
1103
+ /**
1104
+ * Get threads snapshot
1105
+ */
1106
+ this.getThreadsSnapshot = () => {
1107
+ return this.state.getThreadsSnapshot();
1108
+ };
1109
+ /**
1110
+ * Get current thread snapshot
1111
+ */
1112
+ this.getCurrentThreadSnapshot = () => {
1113
+ return this.state.getCurrentThreadSnapshot();
1114
+ };
1115
+ /**
1116
+ * Get current thread ID snapshot
1117
+ */
1118
+ this.getCurrentThreadIdSnapshot = () => {
1119
+ return this.state.currentThreadId;
1120
+ };
1121
+ /**
1122
+ * Get load status snapshot
1123
+ */
1124
+ this.getLoadStatusSnapshot = () => {
1125
+ return this.state.getLoadStatusSnapshot();
1126
+ };
1127
+ /**
1128
+ * Get error snapshot
1129
+ */
1130
+ this.getErrorSnapshot = () => {
1131
+ return this.state.getErrorSnapshot();
1132
+ };
1133
+ /**
1134
+ * Get isLoading snapshot
1135
+ */
1136
+ this.getIsLoadingSnapshot = () => {
1137
+ return this.state.getLoadStatusSnapshot() === "loading";
1138
+ };
1139
+ /**
1140
+ * Get threads snapshot for server (always empty for hydration consistency)
1141
+ */
1142
+ this.getThreadsServerSnapshot = () => {
1143
+ return _ReactThreadManager.EMPTY_THREADS;
1144
+ };
1145
+ /**
1146
+ * Get current thread snapshot for server (always null)
1147
+ */
1148
+ this.getCurrentThreadServerSnapshot = () => {
1149
+ return null;
1150
+ };
1151
+ /**
1152
+ * Get current thread ID snapshot for server (always null)
1153
+ */
1154
+ this.getCurrentThreadIdServerSnapshot = () => {
1155
+ return null;
1156
+ };
1157
+ /**
1158
+ * Get load status snapshot for server (always "idle")
1159
+ */
1160
+ this.getLoadStatusServerSnapshot = () => {
1161
+ return _ReactThreadManager.IDLE_STATUS;
1162
+ };
1163
+ /**
1164
+ * Get error snapshot for server (always undefined)
1165
+ */
1166
+ this.getErrorServerSnapshot = () => {
1167
+ return void 0;
1168
+ };
1169
+ /**
1170
+ * Get isLoading snapshot for server (always false)
1171
+ */
1172
+ this.getIsLoadingServerSnapshot = () => {
1173
+ return false;
1174
+ };
1175
+ }
1176
+ // ============================================
1177
+ // Cleanup
1178
+ // ============================================
1179
+ /**
1180
+ * Dispose of the manager
1181
+ */
1182
+ async dispose() {
1183
+ this.state.dispose();
1184
+ await super.dispose();
1185
+ }
1186
+ };
1187
+ // ============================================
1188
+ // Server Snapshots (for SSR - stable cached values)
1189
+ // ============================================
1190
+ // Cached values for server snapshots (must be stable references)
1191
+ _ReactThreadManager.EMPTY_THREADS = [];
1192
+ _ReactThreadManager.IDLE_STATUS = "idle";
1193
+ var ReactThreadManager = _ReactThreadManager;
1194
+ function createReactThreadManager(config, callbacks) {
1195
+ return new ReactThreadManager(config, callbacks);
1196
+ }
1197
+
1198
+ // src/react/hooks/useThreadManager.ts
1199
+ var defaultManager = null;
1200
+ function getDefaultManager() {
1201
+ if (!defaultManager) {
1202
+ defaultManager = createReactThreadManager();
1203
+ }
1204
+ return defaultManager;
1205
+ }
1206
+ var internalManager = null;
1207
+ function getInternalManager(config) {
1208
+ if (!internalManager) {
1209
+ internalManager = createReactThreadManager(
1210
+ {
1211
+ adapter: config.adapter,
1212
+ saveDebounce: config.saveDebounce,
1213
+ autoLoad: config.autoLoad,
1214
+ autoRestoreLastThread: config.autoRestoreLastThread
1215
+ },
1216
+ config.callbacks
1217
+ );
1218
+ }
1219
+ return internalManager;
1220
+ }
1221
+ function useThreadManager(config) {
1222
+ const manager = useMemo(() => {
1223
+ if (!config) {
1224
+ return getDefaultManager();
1225
+ }
1226
+ if (!config.adapter) {
1227
+ return getInternalManager(config);
1228
+ }
1229
+ return createReactThreadManager(
1230
+ {
1231
+ adapter: config.adapter,
1232
+ saveDebounce: config.saveDebounce,
1233
+ autoLoad: config.autoLoad,
1234
+ autoRestoreLastThread: config.autoRestoreLastThread
1235
+ },
1236
+ config.callbacks
1237
+ );
1238
+ }, [
1239
+ config?.adapter,
1240
+ config?.saveDebounce,
1241
+ config?.autoLoad,
1242
+ config?.autoRestoreLastThread
1243
+ // Note: callbacks are intentionally not in deps to avoid recreating manager
1244
+ ]);
1245
+ const threads = useSyncExternalStore(
1246
+ manager.subscribe,
1247
+ manager.getThreadsSnapshot,
1248
+ manager.getThreadsServerSnapshot
1249
+ // SSR - always empty array
1250
+ );
1251
+ const currentThread = useSyncExternalStore(
1252
+ manager.subscribe,
1253
+ manager.getCurrentThreadSnapshot,
1254
+ manager.getCurrentThreadServerSnapshot
1255
+ // SSR - always null
1256
+ );
1257
+ const currentThreadId = useSyncExternalStore(
1258
+ manager.subscribe,
1259
+ manager.getCurrentThreadIdSnapshot,
1260
+ manager.getCurrentThreadIdServerSnapshot
1261
+ // SSR - always null
1262
+ );
1263
+ const loadStatus = useSyncExternalStore(
1264
+ manager.subscribe,
1265
+ manager.getLoadStatusSnapshot,
1266
+ manager.getLoadStatusServerSnapshot
1267
+ // SSR - always "idle"
1268
+ );
1269
+ const error = useSyncExternalStore(
1270
+ manager.subscribe,
1271
+ manager.getErrorSnapshot,
1272
+ manager.getErrorServerSnapshot
1273
+ // SSR - always undefined
1274
+ );
1275
+ const isLoading = useSyncExternalStore(
1276
+ manager.subscribe,
1277
+ manager.getIsLoadingSnapshot,
1278
+ manager.getIsLoadingServerSnapshot
1279
+ // SSR - always false
1280
+ );
1281
+ useEffect(() => {
1282
+ return () => {
1283
+ if (config?.adapter && manager !== defaultManager && manager !== internalManager) {
1284
+ manager.dispose();
1285
+ }
1286
+ };
1287
+ }, [manager, config]);
1288
+ useEffect(() => {
1289
+ const handleBeforeUnload = () => {
1290
+ if (manager.hasPendingChanges) {
1291
+ manager.saveNow().catch(() => {
1292
+ });
1293
+ }
1294
+ };
1295
+ if (typeof window !== "undefined") {
1296
+ window.addEventListener("beforeunload", handleBeforeUnload);
1297
+ return () => {
1298
+ window.removeEventListener("beforeunload", handleBeforeUnload);
1299
+ };
1300
+ }
1301
+ }, [manager]);
1302
+ const createThread = useCallback(
1303
+ (options) => manager.createThread(options),
1304
+ [manager]
1305
+ );
1306
+ const switchThread = useCallback(
1307
+ (id) => manager.switchThread(id),
1308
+ [manager]
1309
+ );
1310
+ const updateCurrentThread = useCallback(
1311
+ (updates) => manager.updateCurrentThread(updates),
1312
+ [manager]
1313
+ );
1314
+ const deleteThread = useCallback(
1315
+ (id) => manager.deleteThread(id),
1316
+ [manager]
1317
+ );
1318
+ const clearCurrentThread = useCallback(
1319
+ () => manager.clearCurrentThread(),
1320
+ [manager]
1321
+ );
1322
+ const refreshThreads = useCallback(() => manager.loadThreads(), [manager]);
1323
+ const saveNow = useCallback(() => manager.saveNow(), [manager]);
1324
+ const clearAllThreads = useCallback(
1325
+ () => manager.clearAllThreads(),
1326
+ [manager]
1327
+ );
1328
+ const messages = useMemo(
1329
+ () => currentThread?.messages ?? [],
1330
+ [currentThread]
1331
+ );
1332
+ const setMessages = useCallback(
1333
+ (newMessages) => updateCurrentThread({ messages: newMessages }),
1334
+ [updateCurrentThread]
1335
+ );
1336
+ const hasPendingChanges = manager.hasPendingChanges;
1337
+ return {
1338
+ // State
1339
+ threads,
1340
+ currentThread,
1341
+ currentThreadId,
1342
+ isLoading,
1343
+ loadStatus,
1344
+ error,
1345
+ // Actions
1346
+ createThread,
1347
+ switchThread,
1348
+ updateCurrentThread,
1349
+ deleteThread,
1350
+ clearCurrentThread,
1351
+ refreshThreads,
1352
+ saveNow,
1353
+ clearAllThreads,
1354
+ // Utilities
1355
+ messages,
1356
+ setMessages,
1357
+ hasPendingChanges
1358
+ };
1359
+ }
1360
+
1361
+ // src/react/hooks/useThread.ts
1362
+ function useThread() {
1363
+ const { threadId, setActiveThread, renewSession, sessionStatus } = useCopilot();
1364
+ return {
1365
+ threadId,
1366
+ sessionStatus,
1367
+ switchThread: setActiveThread,
1368
+ newThread: () => setActiveThread(null),
1369
+ renewSession
1370
+ };
1371
+ }
1372
+ function useMCPUIIntents(config = {}) {
1373
+ const {
1374
+ onToolCall,
1375
+ onIntent,
1376
+ onPrompt,
1377
+ onNotify,
1378
+ onLink,
1379
+ requireConsent = { tool: false, link: true }
1380
+ } = config;
1381
+ const handleIntent = useCallback(
1382
+ async (intent, context) => {
1383
+ switch (intent.type) {
1384
+ case "tool": {
1385
+ if (requireConsent.tool) ;
1386
+ await onToolCall?.(intent.name, intent.arguments, context);
1387
+ break;
1388
+ }
1389
+ case "intent": {
1390
+ await onIntent?.(intent.action, intent.data, context);
1391
+ break;
1392
+ }
1393
+ case "prompt": {
1394
+ onPrompt?.(intent.text, context);
1395
+ break;
1396
+ }
1397
+ case "notify": {
1398
+ onNotify?.(intent.message, intent.level, context);
1399
+ break;
1400
+ }
1401
+ case "link": {
1402
+ const shouldContinue = onLink?.(intent.url, intent.newTab, context);
1403
+ if (shouldContinue === false) {
1404
+ break;
1405
+ }
1406
+ if (requireConsent.link) {
1407
+ const isSafeUrl = intent.url.startsWith("https://") || intent.url.startsWith("http://localhost");
1408
+ if (!isSafeUrl) {
1409
+ console.warn(
1410
+ "[MCP-UI] Blocked potentially unsafe link:",
1411
+ intent.url
1412
+ );
1413
+ break;
1414
+ }
1415
+ }
1416
+ if (typeof window !== "undefined") {
1417
+ if (intent.newTab !== false) {
1418
+ window.open(intent.url, "_blank", "noopener,noreferrer");
1419
+ } else {
1420
+ window.location.href = intent.url;
1421
+ }
1422
+ }
1423
+ break;
1424
+ }
1425
+ default: {
1426
+ console.warn(
1427
+ "[MCP-UI] Unknown intent type:",
1428
+ intent.type
1429
+ );
1430
+ }
1431
+ }
1432
+ },
1433
+ [onToolCall, onIntent, onPrompt, onNotify, onLink, requireConsent]
1434
+ );
1435
+ return useMemo(
1436
+ () => ({
1437
+ handleIntent
1438
+ }),
1439
+ [handleIntent]
1440
+ );
1441
+ }
1442
+ function createMessageIntentHandler(sendMessage) {
1443
+ return {
1444
+ onIntent: async (action, data) => {
1445
+ const dataStr = data ? ` with ${JSON.stringify(data)}` : "";
1446
+ await sendMessage(`User action: ${action}${dataStr}`);
1447
+ },
1448
+ onPrompt: (text) => {
1449
+ sendMessage(text);
1450
+ },
1451
+ onNotify: (message, level) => {
1452
+ if (level === "error") {
1453
+ sendMessage(`Error: ${message}`);
1454
+ }
1455
+ }
1456
+ };
1457
+ }
1458
+ function createToolIntentHandler(callTool) {
1459
+ return {
1460
+ onToolCall: async (name, args) => {
1461
+ await callTool(name, args);
1462
+ }
1463
+ };
1464
+ }
1465
+ function getLastResponseUsage(messages) {
1466
+ for (let i = messages.length - 1; i >= 0; i--) {
1467
+ const msg = messages[i];
1468
+ if (msg.role === "assistant" && msg.metadata?.usage) {
1469
+ const u = msg.metadata.usage;
1470
+ const prompt = u.prompt_tokens ?? 0;
1471
+ const completion = u.completion_tokens ?? 0;
1472
+ return {
1473
+ prompt_tokens: prompt,
1474
+ completion_tokens: completion,
1475
+ total_tokens: u.total_tokens ?? prompt + completion
1476
+ };
1477
+ }
1478
+ }
1479
+ return null;
1480
+ }
1481
+ function useContextStats() {
1482
+ const { contextChars, contextUsage, registeredTools, messages } = useCopilot();
1483
+ const toolCount = useMemo(() => registeredTools.length, [registeredTools]);
1484
+ const messageCount = useMemo(
1485
+ () => messages.filter((m) => m.role !== "system").length,
1486
+ [messages]
1487
+ );
1488
+ const totalTokens = useMemo(() => {
1489
+ if (contextUsage) return contextUsage.total.tokens;
1490
+ return Math.ceil(contextChars / 3.5);
1491
+ }, [contextUsage, contextChars]);
1492
+ const usagePercent = useMemo(() => {
1493
+ if (contextUsage) return contextUsage.total.percent;
1494
+ return 0;
1495
+ }, [contextUsage]);
1496
+ const lastResponseUsage = useMemo(
1497
+ () => getLastResponseUsage(messages),
1498
+ [messages]
1499
+ );
1500
+ return {
1501
+ contextUsage,
1502
+ totalTokens,
1503
+ usagePercent,
1504
+ contextChars,
1505
+ toolCount,
1506
+ messageCount,
1507
+ lastResponseUsage
1508
+ };
1509
+ }
1510
+ var DEV_CONTENT_WARN_THRESHOLD = 2e3;
1511
+ function useSkill(skill) {
1512
+ const { register, unregister } = useSkillContext();
1513
+ if (process.env.NODE_ENV !== "production" && skill.source.type === "inline" && skill.source.content.length > DEV_CONTENT_WARN_THRESHOLD) {
1514
+ console.warn(
1515
+ `[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.`
1516
+ );
1517
+ }
1518
+ useEffect(() => {
1519
+ if (skill.source.type !== "inline") {
1520
+ console.warn(
1521
+ `[copilot-sdk/skills] useSkill only supports inline skills client-side. Skill "${skill.name}" has source type "${skill.source.type}" and will be skipped.`
1522
+ );
1523
+ return;
1524
+ }
1525
+ const resolved = {
1526
+ ...skill,
1527
+ content: skill.source.content
1528
+ };
1529
+ register(resolved);
1530
+ return () => {
1531
+ unregister(skill.name);
1532
+ };
1533
+ }, [
1534
+ skill.name,
1535
+ skill.source.type === "inline" ? skill.source.content : "",
1536
+ skill.strategy,
1537
+ skill.description
1538
+ ]);
1539
+ }
1540
+ function useSkillStatus() {
1541
+ const { skills, registry } = useSkillContext();
1542
+ const has = useCallback(
1543
+ (name) => registry.has(name),
1544
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1545
+ [skills]
1546
+ );
1547
+ return {
1548
+ skills,
1549
+ count: skills.length,
1550
+ has
1551
+ };
1552
+ }
1553
+ function useMessageCheckpoints() {
1554
+ const { messages, setMessages } = useCopilot();
1555
+ const checkpointMapRef = useRef(/* @__PURE__ */ new Map());
1556
+ const prevUserMsgCountRef = useRef(0);
1557
+ const [revision, bump] = useReducer((n) => n + 1, 0);
1558
+ useEffect(() => {
1559
+ const userMessages = messages.filter((m) => m.role === "user");
1560
+ const count = userMessages.length;
1561
+ if (count > prevUserMsgCountRef.current) {
1562
+ const newUserMsg = userMessages[count - 1];
1563
+ if (!checkpointMapRef.current.has(newUserMsg.id)) {
1564
+ const msgIndex = messages.findIndex((m) => m.id === newUserMsg.id);
1565
+ checkpointMapRef.current.set(newUserMsg.id, {
1566
+ id: `cp_${newUserMsg.id}`,
1567
+ messageId: newUserMsg.id,
1568
+ timestamp: Date.now(),
1569
+ messages: structuredClone(messages.slice(0, msgIndex))
1570
+ });
1571
+ bump();
1572
+ }
1573
+ prevUserMsgCountRef.current = count;
1574
+ }
1575
+ }, [messages]);
1576
+ const hasCheckpoint = useCallback(
1577
+ (messageId) => checkpointMapRef.current.has(messageId),
1578
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1579
+ [revision]
1580
+ );
1581
+ const getCheckpoint = useCallback(
1582
+ (messageId) => checkpointMapRef.current.get(messageId),
1583
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1584
+ [revision]
1585
+ );
1586
+ const restore = useCallback(
1587
+ (messageId) => {
1588
+ const cp = checkpointMapRef.current.get(messageId);
1589
+ if (!cp) return void 0;
1590
+ setMessages(cp.messages);
1591
+ checkpointMapRef.current.forEach((c, k) => {
1592
+ if (c.timestamp > cp.timestamp) checkpointMapRef.current.delete(k);
1593
+ });
1594
+ prevUserMsgCountRef.current = cp.messages.filter(
1595
+ (m) => m.role === "user"
1596
+ ).length;
1597
+ bump();
1598
+ return cp;
1599
+ },
1600
+ [setMessages]
1601
+ );
1602
+ const save = useCallback(
1603
+ (messageId, label) => {
1604
+ const msgIndex = messages.findIndex((m) => m.id === messageId);
1605
+ if (msgIndex === -1) return void 0;
1606
+ const cp = {
1607
+ id: `cp_${messageId}`,
1608
+ messageId,
1609
+ timestamp: Date.now(),
1610
+ label,
1611
+ messages: structuredClone(messages.slice(0, msgIndex))
1612
+ };
1613
+ checkpointMapRef.current.set(messageId, cp);
1614
+ bump();
1615
+ return cp;
1616
+ },
1617
+ [messages]
1618
+ );
1619
+ const clear = useCallback(() => {
1620
+ checkpointMapRef.current.clear();
1621
+ prevUserMsgCountRef.current = 0;
1622
+ bump();
1623
+ }, []);
1624
+ const checkpoints = useMemo(
1625
+ () => Array.from(checkpointMapRef.current.values()).sort(
1626
+ (a, b) => a.timestamp - b.timestamp
1627
+ ),
1628
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1629
+ [revision]
1630
+ );
1631
+ return { checkpoints, hasCheckpoint, getCheckpoint, restore, save, clear };
1632
+ }
1633
+
1634
+ // src/react/utils/permission-storage.ts
1635
+ var DEFAULT_KEY_PREFIX = "yourgpt-permissions";
1636
+ function createPermissionStorage(config) {
1637
+ switch (config.type) {
1638
+ case "localStorage":
1639
+ return createBrowserStorageAdapter(
1640
+ typeof window !== "undefined" ? localStorage : null,
1641
+ config.keyPrefix
1642
+ );
1643
+ case "sessionStorage":
1644
+ return createBrowserStorageAdapter(
1645
+ typeof window !== "undefined" ? sessionStorage : null,
1646
+ config.keyPrefix
1647
+ );
1648
+ case "memory":
1649
+ default:
1650
+ return createMemoryStorageAdapter();
1651
+ }
1652
+ }
1653
+ function createBrowserStorageAdapter(storage, keyPrefix = DEFAULT_KEY_PREFIX) {
1654
+ const getStorageKey = () => keyPrefix;
1655
+ const loadPermissions = () => {
1656
+ if (!storage) return /* @__PURE__ */ new Map();
1657
+ try {
1658
+ const data = storage.getItem(getStorageKey());
1659
+ if (!data) return /* @__PURE__ */ new Map();
1660
+ const parsed = JSON.parse(data);
1661
+ return new Map(parsed.map((p) => [p.toolName, p]));
1662
+ } catch {
1663
+ return /* @__PURE__ */ new Map();
1664
+ }
1665
+ };
1666
+ const savePermissions = (permissions) => {
1667
+ if (!storage) return;
1668
+ try {
1669
+ storage.setItem(
1670
+ getStorageKey(),
1671
+ JSON.stringify(Array.from(permissions.values()))
1672
+ );
1673
+ } catch (e) {
1674
+ console.warn("[PermissionStorage] Failed to save permissions:", e);
1675
+ }
1676
+ };
1677
+ return {
1678
+ async get(toolName) {
1679
+ const permissions = loadPermissions();
1680
+ return permissions.get(toolName) || null;
1681
+ },
1682
+ async set(permission) {
1683
+ const permissions = loadPermissions();
1684
+ permissions.set(permission.toolName, permission);
1685
+ savePermissions(permissions);
1686
+ },
1687
+ async remove(toolName) {
1688
+ const permissions = loadPermissions();
1689
+ permissions.delete(toolName);
1690
+ savePermissions(permissions);
1691
+ },
1692
+ async getAll() {
1693
+ const permissions = loadPermissions();
1694
+ return Array.from(permissions.values());
1695
+ },
1696
+ async clear() {
1697
+ if (!storage) return;
1698
+ storage.removeItem(getStorageKey());
1699
+ }
1700
+ };
1701
+ }
1702
+ function createMemoryStorageAdapter() {
1703
+ const permissions = /* @__PURE__ */ new Map();
1704
+ return {
1705
+ async get(toolName) {
1706
+ return permissions.get(toolName) || null;
1707
+ },
1708
+ async set(permission) {
1709
+ permissions.set(permission.toolName, permission);
1710
+ },
1711
+ async remove(toolName) {
1712
+ permissions.delete(toolName);
1713
+ },
1714
+ async getAll() {
1715
+ return Array.from(permissions.values());
1716
+ },
1717
+ async clear() {
1718
+ permissions.clear();
1719
+ }
1720
+ };
1721
+ }
1722
+ function createSessionPermissionCache() {
1723
+ return /* @__PURE__ */ new Map();
1724
+ }
1725
+
1726
+ // src/react/internal/ReactChat.ts
1727
+ var ReactChat = class extends AbstractChat {
1728
+ constructor(config) {
1729
+ const reactState = new ReactChatState(config.initialMessages);
1730
+ const init = {
1731
+ runtimeUrl: config.runtimeUrl,
1732
+ systemPrompt: config.systemPrompt,
1733
+ llm: config.llm,
1734
+ threadId: config.threadId,
1735
+ onCreateSession: config.onCreateSession,
1736
+ yourgptConfig: config.yourgptConfig,
1737
+ streaming: config.streaming ?? true,
1738
+ headers: config.headers,
1739
+ initialMessages: config.initialMessages,
1740
+ state: reactState,
1741
+ callbacks: config.callbacks,
1742
+ debug: config.debug
1743
+ };
1744
+ super(init);
1745
+ // ============================================
1746
+ // Subscribe (for useSyncExternalStore)
1747
+ // ============================================
1748
+ /**
1749
+ * Subscribe to state changes.
1750
+ * Returns an unsubscribe function.
1751
+ *
1752
+ * @example
1753
+ * ```tsx
1754
+ * const messages = useSyncExternalStore(
1755
+ * chat.subscribe,
1756
+ * () => chat.messages
1757
+ * );
1758
+ * ```
1759
+ */
1760
+ this.subscribe = (callback) => {
1761
+ return this.reactState.subscribe(callback);
1762
+ };
1763
+ this.reactState = reactState;
1764
+ }
1765
+ // ============================================
1766
+ // Event handling shortcuts
1767
+ // ============================================
1768
+ /**
1769
+ * Subscribe to tool calls events
1770
+ */
1771
+ onToolCalls(handler) {
1772
+ return this.on("toolCalls", handler);
1773
+ }
1774
+ /**
1775
+ * Subscribe to done events
1776
+ */
1777
+ onDone(handler) {
1778
+ return this.on("done", handler);
1779
+ }
1780
+ /**
1781
+ * Subscribe to error events
1782
+ */
1783
+ onError(handler) {
1784
+ return this.on("error", handler);
1785
+ }
1786
+ // ============================================
1787
+ // Branching API — pass-throughs to ReactChatState
1788
+ // ============================================
1789
+ /**
1790
+ * Navigate to a sibling branch (makes it the active path).
1791
+ */
1792
+ switchBranch(messageId) {
1793
+ this.reactState.switchBranch(messageId);
1794
+ }
1795
+ /**
1796
+ * Get branch navigation info for a message.
1797
+ * Returns null if the message has no siblings.
1798
+ */
1799
+ getBranchInfo(messageId) {
1800
+ return this.reactState.getBranchInfo(messageId);
1801
+ }
1802
+ /**
1803
+ * Get all messages across all branches (for persistence).
1804
+ */
1805
+ getAllMessages() {
1806
+ return this.reactState.getAllMessages();
1807
+ }
1808
+ /**
1809
+ * Whether any message has siblings (branching has occurred).
1810
+ */
1811
+ get hasBranches() {
1812
+ return this.reactState.hasBranches;
1813
+ }
1814
+ // ============================================
1815
+ // Override dispose to clean up state
1816
+ // ============================================
1817
+ dispose() {
1818
+ super.dispose();
1819
+ this.reactState.dispose();
1820
+ }
1821
+ /**
1822
+ * Revive a disposed instance (for React StrictMode compatibility)
1823
+ */
1824
+ revive() {
1825
+ super.revive();
1826
+ this.reactState.revive();
1827
+ }
1828
+ };
1829
+ function createReactChat(config) {
1830
+ return new ReactChat(config);
1831
+ }
1832
+ function useChat(config) {
1833
+ const chatRef = useRef(null);
1834
+ const isThreadIdControlled = Object.prototype.hasOwnProperty.call(
1835
+ config,
1836
+ "threadId"
1837
+ );
1838
+ const lastControlledThreadIdRef = useRef({
1839
+ controlled: isThreadIdControlled,
1840
+ value: config.threadId
1841
+ });
1842
+ const [input, setInput] = useState("");
1843
+ if (chatRef.current !== null && chatRef.current.disposed) {
1844
+ chatRef.current.revive();
1845
+ }
1846
+ if (chatRef.current === null) {
1847
+ chatRef.current = createReactChat({
1848
+ runtimeUrl: config.runtimeUrl,
1849
+ systemPrompt: config.systemPrompt,
1850
+ llm: config.llm,
1851
+ threadId: config.threadId,
1852
+ onCreateSession: config.onCreateSession,
1853
+ yourgptConfig: config.yourgptConfig,
1854
+ streaming: config.streaming,
1855
+ headers: config.headers,
1856
+ initialMessages: config.initialMessages,
1857
+ debug: config.debug,
1858
+ callbacks: {
1859
+ onMessagesChange: config.onMessagesChange,
1860
+ onError: config.onError,
1861
+ onFinish: config.onFinish,
1862
+ onToolCalls: config.onToolCalls
1863
+ }
1864
+ });
1865
+ }
1866
+ useEffect(() => {
1867
+ const prev = lastControlledThreadIdRef.current;
1868
+ const controlChanged = prev.controlled !== isThreadIdControlled;
1869
+ const valueChanged = prev.value !== config.threadId;
1870
+ if (!controlChanged && !valueChanged) {
1871
+ return;
1872
+ }
1873
+ lastControlledThreadIdRef.current = {
1874
+ controlled: isThreadIdControlled,
1875
+ value: config.threadId
1876
+ };
1877
+ if (!isThreadIdControlled) {
1878
+ return;
1879
+ }
1880
+ chatRef.current?.setActiveThread(config.threadId ?? null);
1881
+ }, [config.threadId, isThreadIdControlled]);
1882
+ const messages = useSyncExternalStore(
1883
+ chatRef.current.subscribe,
1884
+ () => chatRef.current.messages,
1885
+ () => chatRef.current.messages
1886
+ // Server snapshot
1887
+ );
1888
+ const status = useSyncExternalStore(
1889
+ chatRef.current.subscribe,
1890
+ () => chatRef.current.status,
1891
+ () => "ready"
1892
+ // Server snapshot
1893
+ );
1894
+ const error = useSyncExternalStore(
1895
+ chatRef.current.subscribe,
1896
+ () => chatRef.current.error,
1897
+ () => void 0
1898
+ // Server snapshot
1899
+ );
1900
+ const hasBranches = useSyncExternalStore(
1901
+ chatRef.current.subscribe,
1902
+ () => chatRef.current.hasBranches,
1903
+ () => false
1904
+ );
1905
+ const isLoading = status === "streaming" || status === "submitted";
1906
+ const sendMessage = useCallback(
1907
+ async (content, attachments) => {
1908
+ await chatRef.current?.sendMessage(content, attachments);
1909
+ setInput("");
1910
+ },
1911
+ []
1912
+ );
1913
+ const stop = useCallback(() => {
1914
+ chatRef.current?.stop();
1915
+ }, []);
1916
+ const clearMessages = useCallback(() => {
1917
+ chatRef.current?.clearMessages();
1918
+ }, []);
1919
+ const setMessages = useCallback((messages2) => {
1920
+ chatRef.current?.setMessages(messages2);
1921
+ }, []);
1922
+ const regenerate = useCallback(async (messageId) => {
1923
+ await chatRef.current?.regenerate(messageId);
1924
+ }, []);
1925
+ const continueWithToolResults = useCallback(
1926
+ async (toolResults) => {
1927
+ await chatRef.current?.continueWithToolResults(toolResults);
1928
+ },
1929
+ []
1930
+ );
1931
+ const switchBranch = useCallback((messageId) => {
1932
+ chatRef.current?.switchBranch(messageId);
1933
+ }, []);
1934
+ const getBranchInfo = useCallback((messageId) => {
1935
+ return chatRef.current?.getBranchInfo(messageId) ?? null;
1936
+ }, []);
1937
+ const editMessage = useCallback(
1938
+ async (messageId, newContent) => {
1939
+ await chatRef.current?.sendMessage(newContent, void 0, {
1940
+ editMessageId: messageId
1941
+ });
1942
+ setInput("");
1943
+ },
1944
+ []
1945
+ );
1946
+ useEffect(() => {
1947
+ return () => {
1948
+ chatRef.current?.dispose();
1949
+ };
1950
+ }, []);
1951
+ return {
1952
+ messages,
1953
+ status,
1954
+ error,
1955
+ isLoading,
1956
+ input,
1957
+ setInput,
1958
+ sendMessage,
1959
+ stop,
1960
+ clearMessages,
1961
+ setMessages,
1962
+ regenerate,
1963
+ continueWithToolResults,
1964
+ chatRef,
1965
+ // Branching
1966
+ switchBranch,
1967
+ getBranchInfo,
1968
+ editMessage,
1969
+ hasBranches
1970
+ };
1971
+ }
1972
+
1973
+ // src/react/skill/define-skill.ts
1974
+ function defineSkill(def) {
1975
+ return def;
1976
+ }
1977
+ function useCopilotEvent(eventType, handler) {
1978
+ const { subscribeToStreamEvents } = useCopilot();
1979
+ const handlerRef = useRef(handler);
1980
+ handlerRef.current = handler;
1981
+ useEffect(() => {
1982
+ const unsub = subscribeToStreamEvents((chunk) => {
1983
+ if (eventType === "*" || chunk.type === eventType) {
1984
+ handlerRef.current(chunk);
1985
+ }
1986
+ });
1987
+ return unsub;
1988
+ }, [subscribeToStreamEvents, eventType]);
1989
+ }
1990
+ var EMPTY_META = {};
1991
+ function useMessageMeta(messageId) {
1992
+ const { messageMeta } = useCopilot();
1993
+ const meta = useSyncExternalStore(
1994
+ messageMeta.subscribe,
1995
+ () => messageId ? messageMeta.getMeta(messageId) : EMPTY_META,
1996
+ () => EMPTY_META
1997
+ );
1998
+ const setMeta = useCallback(
1999
+ (next) => {
2000
+ if (!messageId) return;
2001
+ messageMeta.setMeta(messageId, next);
2002
+ },
2003
+ [messageMeta, messageId]
2004
+ );
2005
+ const updateMeta = useCallback(
2006
+ (updater) => {
2007
+ if (!messageId) return;
2008
+ messageMeta.updateMeta(
2009
+ messageId,
2010
+ (prev) => updater(prev)
2011
+ );
2012
+ },
2013
+ [messageMeta, messageId]
2014
+ );
2015
+ return { meta, setMeta, updateMeta };
2016
+ }
2017
+
2018
+ export { ReactChat, ReactThreadManager, ReactThreadManagerState, createMessageIntentHandler, createPermissionStorage, createReactChat, createReactThreadManager, createReactThreadManagerState, createSessionPermissionCache, createToolIntentHandler, defineSkill, formatKnowledgeResultsForAI, searchKnowledgeBase, useAIAction, useAIActions, useAITools, useAgent, useCapabilities, useChat, useContextStats, useCopilotEvent, useDevLogger, useFeatureSupport, useKnowledgeBase, useMCPUIIntents, useMessageCheckpoints, useMessageMeta, useSkill, useSkillStatus, useSuggestions, useSupportedMediaTypes, useThread, useThreadManager, useToolExecutor, useToolWithSchema, useToolsWithSchema };
2019
+ //# sourceMappingURL=chunk-PURFAD2P.js.map
2020
+ //# sourceMappingURL=chunk-PURFAD2P.js.map