@meetsmore-oss/use-ai-client 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,13 +4,13 @@ import {
4
4
  } from "./chunk-STF3H6F5.js";
5
5
 
6
6
  // src/useAI.ts
7
- import { useState as useState12, useEffect as useEffect11, useRef as useRef12, useCallback as useCallback11, useMemo as useMemo6 } from "react";
7
+ import { useState as useState14, useEffect as useEffect11, useRef as useRef13, useCallback as useCallback12, useMemo as useMemo6 } from "react";
8
8
 
9
9
  // src/providers/useAIProvider.tsx
10
- import { createContext as createContext4, useContext as useContext4, useState as useState11, useEffect as useEffect10, useCallback as useCallback10, useRef as useRef10 } from "react";
10
+ import { createContext as createContext4, useContext as useContext4, useState as useState13, useEffect as useEffect10, useCallback as useCallback11, useRef as useRef11 } from "react";
11
11
 
12
12
  // src/types.ts
13
- import { EventType, ErrorCode } from "@meetsmore-oss/use-ai-core";
13
+ import { EventType, ErrorCode, TOOL_APPROVAL_REQUEST } from "@meetsmore-oss/use-ai-core";
14
14
 
15
15
  // src/theme/strings.ts
16
16
  import { createContext, useContext } from "react";
@@ -109,6 +109,25 @@ var defaultStrings = {
109
109
  toolExecution: {
110
110
  /** Fallback messages when no tool title is provided (one randomly selected) */
111
111
  fallbackMessages: ["Working", "Processing", "Thinking"]
112
+ },
113
+ // Tool approval dialog
114
+ toolApproval: {
115
+ /** Title shown in the approval dialog */
116
+ title: "Confirmation Required",
117
+ /** Message shown in the approval dialog. {toolName} is replaced with tool name. */
118
+ message: '"{toolName}" is waiting for your approval.',
119
+ /** Message shown when multiple tools are awaiting approval. {count} is replaced with number. */
120
+ batchMessage: "{count} actions are waiting for your approval.",
121
+ /** Label for approve button */
122
+ approve: "Allow",
123
+ /** Label for approve all button (batch mode) */
124
+ approveAll: "Allow All",
125
+ /** Label for reject button */
126
+ reject: "Deny",
127
+ /** Label for reject all button (batch mode) */
128
+ rejectAll: "Deny All",
129
+ /** Label for showing tool arguments */
130
+ showDetails: "Show details"
112
131
  }
113
132
  };
114
133
  var StringsContext = createContext(defaultStrings);
@@ -255,7 +274,7 @@ function UseAIFloatingButton({
255
274
  }
256
275
 
257
276
  // src/components/UseAIChatPanel.tsx
258
- import { useState as useState4, useRef as useRef4, useEffect as useEffect4 } from "react";
277
+ import { useState as useState5, useRef as useRef4, useEffect as useEffect4 } from "react";
259
278
 
260
279
  // src/components/MarkdownContent.tsx
261
280
  import ReactMarkdown from "react-markdown";
@@ -1177,30 +1196,30 @@ function matchesMimeType(mimeType, pattern) {
1177
1196
  const regex = new RegExp(`^${regexPattern}$`);
1178
1197
  return regex.test(mimeType);
1179
1198
  }
1180
- function findTransformer(mimeType, transformers) {
1199
+ function findTransformerPattern(mimeType, transformers) {
1181
1200
  if (!transformers) {
1182
1201
  return void 0;
1183
1202
  }
1184
- let bestMatch;
1203
+ let bestKey;
1185
1204
  let bestIsExact = false;
1186
1205
  let bestLength = -1;
1187
- for (const [pattern, transformer] of Object.entries(transformers)) {
1206
+ for (const pattern of Object.keys(transformers)) {
1188
1207
  if (!matchesMimeType(mimeType, pattern)) {
1189
1208
  continue;
1190
1209
  }
1191
1210
  const isExact = !pattern.includes("*");
1192
1211
  if (isExact && !bestIsExact) {
1193
- bestMatch = transformer;
1212
+ bestKey = pattern;
1194
1213
  bestIsExact = true;
1195
1214
  bestLength = pattern.length;
1196
1215
  continue;
1197
1216
  }
1198
1217
  if (isExact === bestIsExact && pattern.length > bestLength) {
1199
- bestMatch = transformer;
1218
+ bestKey = pattern;
1200
1219
  bestLength = pattern.length;
1201
1220
  }
1202
1221
  }
1203
- return bestMatch;
1222
+ return bestKey;
1204
1223
  }
1205
1224
 
1206
1225
  // src/fileUpload/EmbedFileUploadBackend.ts
@@ -1231,75 +1250,104 @@ var EmbedFileUploadBackend = class {
1231
1250
  };
1232
1251
 
1233
1252
  // src/fileUpload/processAttachments.ts
1253
+ function groupBy(items, keyFn) {
1254
+ const map = /* @__PURE__ */ new Map();
1255
+ for (const item of items) {
1256
+ const key = keyFn(item);
1257
+ const list = map.get(key);
1258
+ list ? list.push(item) : map.set(key, [item]);
1259
+ }
1260
+ return map;
1261
+ }
1234
1262
  var transformationCache = /* @__PURE__ */ new Map();
1235
1263
  function getFileCacheKey(file) {
1236
1264
  return `${file.name}:${file.size}:${file.lastModified}`;
1237
1265
  }
1238
- async function getTransformedContent(file, transformer, context, onProgress) {
1239
- const cacheKey = getFileCacheKey(file);
1266
+ async function hashGroupCacheKey(files) {
1267
+ const raw = files.map(getFileCacheKey).join(", ");
1268
+ const data = new TextEncoder().encode(raw);
1269
+ const hash = await crypto.subtle.digest("SHA-256", data);
1270
+ return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
1271
+ }
1272
+ async function getTransformedContent(files, transformer, context, onProgress) {
1273
+ if (files.length === 0) {
1274
+ return [];
1275
+ }
1276
+ const cacheKey = await hashGroupCacheKey(files);
1240
1277
  const cached = transformationCache.get(cacheKey);
1241
- if (cached !== void 0) {
1278
+ if (cached) {
1242
1279
  return cached;
1243
1280
  }
1244
- const result = await transformer.transform(file, context, onProgress);
1245
- transformationCache.set(cacheKey, result);
1246
- return result;
1281
+ const results = await transformer.transform(files, context, onProgress);
1282
+ transformationCache.set(cacheKey, results);
1283
+ return results;
1284
+ }
1285
+ async function toContentPart(attachment, backend) {
1286
+ if (attachment.transformedContent !== void 0) {
1287
+ return {
1288
+ type: "transformed_file",
1289
+ text: attachment.transformedContent,
1290
+ originalFile: {
1291
+ name: attachment.file.name,
1292
+ mimeType: attachment.file.type,
1293
+ size: attachment.file.size
1294
+ }
1295
+ };
1296
+ }
1297
+ const url = await backend.prepareForSend(attachment.file);
1298
+ if (attachment.file.type.startsWith("image/")) {
1299
+ return { type: "image", url };
1300
+ }
1301
+ return {
1302
+ type: "file",
1303
+ url,
1304
+ mimeType: attachment.file.type,
1305
+ name: attachment.file.name
1306
+ };
1247
1307
  }
1248
1308
  async function processAttachments(attachments, config) {
1249
1309
  const { getCurrentChat, backend = new EmbedFileUploadBackend(), transformers = {}, onFileProgress } = config;
1250
1310
  const contentParts = [];
1251
1311
  const chat = await getCurrentChat();
1252
1312
  const context = { chat };
1253
- for (const attachment of attachments) {
1313
+ const groups = groupBy(
1314
+ attachments,
1315
+ (attachment) => attachment.transformedContent !== void 0 ? null : findTransformerPattern(attachment.file.type, transformers) ?? null
1316
+ );
1317
+ for (const [key, groupAttachments] of groups) {
1318
+ if (key === null) {
1319
+ const parts = await Promise.all(
1320
+ groupAttachments.map((a) => toContentPart(a, backend))
1321
+ );
1322
+ contentParts.push(...parts);
1323
+ continue;
1324
+ }
1325
+ const transformer = transformers[key];
1326
+ const files = groupAttachments.map((a) => a.file);
1327
+ groupAttachments.forEach((a) => onFileProgress?.(a.id, { status: "processing" }));
1254
1328
  try {
1255
- if (attachment.transformedContent !== void 0) {
1329
+ const results = await getTransformedContent(
1330
+ files,
1331
+ transformer,
1332
+ context,
1333
+ (progress) => {
1334
+ groupAttachments.forEach((a) => onFileProgress?.(a.id, { status: "processing", progress }));
1335
+ }
1336
+ );
1337
+ results.forEach((text, i) => {
1256
1338
  contentParts.push({
1257
1339
  type: "transformed_file",
1258
- text: attachment.transformedContent,
1340
+ text,
1259
1341
  originalFile: {
1260
- name: attachment.file.name,
1261
- mimeType: attachment.file.type,
1262
- size: attachment.file.size
1342
+ name: files[i].name,
1343
+ mimeType: files[i].type,
1344
+ size: files[i].size
1263
1345
  }
1264
1346
  });
1265
- continue;
1266
- }
1267
- const transformer = findTransformer(attachment.file.type, transformers);
1268
- if (transformer) {
1269
- onFileProgress?.(attachment.id, { status: "processing" });
1270
- const transformedText = await getTransformedContent(
1271
- attachment.file,
1272
- transformer,
1273
- context,
1274
- (progress) => {
1275
- onFileProgress?.(attachment.id, { status: "processing", progress });
1276
- }
1277
- );
1278
- contentParts.push({
1279
- type: "transformed_file",
1280
- text: transformedText,
1281
- originalFile: {
1282
- name: attachment.file.name,
1283
- mimeType: attachment.file.type,
1284
- size: attachment.file.size
1285
- }
1286
- });
1287
- onFileProgress?.(attachment.id, { status: "done" });
1288
- } else {
1289
- const url = await backend.prepareForSend(attachment.file);
1290
- if (attachment.file.type.startsWith("image/")) {
1291
- contentParts.push({ type: "image", url });
1292
- } else {
1293
- contentParts.push({
1294
- type: "file",
1295
- url,
1296
- mimeType: attachment.file.type,
1297
- name: attachment.file.name
1298
- });
1299
- }
1300
- }
1347
+ onFileProgress?.(groupAttachments[i].id, { status: "done" });
1348
+ });
1301
1349
  } catch (error) {
1302
- onFileProgress?.(attachment.id, { status: "error" });
1350
+ groupAttachments.forEach((a) => onFileProgress?.(a.id, { status: "error" }));
1303
1351
  throw error;
1304
1352
  }
1305
1353
  }
@@ -1370,12 +1418,14 @@ function useFileUpload({
1370
1418
  setFileError(null);
1371
1419
  setProcessingState(/* @__PURE__ */ new Map());
1372
1420
  }, [resetDependency]);
1373
- const runTransformer = useCallback2(async (attachmentId, file, transformer) => {
1421
+ const runTransformer = useCallback2(async (attachmentId, file, transformerKey) => {
1422
+ const transformer = transformers?.[transformerKey];
1423
+ if (!transformer) return;
1374
1424
  setProcessingState((prev) => new Map(prev).set(attachmentId, { status: "processing" }));
1375
1425
  try {
1376
1426
  const chat = await getCurrentChat();
1377
1427
  const context = { chat };
1378
- const transformedContent = await getTransformedContent(file, transformer, context, (progress) => {
1428
+ const [transformedContent] = await getTransformedContent([file], transformer, context, (progress) => {
1379
1429
  setProcessingState((prev) => new Map(prev).set(attachmentId, {
1380
1430
  status: "processing",
1381
1431
  progress
@@ -1389,7 +1439,7 @@ function useFileUpload({
1389
1439
  console.error(`[useFileUpload] Transformation failed for ${file.name}:`, error);
1390
1440
  setProcessingState((prev) => new Map(prev).set(attachmentId, { status: "error" }));
1391
1441
  }
1392
- }, [getCurrentChat]);
1442
+ }, [getCurrentChat, transformers]);
1393
1443
  const handleFiles = useCallback2(async (files) => {
1394
1444
  const fileArray = Array.from(files);
1395
1445
  for (const file of fileArray) {
@@ -1411,9 +1461,9 @@ function useFileUpload({
1411
1461
  preview
1412
1462
  };
1413
1463
  setAttachments((prev) => [...prev, attachment]);
1414
- const transformer = findTransformer(file.type, transformers);
1415
- if (transformer) {
1416
- runTransformer(attachmentId, file, transformer);
1464
+ const transformerKey = findTransformerPattern(file.type, transformers);
1465
+ if (transformerKey) {
1466
+ runTransformer(attachmentId, file, transformerKey);
1417
1467
  }
1418
1468
  }
1419
1469
  }, [maxFileSize, acceptedTypes, strings, transformers, runTransformer]);
@@ -1574,8 +1624,210 @@ function useDropdownState(options = {}) {
1574
1624
  };
1575
1625
  }
1576
1626
 
1627
+ // src/components/ToolApprovalDialog.tsx
1628
+ import { useState as useState4 } from "react";
1629
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1630
+ function ToolApprovalDialog({
1631
+ toolCallName,
1632
+ toolCallArgs,
1633
+ annotations,
1634
+ toolCount = 1,
1635
+ pendingTools = [],
1636
+ onApprove,
1637
+ onReject,
1638
+ theme,
1639
+ strings
1640
+ }) {
1641
+ const [showDetails, setShowDetails] = useState4(false);
1642
+ const displayName = annotations?.title || toolCallName;
1643
+ const isBatch = toolCount > 1;
1644
+ const message = isBatch ? strings.toolApproval.batchMessage?.replace("{count}", String(toolCount)) ?? `${toolCount} actions are waiting for your approval` : strings.toolApproval.message.replace("{toolName}", displayName);
1645
+ const getToolDisplayName = (tool) => tool.annotations?.title || tool.toolCallName;
1646
+ return /* @__PURE__ */ jsxs7(
1647
+ "div",
1648
+ {
1649
+ "data-testid": "tool-approval-dialog",
1650
+ style: {
1651
+ border: `2px solid ${theme.primaryColor}`,
1652
+ borderRadius: "12px",
1653
+ background: theme.backgroundColor,
1654
+ overflow: "hidden"
1655
+ },
1656
+ children: [
1657
+ /* @__PURE__ */ jsxs7(
1658
+ "div",
1659
+ {
1660
+ style: {
1661
+ padding: "12px 14px",
1662
+ borderBottom: `1px solid ${theme.borderColor}`,
1663
+ background: theme.assistantMessageBackground
1664
+ },
1665
+ children: [
1666
+ /* @__PURE__ */ jsxs7("div", { style: {
1667
+ display: "flex",
1668
+ alignItems: "center",
1669
+ gap: "8px",
1670
+ marginBottom: "4px"
1671
+ }, children: [
1672
+ /* @__PURE__ */ jsxs7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: theme.primaryColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1673
+ /* @__PURE__ */ jsx10("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
1674
+ /* @__PURE__ */ jsx10("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
1675
+ /* @__PURE__ */ jsx10("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
1676
+ ] }),
1677
+ /* @__PURE__ */ jsx10("span", { style: {
1678
+ fontWeight: 600,
1679
+ fontSize: "14px",
1680
+ color: theme.textColor
1681
+ }, children: strings.toolApproval.title })
1682
+ ] }),
1683
+ /* @__PURE__ */ jsx10("div", { style: {
1684
+ fontSize: "13px",
1685
+ color: theme.secondaryTextColor,
1686
+ paddingLeft: "24px"
1687
+ }, children: message })
1688
+ ]
1689
+ }
1690
+ ),
1691
+ /* @__PURE__ */ jsxs7("div", { style: { padding: "8px 14px" }, children: [
1692
+ /* @__PURE__ */ jsxs7(
1693
+ "button",
1694
+ {
1695
+ onClick: () => setShowDetails(!showDetails),
1696
+ style: {
1697
+ background: "transparent",
1698
+ border: "none",
1699
+ padding: 0,
1700
+ cursor: "pointer",
1701
+ fontSize: "12px",
1702
+ color: theme.secondaryTextColor,
1703
+ display: "flex",
1704
+ alignItems: "center",
1705
+ gap: "4px"
1706
+ },
1707
+ children: [
1708
+ /* @__PURE__ */ jsx10(
1709
+ "svg",
1710
+ {
1711
+ width: "10",
1712
+ height: "10",
1713
+ viewBox: "0 0 12 12",
1714
+ fill: "none",
1715
+ style: {
1716
+ transform: showDetails ? "rotate(90deg)" : "rotate(0deg)",
1717
+ transition: "transform 0.15s"
1718
+ },
1719
+ children: /* @__PURE__ */ jsx10("path", { d: "M4 2L8 6L4 10", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1720
+ }
1721
+ ),
1722
+ strings.toolApproval.showDetails
1723
+ ]
1724
+ }
1725
+ ),
1726
+ showDetails && /* @__PURE__ */ jsx10("div", { style: {
1727
+ marginTop: "6px",
1728
+ display: "flex",
1729
+ flexDirection: "column",
1730
+ gap: "8px",
1731
+ maxHeight: "200px",
1732
+ overflow: "auto"
1733
+ }, children: (pendingTools.length > 0 ? pendingTools : [{
1734
+ toolCallId: "single",
1735
+ toolCallName,
1736
+ toolCallArgs,
1737
+ annotations
1738
+ }]).map((tool, index) => /* @__PURE__ */ jsxs7(
1739
+ "div",
1740
+ {
1741
+ style: {
1742
+ padding: "8px",
1743
+ background: theme.hoverBackground,
1744
+ borderRadius: "6px"
1745
+ },
1746
+ children: [
1747
+ /* @__PURE__ */ jsx10("div", { style: {
1748
+ fontSize: "12px",
1749
+ fontWeight: 500,
1750
+ color: theme.textColor,
1751
+ marginBottom: "4px"
1752
+ }, children: getToolDisplayName(tool) }),
1753
+ /* @__PURE__ */ jsx10("pre", { style: {
1754
+ margin: 0,
1755
+ fontSize: "11px",
1756
+ overflow: "auto",
1757
+ color: theme.secondaryTextColor,
1758
+ whiteSpace: "pre-wrap",
1759
+ wordBreak: "break-word"
1760
+ }, children: JSON.stringify(tool.toolCallArgs, null, 2) })
1761
+ ]
1762
+ },
1763
+ tool.toolCallId
1764
+ )) })
1765
+ ] }),
1766
+ /* @__PURE__ */ jsxs7("div", { style: {
1767
+ display: "flex",
1768
+ gap: "8px",
1769
+ padding: "8px 14px 12px"
1770
+ }, children: [
1771
+ /* @__PURE__ */ jsx10(
1772
+ "button",
1773
+ {
1774
+ "data-testid": "approve-tool-button",
1775
+ onClick: onApprove,
1776
+ style: {
1777
+ flex: 1,
1778
+ padding: "8px 16px",
1779
+ borderRadius: "8px",
1780
+ border: "none",
1781
+ background: theme.primaryGradient,
1782
+ color: "white",
1783
+ fontWeight: 500,
1784
+ cursor: "pointer",
1785
+ fontSize: "13px",
1786
+ transition: "opacity 0.15s"
1787
+ },
1788
+ onMouseEnter: (e) => {
1789
+ e.currentTarget.style.opacity = "0.9";
1790
+ },
1791
+ onMouseLeave: (e) => {
1792
+ e.currentTarget.style.opacity = "1";
1793
+ },
1794
+ children: isBatch ? strings.toolApproval.approveAll ?? "Approve All" : strings.toolApproval.approve
1795
+ }
1796
+ ),
1797
+ /* @__PURE__ */ jsx10(
1798
+ "button",
1799
+ {
1800
+ "data-testid": "reject-tool-button",
1801
+ onClick: () => onReject(),
1802
+ style: {
1803
+ flex: 1,
1804
+ padding: "8px 16px",
1805
+ borderRadius: "8px",
1806
+ border: `1px solid ${theme.borderColor}`,
1807
+ background: "transparent",
1808
+ color: theme.textColor,
1809
+ fontWeight: 500,
1810
+ cursor: "pointer",
1811
+ fontSize: "13px",
1812
+ transition: "all 0.15s"
1813
+ },
1814
+ onMouseEnter: (e) => {
1815
+ e.currentTarget.style.background = theme.hoverBackground;
1816
+ },
1817
+ onMouseLeave: (e) => {
1818
+ e.currentTarget.style.background = "transparent";
1819
+ },
1820
+ children: isBatch ? strings.toolApproval.rejectAll ?? "Reject All" : strings.toolApproval.reject
1821
+ }
1822
+ )
1823
+ ] })
1824
+ ]
1825
+ }
1826
+ );
1827
+ }
1828
+
1577
1829
  // src/components/UseAIChatPanel.tsx
1578
- import { Fragment, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1830
+ import { Fragment, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1579
1831
  function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedColor }) {
1580
1832
  const buttonRef = useRef4(null);
1581
1833
  const handleClick = () => {
@@ -1591,7 +1843,7 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
1591
1843
  };
1592
1844
  const thumbsUpPath = "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3";
1593
1845
  const thumbsDownPath = "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17";
1594
- return /* @__PURE__ */ jsx10(
1846
+ return /* @__PURE__ */ jsx11(
1595
1847
  "button",
1596
1848
  {
1597
1849
  ref: buttonRef,
@@ -1624,7 +1876,7 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
1624
1876
  e.currentTarget.style.color = unselectedColor;
1625
1877
  }
1626
1878
  },
1627
- children: /* @__PURE__ */ jsx10(
1879
+ children: /* @__PURE__ */ jsx11(
1628
1880
  "svg",
1629
1881
  {
1630
1882
  width: "14",
@@ -1635,7 +1887,7 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
1635
1887
  strokeWidth: "2",
1636
1888
  strokeLinecap: "round",
1637
1889
  strokeLinejoin: "round",
1638
- children: /* @__PURE__ */ jsx10("path", { d: type === "upvote" ? thumbsUpPath : thumbsDownPath })
1890
+ children: /* @__PURE__ */ jsx11("path", { d: type === "upvote" ? thumbsUpPath : thumbsDownPath })
1639
1891
  }
1640
1892
  )
1641
1893
  }
@@ -1676,18 +1928,21 @@ function UseAIChatPanel({
1676
1928
  closeButton,
1677
1929
  executingTool,
1678
1930
  feedbackEnabled,
1679
- onFeedback
1931
+ onFeedback,
1932
+ pendingApprovals = [],
1933
+ onApproveToolCall,
1934
+ onRejectToolCall
1680
1935
  }) {
1681
1936
  const strings = useStrings();
1682
1937
  const theme = useTheme();
1683
- const [input, setInput] = useState4("");
1938
+ const [input, setInput] = useState5("");
1684
1939
  const chatHistoryDropdown = useDropdownState();
1685
1940
  const agentDropdown = useDropdownState();
1686
- const [chatHistory, setChatHistory] = useState4([]);
1941
+ const [chatHistory, setChatHistory] = useState5([]);
1687
1942
  const messagesEndRef = useRef4(null);
1688
- const [displayedSuggestions, setDisplayedSuggestions] = useState4([]);
1943
+ const [displayedSuggestions, setDisplayedSuggestions] = useState5([]);
1689
1944
  const textareaRef = useRef4(null);
1690
- const [hoveredMessageId, setHoveredMessageId] = useState4(null);
1945
+ const [hoveredMessageId, setHoveredMessageId] = useState5(null);
1691
1946
  const {
1692
1947
  attachments,
1693
1948
  fileError,
@@ -1774,7 +2029,7 @@ function UseAIChatPanel({
1774
2029
  chatHistoryDropdown.close();
1775
2030
  }
1776
2031
  };
1777
- return /* @__PURE__ */ jsxs7(
2032
+ return /* @__PURE__ */ jsxs8(
1778
2033
  "div",
1779
2034
  {
1780
2035
  onClick: () => {
@@ -1792,7 +2047,7 @@ function UseAIChatPanel({
1792
2047
  },
1793
2048
  children: [
1794
2049
  DropZoneOverlay,
1795
- /* @__PURE__ */ jsxs7(
2050
+ /* @__PURE__ */ jsxs8(
1796
2051
  "div",
1797
2052
  {
1798
2053
  style: {
@@ -1805,7 +2060,7 @@ function UseAIChatPanel({
1805
2060
  gap: "12px"
1806
2061
  },
1807
2062
  children: [
1808
- /* @__PURE__ */ jsx10("div", { style: { flex: 1, minWidth: 0, position: "relative" }, children: onListChats ? /* @__PURE__ */ jsxs7(
2063
+ /* @__PURE__ */ jsx11("div", { style: { flex: 1, minWidth: 0, position: "relative" }, children: onListChats ? /* @__PURE__ */ jsxs8(
1809
2064
  "button",
1810
2065
  {
1811
2066
  "data-testid": "chat-history-dropdown-button",
@@ -1838,7 +2093,7 @@ function UseAIChatPanel({
1838
2093
  e.currentTarget.style.background = "transparent";
1839
2094
  },
1840
2095
  children: [
1841
- /* @__PURE__ */ jsx10("span", { style: {
2096
+ /* @__PURE__ */ jsx11("span", { style: {
1842
2097
  overflow: "hidden",
1843
2098
  textOverflow: "ellipsis",
1844
2099
  whiteSpace: "nowrap",
@@ -1855,13 +2110,13 @@ function UseAIChatPanel({
1855
2110
  }
1856
2111
  return strings.header.newChat;
1857
2112
  })() }),
1858
- /* @__PURE__ */ jsx10("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx10("path", { d: "M3 4.5L6 7.5L9 4.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2113
+ /* @__PURE__ */ jsx11("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx11("path", { d: "M3 4.5L6 7.5L9 4.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1859
2114
  ]
1860
2115
  }
1861
- ) : /* @__PURE__ */ jsx10("div", { style: { fontSize: "14px", fontWeight: "600", color: theme.textColor, padding: "6px 8px" }, children: strings.header.aiAssistant }) }),
1862
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
1863
- availableAgents && availableAgents.length > 1 && onAgentChange && /* @__PURE__ */ jsxs7("div", { style: { position: "relative" }, children: [
1864
- /* @__PURE__ */ jsxs7(
2116
+ ) : /* @__PURE__ */ jsx11("div", { style: { fontSize: "14px", fontWeight: "600", color: theme.textColor, padding: "6px 8px" }, children: strings.header.aiAssistant }) }),
2117
+ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
2118
+ availableAgents && availableAgents.length > 1 && onAgentChange && /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
2119
+ /* @__PURE__ */ jsxs8(
1865
2120
  "button",
1866
2121
  {
1867
2122
  "data-testid": "agent-selector",
@@ -1890,7 +2145,7 @@ function UseAIChatPanel({
1890
2145
  },
1891
2146
  title: "Select AI model",
1892
2147
  children: [
1893
- /* @__PURE__ */ jsx10("span", { style: {
2148
+ /* @__PURE__ */ jsx11("span", { style: {
1894
2149
  overflow: "hidden",
1895
2150
  textOverflow: "ellipsis",
1896
2151
  whiteSpace: "nowrap",
@@ -1899,11 +2154,11 @@ function UseAIChatPanel({
1899
2154
  const agent = availableAgents.find((a) => a.id === (selectedAgent ?? defaultAgent));
1900
2155
  return agent?.name || "AI";
1901
2156
  })() }),
1902
- /* @__PURE__ */ jsx10("svg", { width: "10", height: "10", viewBox: "0 0 12 12", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx10("path", { d: "M3 4.5L6 7.5L9 4.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2157
+ /* @__PURE__ */ jsx11("svg", { width: "10", height: "10", viewBox: "0 0 12 12", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx11("path", { d: "M3 4.5L6 7.5L9 4.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
1903
2158
  ]
1904
2159
  }
1905
2160
  ),
1906
- agentDropdown.isOpen && /* @__PURE__ */ jsx10(
2161
+ agentDropdown.isOpen && /* @__PURE__ */ jsx11(
1907
2162
  "div",
1908
2163
  {
1909
2164
  style: {
@@ -1923,7 +2178,7 @@ function UseAIChatPanel({
1923
2178
  },
1924
2179
  children: availableAgents.map((agent) => {
1925
2180
  const isSelected = agent.id === (selectedAgent ?? defaultAgent);
1926
- return /* @__PURE__ */ jsxs7(
2181
+ return /* @__PURE__ */ jsxs8(
1927
2182
  "div",
1928
2183
  {
1929
2184
  "data-testid": "agent-option",
@@ -1953,13 +2208,13 @@ function UseAIChatPanel({
1953
2208
  }
1954
2209
  },
1955
2210
  children: [
1956
- /* @__PURE__ */ jsxs7("div", { style: { flex: 1, minWidth: 0 }, children: [
1957
- /* @__PURE__ */ jsx10("div", { style: {
2211
+ /* @__PURE__ */ jsxs8("div", { style: { flex: 1, minWidth: 0 }, children: [
2212
+ /* @__PURE__ */ jsx11("div", { style: {
1958
2213
  fontSize: "13px",
1959
2214
  fontWeight: isSelected ? "600" : "500",
1960
2215
  color: isSelected ? theme.primaryColor : theme.textColor
1961
2216
  }, children: agent.name }),
1962
- agent.annotation && /* @__PURE__ */ jsx10("div", { style: {
2217
+ agent.annotation && /* @__PURE__ */ jsx11("div", { style: {
1963
2218
  fontSize: "11px",
1964
2219
  color: theme.secondaryTextColor,
1965
2220
  marginTop: "2px",
@@ -1968,7 +2223,7 @@ function UseAIChatPanel({
1968
2223
  whiteSpace: "nowrap"
1969
2224
  }, children: agent.annotation })
1970
2225
  ] }),
1971
- isSelected && /* @__PURE__ */ jsx10("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx10("path", { d: "M2 7L5.5 10.5L12 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
2226
+ isSelected && /* @__PURE__ */ jsx11("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", style: { flexShrink: 0 }, children: /* @__PURE__ */ jsx11("path", { d: "M2 7L5.5 10.5L12 4", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
1972
2227
  ]
1973
2228
  },
1974
2229
  agent.id
@@ -1977,7 +2232,7 @@ function UseAIChatPanel({
1977
2232
  }
1978
2233
  )
1979
2234
  ] }),
1980
- onNewChat && /* @__PURE__ */ jsx10(
2235
+ onNewChat && /* @__PURE__ */ jsx11(
1981
2236
  "button",
1982
2237
  {
1983
2238
  "data-testid": "new-chat-button",
@@ -2004,10 +2259,10 @@ function UseAIChatPanel({
2004
2259
  e.currentTarget.style.color = theme.secondaryTextColor;
2005
2260
  },
2006
2261
  title: strings.header.newChat,
2007
- children: /* @__PURE__ */ jsx10("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx10("path", { d: "M8 3.5V12.5M3.5 8H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) })
2262
+ children: /* @__PURE__ */ jsx11("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx11("path", { d: "M8 3.5V12.5M3.5 8H12.5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) })
2008
2263
  }
2009
2264
  ),
2010
- onDeleteChat && messages.length > 0 && /* @__PURE__ */ jsx10(
2265
+ onDeleteChat && messages.length > 0 && /* @__PURE__ */ jsx11(
2011
2266
  "button",
2012
2267
  {
2013
2268
  "data-testid": "delete-chat-button",
@@ -2031,7 +2286,7 @@ function UseAIChatPanel({
2031
2286
  e.currentTarget.style.color = theme.secondaryTextColor;
2032
2287
  },
2033
2288
  title: strings.header.deleteChat,
2034
- children: /* @__PURE__ */ jsx10("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx10("path", { d: "M2 4H14M6.5 7V11M9.5 7V11M3 4L4 13C4 13.5304 4.21071 14.0391 4.58579 14.4142C4.96086 14.7893 5.46957 15 6 15H10C10.5304 15 11.0391 14.7893 11.4142 14.4142C11.7893 14.0391 12 13.5304 12 13L13 4M5.5 4V2.5C5.5 2.23478 5.60536 1.98043 5.79289 1.79289C5.98043 1.60536 6.23478 1.5 6.5 1.5H9.5C9.76522 1.5 10.0196 1.60536 10.2071 1.79289C10.3946 1.98043 10.5 2.23478 10.5 2.5V4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2289
+ children: /* @__PURE__ */ jsx11("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx11("path", { d: "M2 4H14M6.5 7V11M9.5 7V11M3 4L4 13C4 13.5304 4.21071 14.0391 4.58579 14.4142C4.96086 14.7893 5.46957 15 6 15H10C10.5304 15 11.0391 14.7893 11.4142 14.4142C11.7893 14.0391 12 13.5304 12 13L13 4M5.5 4V2.5C5.5 2.23478 5.60536 1.98043 5.79289 1.79289C5.98043 1.60536 6.23478 1.5 6.5 1.5H9.5C9.76522 1.5 10.0196 1.60536 10.2071 1.79289C10.3946 1.98043 10.5 2.23478 10.5 2.5V4", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })
2035
2290
  }
2036
2291
  ),
2037
2292
  closeButton
@@ -2039,7 +2294,7 @@ function UseAIChatPanel({
2039
2294
  ]
2040
2295
  }
2041
2296
  ),
2042
- chatHistoryDropdown.isOpen && onListChats && /* @__PURE__ */ jsx10(
2297
+ chatHistoryDropdown.isOpen && onListChats && /* @__PURE__ */ jsx11(
2043
2298
  "div",
2044
2299
  {
2045
2300
  style: {
@@ -2056,7 +2311,7 @@ function UseAIChatPanel({
2056
2311
  flexDirection: "column",
2057
2312
  overflow: "hidden"
2058
2313
  },
2059
- children: /* @__PURE__ */ jsx10(
2314
+ children: /* @__PURE__ */ jsx11(
2060
2315
  "div",
2061
2316
  {
2062
2317
  style: {
@@ -2064,7 +2319,7 @@ function UseAIChatPanel({
2064
2319
  overflowY: "auto",
2065
2320
  padding: "8px"
2066
2321
  },
2067
- children: chatHistory.length === 0 ? /* @__PURE__ */ jsx10(
2322
+ children: chatHistory.length === 0 ? /* @__PURE__ */ jsx11(
2068
2323
  "div",
2069
2324
  {
2070
2325
  style: {
@@ -2073,9 +2328,9 @@ function UseAIChatPanel({
2073
2328
  padding: "32px 16px",
2074
2329
  fontSize: "13px"
2075
2330
  },
2076
- children: /* @__PURE__ */ jsx10("p", { style: { margin: 0 }, children: strings.chatHistory.noChatHistory })
2331
+ children: /* @__PURE__ */ jsx11("p", { style: { margin: 0 }, children: strings.chatHistory.noChatHistory })
2077
2332
  }
2078
- ) : chatHistory.map((chat) => /* @__PURE__ */ jsxs7(
2333
+ ) : chatHistory.map((chat) => /* @__PURE__ */ jsxs8(
2079
2334
  "div",
2080
2335
  {
2081
2336
  "data-testid": "chat-history-item",
@@ -2099,10 +2354,10 @@ function UseAIChatPanel({
2099
2354
  }
2100
2355
  },
2101
2356
  children: [
2102
- /* @__PURE__ */ jsx10("div", { style: { fontSize: "13px", fontWeight: "500", color: theme.textColor, marginBottom: "4px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: chat.title || strings.header.newChat }),
2103
- /* @__PURE__ */ jsxs7("div", { style: { fontSize: "11px", color: theme.secondaryTextColor }, children: [
2357
+ /* @__PURE__ */ jsx11("div", { style: { fontSize: "13px", fontWeight: "500", color: theme.textColor, marginBottom: "4px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: chat.title || strings.header.newChat }),
2358
+ /* @__PURE__ */ jsxs8("div", { style: { fontSize: "11px", color: theme.secondaryTextColor }, children: [
2104
2359
  new Date(chat.updatedAt).toLocaleDateString([], { month: "short", day: "numeric" }),
2105
- currentChatId === chat.id && /* @__PURE__ */ jsxs7("span", { style: {
2360
+ currentChatId === chat.id && /* @__PURE__ */ jsxs8("span", { style: {
2106
2361
  marginLeft: "8px",
2107
2362
  color: theme.primaryColor,
2108
2363
  fontWeight: "600"
@@ -2121,7 +2376,7 @@ function UseAIChatPanel({
2121
2376
  ),
2122
2377
  chatHistoryDropdown.Backdrop,
2123
2378
  agentDropdown.Backdrop,
2124
- /* @__PURE__ */ jsxs7(
2379
+ /* @__PURE__ */ jsxs8(
2125
2380
  "div",
2126
2381
  {
2127
2382
  style: {
@@ -2133,7 +2388,7 @@ function UseAIChatPanel({
2133
2388
  gap: "12px"
2134
2389
  },
2135
2390
  children: [
2136
- messages.length === 0 && /* @__PURE__ */ jsxs7(
2391
+ messages.length === 0 && /* @__PURE__ */ jsxs8(
2137
2392
  "div",
2138
2393
  {
2139
2394
  style: {
@@ -2144,12 +2399,12 @@ function UseAIChatPanel({
2144
2399
  gap: "20px"
2145
2400
  },
2146
2401
  children: [
2147
- /* @__PURE__ */ jsxs7("div", { style: { textAlign: "center", color: theme.secondaryTextColor, fontSize: "14px" }, children: [
2148
- /* @__PURE__ */ jsx10("p", { style: { margin: 0, fontSize: "32px", marginBottom: "12px" }, children: "\u{1F4AC}" }),
2149
- /* @__PURE__ */ jsx10("p", { style: { margin: 0 }, children: strings.emptyChat.startConversation }),
2150
- /* @__PURE__ */ jsx10("p", { style: { margin: "8px 0 0", fontSize: "12px" }, children: strings.emptyChat.askMeToHelp })
2402
+ /* @__PURE__ */ jsxs8("div", { style: { textAlign: "center", color: theme.secondaryTextColor, fontSize: "14px" }, children: [
2403
+ /* @__PURE__ */ jsx11("p", { style: { margin: 0, fontSize: "32px", marginBottom: "12px" }, children: "\u{1F4AC}" }),
2404
+ /* @__PURE__ */ jsx11("p", { style: { margin: 0 }, children: strings.emptyChat.startConversation }),
2405
+ /* @__PURE__ */ jsx11("p", { style: { margin: "8px 0 0", fontSize: "12px" }, children: strings.emptyChat.askMeToHelp })
2151
2406
  ] }),
2152
- displayedSuggestions.length > 0 && /* @__PURE__ */ jsx10(
2407
+ displayedSuggestions.length > 0 && /* @__PURE__ */ jsx11(
2153
2408
  "div",
2154
2409
  {
2155
2410
  style: {
@@ -2159,7 +2414,7 @@ function UseAIChatPanel({
2159
2414
  width: "100%",
2160
2415
  maxWidth: "320px"
2161
2416
  },
2162
- children: displayedSuggestions.map((suggestion, index) => /* @__PURE__ */ jsx10(
2417
+ children: displayedSuggestions.map((suggestion, index) => /* @__PURE__ */ jsx11(
2163
2418
  "button",
2164
2419
  {
2165
2420
  "data-testid": "chat-suggestion-button",
@@ -2203,7 +2458,7 @@ function UseAIChatPanel({
2203
2458
  ]
2204
2459
  }
2205
2460
  ),
2206
- messages.map((message) => /* @__PURE__ */ jsxs7(
2461
+ messages.map((message) => /* @__PURE__ */ jsxs8(
2207
2462
  "div",
2208
2463
  {
2209
2464
  "data-testid": `chat-message-${message.role}`,
@@ -2216,7 +2471,7 @@ function UseAIChatPanel({
2216
2471
  onMouseEnter: () => message.role === "user" && setHoveredMessageId(message.id),
2217
2472
  onMouseLeave: () => setHoveredMessageId(null),
2218
2473
  children: [
2219
- /* @__PURE__ */ jsxs7(
2474
+ /* @__PURE__ */ jsxs8(
2220
2475
  "div",
2221
2476
  {
2222
2477
  style: {
@@ -2224,7 +2479,7 @@ function UseAIChatPanel({
2224
2479
  maxWidth: "80%"
2225
2480
  },
2226
2481
  children: [
2227
- message.role === "user" && hoveredMessageId === message.id && onSaveCommand && !slashCommands.isSavingCommand(message.id) && /* @__PURE__ */ jsx10(
2482
+ message.role === "user" && hoveredMessageId === message.id && onSaveCommand && !slashCommands.isSavingCommand(message.id) && /* @__PURE__ */ jsx11(
2228
2483
  "button",
2229
2484
  {
2230
2485
  "data-testid": "save-command-button",
@@ -2260,14 +2515,14 @@ function UseAIChatPanel({
2260
2515
  e.currentTarget.style.transform = "scale(1)";
2261
2516
  e.currentTarget.style.boxShadow = "0 2px 6px rgba(0, 0, 0, 0.15)";
2262
2517
  },
2263
- children: /* @__PURE__ */ jsxs7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2264
- /* @__PURE__ */ jsx10("path", { d: "M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" }),
2265
- /* @__PURE__ */ jsx10("polyline", { points: "17 21 17 13 7 13 7 21" }),
2266
- /* @__PURE__ */ jsx10("polyline", { points: "7 3 7 8 15 8" })
2518
+ children: /* @__PURE__ */ jsxs8("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2519
+ /* @__PURE__ */ jsx11("path", { d: "M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" }),
2520
+ /* @__PURE__ */ jsx11("polyline", { points: "17 21 17 13 7 13 7 21" }),
2521
+ /* @__PURE__ */ jsx11("polyline", { points: "7 3 7 8 15 8" })
2267
2522
  ] })
2268
2523
  }
2269
2524
  ),
2270
- /* @__PURE__ */ jsxs7(
2525
+ /* @__PURE__ */ jsxs8(
2271
2526
  "div",
2272
2527
  {
2273
2528
  "data-testid": "chat-message-content",
@@ -2282,7 +2537,7 @@ function UseAIChatPanel({
2282
2537
  wordWrap: "break-word"
2283
2538
  },
2284
2539
  children: [
2285
- message.role === "user" && hasFileContent(message.content) && /* @__PURE__ */ jsx10("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px", marginBottom: "8px" }, children: message.content.filter((part) => part.type === "file").map((part, idx) => /* @__PURE__ */ jsx10(
2540
+ message.role === "user" && hasFileContent(message.content) && /* @__PURE__ */ jsx11("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px", marginBottom: "8px" }, children: message.content.filter((part) => part.type === "file").map((part, idx) => /* @__PURE__ */ jsx11(
2286
2541
  FilePlaceholder,
2287
2542
  {
2288
2543
  name: part.file.name,
@@ -2290,7 +2545,7 @@ function UseAIChatPanel({
2290
2545
  },
2291
2546
  idx
2292
2547
  )) }),
2293
- message.role === "assistant" ? /* @__PURE__ */ jsx10(MarkdownContent, { content: getTextContent(message.content) }) : getTextContent(message.content)
2548
+ message.role === "assistant" ? /* @__PURE__ */ jsx11(MarkdownContent, { content: getTextContent(message.content) }) : getTextContent(message.content)
2294
2549
  ]
2295
2550
  }
2296
2551
  ),
@@ -2301,7 +2556,7 @@ function UseAIChatPanel({
2301
2556
  ]
2302
2557
  }
2303
2558
  ),
2304
- message.role === "assistant" && message.traceId && feedbackEnabled && onFeedback && /* @__PURE__ */ jsxs7(
2559
+ message.role === "assistant" && message.traceId && feedbackEnabled && onFeedback && /* @__PURE__ */ jsxs8(
2305
2560
  "div",
2306
2561
  {
2307
2562
  "data-testid": "feedback-buttons",
@@ -2312,7 +2567,7 @@ function UseAIChatPanel({
2312
2567
  padding: "0 4px"
2313
2568
  },
2314
2569
  children: [
2315
- /* @__PURE__ */ jsx10(
2570
+ /* @__PURE__ */ jsx11(
2316
2571
  FeedbackButton,
2317
2572
  {
2318
2573
  type: "upvote",
@@ -2325,7 +2580,7 @@ function UseAIChatPanel({
2325
2580
  unselectedColor: theme.secondaryTextColor
2326
2581
  }
2327
2582
  ),
2328
- /* @__PURE__ */ jsx10(
2583
+ /* @__PURE__ */ jsx11(
2329
2584
  FeedbackButton,
2330
2585
  {
2331
2586
  type: "downvote",
@@ -2341,7 +2596,7 @@ function UseAIChatPanel({
2341
2596
  ]
2342
2597
  }
2343
2598
  ),
2344
- /* @__PURE__ */ jsx10(
2599
+ /* @__PURE__ */ jsx11(
2345
2600
  "div",
2346
2601
  {
2347
2602
  style: {
@@ -2360,14 +2615,14 @@ function UseAIChatPanel({
2360
2615
  },
2361
2616
  message.id
2362
2617
  )),
2363
- loading && /* @__PURE__ */ jsx10(
2618
+ loading && /* @__PURE__ */ jsx11(
2364
2619
  "div",
2365
2620
  {
2366
2621
  style: {
2367
2622
  display: "flex",
2368
2623
  alignItems: "flex-start"
2369
2624
  },
2370
- children: /* @__PURE__ */ jsx10(
2625
+ children: /* @__PURE__ */ jsx11(
2371
2626
  "div",
2372
2627
  {
2373
2628
  className: "markdown-content",
@@ -2380,20 +2635,20 @@ function UseAIChatPanel({
2380
2635
  color: theme.textColor,
2381
2636
  maxWidth: "80%"
2382
2637
  },
2383
- children: streamingText ? /* @__PURE__ */ jsx10(MarkdownContent, { content: streamingText }) : fileProcessing && fileProcessing.status === "processing" ? /* @__PURE__ */ jsxs7("div", { children: [
2384
- /* @__PURE__ */ jsx10("span", { style: { opacity: 0.6 }, children: strings.input.processingFile }),
2385
- fileProcessing.progress != null && /* @__PURE__ */ jsxs7(Fragment, { children: [
2386
- /* @__PURE__ */ jsxs7("span", { style: { opacity: 0.6, marginLeft: "4px" }, children: [
2638
+ children: streamingText ? /* @__PURE__ */ jsx11(MarkdownContent, { content: streamingText }) : fileProcessing && fileProcessing.status === "processing" ? /* @__PURE__ */ jsxs8("div", { children: [
2639
+ /* @__PURE__ */ jsx11("span", { style: { opacity: 0.6 }, children: strings.input.processingFile }),
2640
+ fileProcessing.progress != null && /* @__PURE__ */ jsxs8(Fragment, { children: [
2641
+ /* @__PURE__ */ jsxs8("span", { style: { opacity: 0.6, marginLeft: "4px" }, children: [
2387
2642
  Math.round(fileProcessing.progress),
2388
2643
  "%"
2389
2644
  ] }),
2390
- /* @__PURE__ */ jsx10("div", { style: {
2645
+ /* @__PURE__ */ jsx11("div", { style: {
2391
2646
  marginTop: "6px",
2392
2647
  height: "4px",
2393
2648
  borderRadius: "2px",
2394
2649
  background: theme.borderColor,
2395
2650
  overflow: "hidden"
2396
- }, children: /* @__PURE__ */ jsx10("div", { style: {
2651
+ }, children: /* @__PURE__ */ jsx11("div", { style: {
2397
2652
  height: "100%",
2398
2653
  width: `${fileProcessing.progress}%`,
2399
2654
  borderRadius: "2px",
@@ -2401,17 +2656,17 @@ function UseAIChatPanel({
2401
2656
  transition: "width 0.3s ease"
2402
2657
  } }) })
2403
2658
  ] }),
2404
- fileProcessing.progress == null && /* @__PURE__ */ jsx10("span", { className: "dots", style: { marginLeft: "4px" }, children: "..." })
2405
- ] }) : /* @__PURE__ */ jsx10("span", { className: "dots", style: { opacity: 0.6 }, children: "..." })
2659
+ fileProcessing.progress == null && /* @__PURE__ */ jsx11("span", { className: "dots", style: { marginLeft: "4px" }, children: "..." })
2660
+ ] }) : /* @__PURE__ */ jsx11("span", { className: "dots", style: { opacity: 0.6 }, children: "..." })
2406
2661
  }
2407
2662
  )
2408
2663
  }
2409
2664
  ),
2410
- /* @__PURE__ */ jsx10("div", { ref: messagesEndRef })
2665
+ /* @__PURE__ */ jsx11("div", { ref: messagesEndRef })
2411
2666
  ]
2412
2667
  }
2413
2668
  ),
2414
- /* @__PURE__ */ jsxs7(
2669
+ /* @__PURE__ */ jsxs8(
2415
2670
  "div",
2416
2671
  {
2417
2672
  style: {
@@ -2419,7 +2674,7 @@ function UseAIChatPanel({
2419
2674
  borderTop: `1px solid ${theme.borderColor}`
2420
2675
  },
2421
2676
  children: [
2422
- fileError && /* @__PURE__ */ jsx10(
2677
+ fileError && /* @__PURE__ */ jsx11(
2423
2678
  "div",
2424
2679
  {
2425
2680
  "data-testid": "file-error",
@@ -2434,7 +2689,7 @@ function UseAIChatPanel({
2434
2689
  children: fileError
2435
2690
  }
2436
2691
  ),
2437
- attachments.length > 0 && /* @__PURE__ */ jsx10(
2692
+ attachments.length > 0 && /* @__PURE__ */ jsx11(
2438
2693
  "div",
2439
2694
  {
2440
2695
  "data-testid": "file-attachments",
@@ -2444,7 +2699,7 @@ function UseAIChatPanel({
2444
2699
  gap: "8px",
2445
2700
  marginBottom: "8px"
2446
2701
  },
2447
- children: attachments.map((attachment) => /* @__PURE__ */ jsx10(
2702
+ children: attachments.map((attachment) => /* @__PURE__ */ jsx11(
2448
2703
  FileChip,
2449
2704
  {
2450
2705
  attachment,
@@ -2456,143 +2711,159 @@ function UseAIChatPanel({
2456
2711
  ))
2457
2712
  }
2458
2713
  ),
2459
- /* @__PURE__ */ jsxs7(
2460
- "div",
2714
+ /* @__PURE__ */ jsx11(
2715
+ "input",
2461
2716
  {
2462
- style: {
2463
- border: `1px solid ${theme.borderColor}`,
2464
- borderRadius: "12px",
2465
- background: theme.backgroundColor,
2466
- overflow: "hidden",
2467
- position: "relative"
2468
- },
2469
- children: [
2470
- slashCommands.AutocompleteComponent,
2471
- /* @__PURE__ */ jsx10(
2472
- "input",
2473
- {
2474
- ref: fileInputRef,
2475
- type: "file",
2476
- multiple: true,
2477
- "data-testid": "file-input",
2478
- style: { display: "none" },
2479
- onChange: handleFileInputChange,
2480
- accept: acceptedTypes?.join(",")
2481
- }
2482
- ),
2483
- /* @__PURE__ */ jsx10(
2484
- "textarea",
2485
- {
2486
- ref: textareaRef,
2487
- "data-testid": "chat-input",
2488
- className: "chat-input",
2489
- value: input,
2490
- onChange: handleInputChange,
2491
- onKeyDown: handleKeyDown,
2492
- placeholder: !connected ? strings.input.connectingPlaceholder : loading ? `${executingTool?.displayText ?? strings.input.thinking}...` : strings.input.placeholder,
2493
- disabled: !connected || loading,
2494
- rows: 1,
2495
- style: {
2496
- width: "100%",
2497
- padding: "10px 14px 6px",
2498
- border: "none",
2499
- fontSize: "14px",
2500
- lineHeight: "1.4",
2501
- resize: "none",
2502
- maxHeight: `${maxTextareaHeight}px`,
2503
- fontFamily: "inherit",
2504
- outline: "none",
2505
- background: "transparent",
2506
- overflowY: "auto",
2507
- boxSizing: "border-box"
2508
- }
2509
- }
2510
- ),
2511
- /* @__PURE__ */ jsxs7(
2512
- "div",
2513
- {
2514
- style: {
2515
- display: "flex",
2516
- alignItems: "center",
2517
- justifyContent: "space-between",
2518
- padding: "4px 8px"
2519
- },
2520
- children: [
2521
- /* @__PURE__ */ jsx10("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: fileUploadEnabled && /* @__PURE__ */ jsx10(
2522
- "button",
2523
- {
2524
- "data-testid": "file-picker-button",
2525
- onClick: openFilePicker,
2526
- disabled: !connected || loading,
2527
- style: {
2528
- padding: "4px",
2529
- background: "transparent",
2530
- border: `1px solid ${theme.borderColor}`,
2531
- borderRadius: "50%",
2532
- cursor: connected && !loading ? "pointer" : "not-allowed",
2533
- color: theme.secondaryTextColor,
2534
- display: "flex",
2535
- alignItems: "center",
2536
- justifyContent: "center",
2537
- width: "28px",
2538
- height: "28px",
2539
- transition: "all 0.15s",
2540
- opacity: connected && !loading ? 1 : 0.5
2541
- },
2542
- onMouseEnter: (e) => {
2543
- if (connected && !loading) {
2544
- e.currentTarget.style.color = theme.primaryColor;
2545
- e.currentTarget.style.borderColor = theme.primaryColor;
2546
- }
2547
- },
2548
- onMouseLeave: (e) => {
2549
- e.currentTarget.style.color = theme.secondaryTextColor;
2550
- e.currentTarget.style.borderColor = theme.borderColor;
2551
- },
2552
- title: strings.fileUpload.attachFiles,
2553
- children: /* @__PURE__ */ jsxs7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2554
- /* @__PURE__ */ jsx10("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
2555
- /* @__PURE__ */ jsx10("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
2556
- ] })
2557
- }
2558
- ) }),
2559
- /* @__PURE__ */ jsx10(
2560
- "button",
2561
- {
2562
- "data-testid": "chat-send-button",
2563
- className: "chat-send-button",
2564
- onClick: handleSend,
2565
- disabled: !connected || loading || !input.trim() && attachments.length === 0,
2566
- style: {
2567
- padding: "6px",
2568
- background: connected && !loading && (input.trim() || attachments.length > 0) ? theme.primaryGradient : theme.buttonDisabledBackground,
2569
- color: connected && !loading && (input.trim() || attachments.length > 0) ? "white" : theme.secondaryTextColor,
2570
- border: "none",
2571
- borderRadius: "50%",
2572
- cursor: connected && !loading && (input.trim() || attachments.length > 0) ? "pointer" : "not-allowed",
2573
- display: "flex",
2574
- alignItems: "center",
2575
- justifyContent: "center",
2576
- width: "32px",
2577
- height: "32px",
2578
- transition: "all 0.2s"
2579
- },
2580
- children: /* @__PURE__ */ jsxs7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2581
- /* @__PURE__ */ jsx10("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
2582
- /* @__PURE__ */ jsx10("polyline", { points: "5 12 12 5 19 12" })
2583
- ] })
2584
- }
2585
- )
2586
- ]
2587
- }
2588
- )
2589
- ]
2717
+ ref: fileInputRef,
2718
+ type: "file",
2719
+ multiple: true,
2720
+ "data-testid": "file-input",
2721
+ style: { display: "none" },
2722
+ onChange: handleFileInputChange,
2723
+ accept: acceptedTypes?.join(",")
2590
2724
  }
2725
+ ),
2726
+ pendingApprovals.length > 0 && onApproveToolCall && onRejectToolCall ? /* @__PURE__ */ jsx11(
2727
+ ToolApprovalDialog,
2728
+ {
2729
+ toolCallName: pendingApprovals[0].toolCallName,
2730
+ toolCallArgs: pendingApprovals[0].toolCallArgs,
2731
+ annotations: pendingApprovals[0].annotations,
2732
+ toolCount: pendingApprovals.length,
2733
+ pendingTools: pendingApprovals,
2734
+ onApprove: onApproveToolCall,
2735
+ onReject: onRejectToolCall,
2736
+ theme,
2737
+ strings
2738
+ }
2739
+ ) : (
2740
+ /* Input container - single border around everything */
2741
+ /* @__PURE__ */ jsxs8(
2742
+ "div",
2743
+ {
2744
+ style: {
2745
+ border: `1px solid ${theme.borderColor}`,
2746
+ borderRadius: "12px",
2747
+ background: theme.backgroundColor,
2748
+ overflow: "hidden",
2749
+ position: "relative"
2750
+ },
2751
+ children: [
2752
+ slashCommands.AutocompleteComponent,
2753
+ /* @__PURE__ */ jsx11(
2754
+ "textarea",
2755
+ {
2756
+ ref: textareaRef,
2757
+ "data-testid": "chat-input",
2758
+ className: "chat-input",
2759
+ value: input,
2760
+ onChange: handleInputChange,
2761
+ onKeyDown: handleKeyDown,
2762
+ placeholder: !connected ? strings.input.connectingPlaceholder : loading ? `${executingTool?.displayText ?? strings.input.thinking}...` : strings.input.placeholder,
2763
+ disabled: !connected || loading || pendingApprovals.length > 0,
2764
+ rows: 1,
2765
+ style: {
2766
+ width: "100%",
2767
+ padding: "10px 14px 6px",
2768
+ border: "none",
2769
+ fontSize: "14px",
2770
+ lineHeight: "1.4",
2771
+ resize: "none",
2772
+ maxHeight: `${maxTextareaHeight}px`,
2773
+ fontFamily: "inherit",
2774
+ outline: "none",
2775
+ background: "transparent",
2776
+ overflowY: "auto",
2777
+ boxSizing: "border-box"
2778
+ }
2779
+ }
2780
+ ),
2781
+ /* @__PURE__ */ jsxs8(
2782
+ "div",
2783
+ {
2784
+ style: {
2785
+ display: "flex",
2786
+ alignItems: "center",
2787
+ justifyContent: "space-between",
2788
+ padding: "4px 8px"
2789
+ },
2790
+ children: [
2791
+ /* @__PURE__ */ jsx11("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: fileUploadEnabled && /* @__PURE__ */ jsx11(
2792
+ "button",
2793
+ {
2794
+ "data-testid": "file-picker-button",
2795
+ onClick: openFilePicker,
2796
+ disabled: !connected || loading || pendingApprovals.length > 0,
2797
+ style: {
2798
+ padding: "4px",
2799
+ background: "transparent",
2800
+ border: `1px solid ${theme.borderColor}`,
2801
+ borderRadius: "50%",
2802
+ cursor: connected && !loading && pendingApprovals.length === 0 ? "pointer" : "not-allowed",
2803
+ color: theme.secondaryTextColor,
2804
+ display: "flex",
2805
+ alignItems: "center",
2806
+ justifyContent: "center",
2807
+ width: "28px",
2808
+ height: "28px",
2809
+ transition: "all 0.15s",
2810
+ opacity: connected && !loading && pendingApprovals.length === 0 ? 1 : 0.5
2811
+ },
2812
+ onMouseEnter: (e) => {
2813
+ if (connected && !loading && pendingApprovals.length === 0) {
2814
+ e.currentTarget.style.color = theme.primaryColor;
2815
+ e.currentTarget.style.borderColor = theme.primaryColor;
2816
+ }
2817
+ },
2818
+ onMouseLeave: (e) => {
2819
+ e.currentTarget.style.color = theme.secondaryTextColor;
2820
+ e.currentTarget.style.borderColor = theme.borderColor;
2821
+ },
2822
+ title: strings.fileUpload.attachFiles,
2823
+ children: /* @__PURE__ */ jsxs8("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2824
+ /* @__PURE__ */ jsx11("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
2825
+ /* @__PURE__ */ jsx11("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
2826
+ ] })
2827
+ }
2828
+ ) }),
2829
+ /* @__PURE__ */ jsx11(
2830
+ "button",
2831
+ {
2832
+ "data-testid": "chat-send-button",
2833
+ className: "chat-send-button",
2834
+ onClick: handleSend,
2835
+ disabled: !connected || loading || pendingApprovals.length > 0 || !input.trim() && attachments.length === 0,
2836
+ style: {
2837
+ padding: "6px",
2838
+ background: connected && !loading && pendingApprovals.length === 0 && (input.trim() || attachments.length > 0) ? theme.primaryGradient : theme.buttonDisabledBackground,
2839
+ color: connected && !loading && pendingApprovals.length === 0 && (input.trim() || attachments.length > 0) ? "white" : theme.secondaryTextColor,
2840
+ border: "none",
2841
+ borderRadius: "50%",
2842
+ cursor: connected && !loading && pendingApprovals.length === 0 && (input.trim() || attachments.length > 0) ? "pointer" : "not-allowed",
2843
+ display: "flex",
2844
+ alignItems: "center",
2845
+ justifyContent: "center",
2846
+ width: "32px",
2847
+ height: "32px",
2848
+ transition: "all 0.2s"
2849
+ },
2850
+ children: /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2851
+ /* @__PURE__ */ jsx11("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
2852
+ /* @__PURE__ */ jsx11("polyline", { points: "5 12 12 5 19 12" })
2853
+ ] })
2854
+ }
2855
+ )
2856
+ ]
2857
+ }
2858
+ )
2859
+ ]
2860
+ }
2861
+ )
2591
2862
  )
2592
2863
  ]
2593
2864
  }
2594
2865
  ),
2595
- /* @__PURE__ */ jsx10("style", { children: `
2866
+ /* @__PURE__ */ jsx11("style", { children: `
2596
2867
  /* Markdown content styles */
2597
2868
  .markdown-content > :first-child {
2598
2869
  margin-top: 0 !important;
@@ -2617,7 +2888,7 @@ function UseAIChatPanel({
2617
2888
  }
2618
2889
 
2619
2890
  // src/components/UseAIFloatingChatWrapper.tsx
2620
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2891
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2621
2892
  function UseAIFloatingChatWrapper({
2622
2893
  isOpen,
2623
2894
  onClose,
@@ -2625,8 +2896,8 @@ function UseAIFloatingChatWrapper({
2625
2896
  }) {
2626
2897
  const theme = useTheme();
2627
2898
  if (!isOpen) return null;
2628
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
2629
- /* @__PURE__ */ jsx11(
2899
+ return /* @__PURE__ */ jsxs9(Fragment2, { children: [
2900
+ /* @__PURE__ */ jsx12(
2630
2901
  "div",
2631
2902
  {
2632
2903
  style: {
@@ -2642,7 +2913,7 @@ function UseAIFloatingChatWrapper({
2642
2913
  onClick: onClose
2643
2914
  }
2644
2915
  ),
2645
- /* @__PURE__ */ jsx11(
2916
+ /* @__PURE__ */ jsx12(
2646
2917
  "div",
2647
2918
  {
2648
2919
  style: {
@@ -2661,7 +2932,7 @@ function UseAIFloatingChatWrapper({
2661
2932
  children
2662
2933
  }
2663
2934
  ),
2664
- /* @__PURE__ */ jsx11("style", { children: `
2935
+ /* @__PURE__ */ jsx12("style", { children: `
2665
2936
  @keyframes fadeIn {
2666
2937
  from { opacity: 0; }
2667
2938
  to { opacity: 1; }
@@ -2681,7 +2952,7 @@ function UseAIFloatingChatWrapper({
2681
2952
  }
2682
2953
  function CloseButton({ onClick }) {
2683
2954
  const theme = useTheme();
2684
- return /* @__PURE__ */ jsx11(
2955
+ return /* @__PURE__ */ jsx12(
2685
2956
  "button",
2686
2957
  {
2687
2958
  "data-testid": "chat-close-button",
@@ -2716,7 +2987,7 @@ function CloseButton({ onClick }) {
2716
2987
 
2717
2988
  // src/components/UseAIChat.tsx
2718
2989
  import { createContext as createContext3, useContext as useContext3 } from "react";
2719
- import { jsx as jsx12 } from "react/jsx-runtime";
2990
+ import { jsx as jsx13 } from "react/jsx-runtime";
2720
2991
  var __UseAIChatContext = createContext3(null);
2721
2992
  function useChatUIContext() {
2722
2993
  const context = useContext3(__UseAIChatContext);
@@ -2752,27 +3023,30 @@ function UseAIChat({ floating = false }) {
2752
3023
  onSaveCommand: ctx.commands.save,
2753
3024
  onRenameCommand: ctx.commands.rename,
2754
3025
  onDeleteCommand: ctx.commands.delete,
2755
- executingTool: ctx.executingTool,
3026
+ executingTool: ctx.tools.executing,
2756
3027
  feedbackEnabled: ctx.feedback?.enabled,
2757
- onFeedback: ctx.feedback?.submit
3028
+ onFeedback: ctx.feedback?.submit,
3029
+ pendingApprovals: ctx.tools.pending.tools,
3030
+ onApproveToolCall: ctx.tools.pending.tools.length > 0 ? ctx.tools.pending.approveAll : void 0,
3031
+ onRejectToolCall: ctx.tools.pending.tools.length > 0 ? ctx.tools.pending.rejectAll : void 0
2758
3032
  };
2759
3033
  if (floating) {
2760
- return /* @__PURE__ */ jsx12(
3034
+ return /* @__PURE__ */ jsx13(
2761
3035
  UseAIFloatingChatWrapper,
2762
3036
  {
2763
3037
  isOpen: ctx.ui.isOpen,
2764
3038
  onClose: () => ctx.ui.setOpen(false),
2765
- children: /* @__PURE__ */ jsx12(
3039
+ children: /* @__PURE__ */ jsx13(
2766
3040
  UseAIChatPanel,
2767
3041
  {
2768
3042
  ...chatPanelProps,
2769
- closeButton: /* @__PURE__ */ jsx12(CloseButton, { onClick: () => ctx.ui.setOpen(false) })
3043
+ closeButton: /* @__PURE__ */ jsx13(CloseButton, { onClick: () => ctx.ui.setOpen(false) })
2770
3044
  }
2771
3045
  )
2772
3046
  }
2773
3047
  );
2774
3048
  }
2775
- return /* @__PURE__ */ jsx12(UseAIChatPanel, { ...chatPanelProps });
3049
+ return /* @__PURE__ */ jsx13(UseAIChatPanel, { ...chatPanelProps });
2776
3050
  }
2777
3051
 
2778
3052
  // src/client.ts
@@ -3019,7 +3293,8 @@ var UseAIClient = class {
3019
3293
  tools: this._tools.map((t) => ({
3020
3294
  name: t.name,
3021
3295
  description: t.description,
3022
- parameters: t.parameters
3296
+ parameters: t.parameters,
3297
+ annotations: t.annotations
3023
3298
  })),
3024
3299
  state: this._state,
3025
3300
  context: [],
@@ -3062,6 +3337,24 @@ var UseAIClient = class {
3062
3337
  this._messages.push(toolResultMsg);
3063
3338
  this.send(toolResultMessage);
3064
3339
  }
3340
+ /**
3341
+ * Sends a tool approval response back to the server.
3342
+ *
3343
+ * @param toolCallId - The ID of the tool call being approved/rejected
3344
+ * @param approved - Whether the tool execution is approved
3345
+ * @param reason - Optional reason for rejection (shown to AI)
3346
+ */
3347
+ sendToolApprovalResponse(toolCallId, approved, reason) {
3348
+ const message = {
3349
+ type: "tool_approval_response",
3350
+ data: {
3351
+ toolCallId,
3352
+ approved,
3353
+ reason
3354
+ }
3355
+ };
3356
+ this.send(message);
3357
+ }
3065
3358
  /**
3066
3359
  * Retrieves accumulated tool call data for a specific tool call ID.
3067
3360
  * Used to get the complete tool name and arguments after they've been streamed
@@ -3534,7 +3827,7 @@ var LocalStorageChatRepository = class {
3534
3827
  };
3535
3828
 
3536
3829
  // src/hooks/useChatManagement.ts
3537
- import { useState as useState5, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect5 } from "react";
3830
+ import { useState as useState6, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect5 } from "react";
3538
3831
  var CHAT_TITLE_MAX_LENGTH = 50;
3539
3832
  function deepEquals(a, b) {
3540
3833
  return JSON.stringify(a) === JSON.stringify(b);
@@ -3577,10 +3870,11 @@ function useChatManagement({
3577
3870
  onSendMessage,
3578
3871
  setOpen,
3579
3872
  connected,
3580
- loading
3873
+ loading,
3874
+ hasPendingApproval
3581
3875
  }) {
3582
- const [currentChatId, setCurrentChatId] = useState5(null);
3583
- const [pendingChatId, setPendingChatId] = useState5(null);
3876
+ const [currentChatId, setCurrentChatId] = useState6(null);
3877
+ const [pendingChatId, setPendingChatId] = useState6(null);
3584
3878
  const currentChatIdSnapshot = useRef5(null);
3585
3879
  const pendingChatIdSnapshot = useRef5(null);
3586
3880
  useEffect5(() => {
@@ -3799,6 +4093,10 @@ function useChatManagement({
3799
4093
  useEffect5(() => {
3800
4094
  loadingRef.current = loading;
3801
4095
  }, [loading]);
4096
+ const hasPendingApprovalRef = useRef5(hasPendingApproval);
4097
+ useEffect5(() => {
4098
+ hasPendingApprovalRef.current = hasPendingApproval;
4099
+ }, [hasPendingApproval]);
3802
4100
  const processMessageQueue = useCallback4(async () => {
3803
4101
  if (isProcessingQueueRef.current || pendingMessagesRef.current.length === 0 || !onSendMessage) {
3804
4102
  return;
@@ -3833,16 +4131,16 @@ function useChatManagement({
3833
4131
  setOpen(true);
3834
4132
  }
3835
4133
  await new Promise((resolve) => {
3836
- const checkLoading = () => {
4134
+ const checkReady = () => {
3837
4135
  setTimeout(() => {
3838
- if (!loadingRef.current) {
4136
+ if (!loadingRef.current && !hasPendingApprovalRef.current) {
3839
4137
  resolve();
3840
4138
  } else {
3841
- checkLoading();
4139
+ checkReady();
3842
4140
  }
3843
4141
  }, 100);
3844
4142
  };
3845
- checkLoading();
4143
+ checkReady();
3846
4144
  });
3847
4145
  }
3848
4146
  isProcessingQueueRef.current = false;
@@ -3879,7 +4177,7 @@ function useChatManagement({
3879
4177
  }
3880
4178
 
3881
4179
  // src/hooks/useAgentSelection.ts
3882
- import { useState as useState6, useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3 } from "react";
4180
+ import { useState as useState7, useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3 } from "react";
3883
4181
  function filterAgents(serverAgents, defaultAgentId, visibleAgentIds) {
3884
4182
  const getDefaultAgentFallback = () => {
3885
4183
  const defaultAgentInfo = serverAgents.find((a) => a.id === defaultAgentId);
@@ -3905,9 +4203,9 @@ function useAgentSelection({
3905
4203
  connected,
3906
4204
  visibleAgentIds
3907
4205
  }) {
3908
- const [serverAgents, setServerAgents] = useState6([]);
3909
- const [defaultAgent, setDefaultAgent] = useState6(null);
3910
- const [selectedAgent, setSelectedAgent] = useState6(null);
4206
+ const [serverAgents, setServerAgents] = useState7([]);
4207
+ const [defaultAgent, setDefaultAgent] = useState7(null);
4208
+ const [selectedAgent, setSelectedAgent] = useState7(null);
3911
4209
  const availableAgents = useMemo3(
3912
4210
  () => filterAgents(serverAgents, defaultAgent, visibleAgentIds),
3913
4211
  [serverAgents, defaultAgent, visibleAgentIds]
@@ -3944,7 +4242,7 @@ function useAgentSelection({
3944
4242
  }
3945
4243
 
3946
4244
  // src/hooks/useCommandManagement.ts
3947
- import { useState as useState7, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect7 } from "react";
4245
+ import { useState as useState8, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect7 } from "react";
3948
4246
 
3949
4247
  // src/commands/LocalStorageCommandRepository.ts
3950
4248
  var STORAGE_KEY_PREFIX2 = "use-ai:command:";
@@ -4077,7 +4375,7 @@ function useCommandManagement({
4077
4375
  const repositoryRef = useRef6(
4078
4376
  repository || new LocalStorageCommandRepository()
4079
4377
  );
4080
- const [commands, setCommands] = useState7([]);
4378
+ const [commands, setCommands] = useState8([]);
4081
4379
  const refreshCommands = useCallback6(async () => {
4082
4380
  try {
4083
4381
  const cmdList = await repositoryRef.current.listCommands();
@@ -4119,10 +4417,10 @@ function useCommandManagement({
4119
4417
  }
4120
4418
 
4121
4419
  // src/hooks/useToolRegistry.ts
4122
- import { useState as useState8, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
4420
+ import { useState as useState9, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
4123
4421
  function useToolRegistry() {
4124
4422
  const toolRegistryRef = useRef7(/* @__PURE__ */ new Map());
4125
- const [toolRegistryVersion, setToolRegistryVersion] = useState8(0);
4423
+ const [toolRegistryVersion, setToolRegistryVersion] = useState9(0);
4126
4424
  const toolOwnershipRef = useRef7(/* @__PURE__ */ new Map());
4127
4425
  const invisibleRef = useRef7(/* @__PURE__ */ new Set());
4128
4426
  const registerTools = useCallback7((id, tools, options) => {
@@ -4182,7 +4480,7 @@ function useToolRegistry() {
4182
4480
  }
4183
4481
 
4184
4482
  // src/hooks/usePromptState.ts
4185
- import { useState as useState9, useCallback as useCallback8, useRef as useRef8, useMemo as useMemo5, useEffect as useEffect8 } from "react";
4483
+ import { useState as useState10, useCallback as useCallback8, useRef as useRef8, useMemo as useMemo5, useEffect as useEffect8 } from "react";
4186
4484
  function usePromptState({
4187
4485
  systemPrompt,
4188
4486
  clientRef,
@@ -4191,7 +4489,7 @@ function usePromptState({
4191
4489
  const promptsRef = useRef8(/* @__PURE__ */ new Map());
4192
4490
  const suggestionsRef = useRef8(/* @__PURE__ */ new Map());
4193
4491
  const waitersRef = useRef8(/* @__PURE__ */ new Map());
4194
- const [suggestionsVersion, setSuggestionsVersion] = useState9(0);
4492
+ const [suggestionsVersion, setSuggestionsVersion] = useState10(0);
4195
4493
  const buildStateFromPrompts = useCallback8(() => {
4196
4494
  const promptParts = [];
4197
4495
  if (systemPrompt) {
@@ -4254,14 +4552,14 @@ function usePromptState({
4254
4552
  }
4255
4553
 
4256
4554
  // src/hooks/useFeedback.ts
4257
- import { useState as useState10, useEffect as useEffect9, useRef as useRef9, useCallback as useCallback9 } from "react";
4555
+ import { useState as useState11, useEffect as useEffect9, useRef as useRef9, useCallback as useCallback9 } from "react";
4258
4556
  function useFeedback({
4259
4557
  clientRef,
4260
4558
  repository,
4261
4559
  getDisplayedChatId,
4262
4560
  setMessages
4263
4561
  }) {
4264
- const [enabled, setEnabled] = useState10(false);
4562
+ const [enabled, setEnabled] = useState11(false);
4265
4563
  const enabledRef = useRef9(false);
4266
4564
  useEffect9(() => {
4267
4565
  enabledRef.current = enabled;
@@ -4315,8 +4613,120 @@ function useFeedback({
4315
4613
  };
4316
4614
  }
4317
4615
 
4616
+ // src/hooks/useToolExecution.ts
4617
+ import { useState as useState12, useCallback as useCallback10, useRef as useRef10 } from "react";
4618
+ function useToolExecution({
4619
+ clientRef,
4620
+ aggregatedToolsRef,
4621
+ toolOwnershipRef,
4622
+ promptsRef,
4623
+ isInvisible,
4624
+ getWaiter
4625
+ }) {
4626
+ const [pendingApprovals, setPendingApprovals] = useState12([]);
4627
+ const pendingApprovalToolCallsRef = useRef10(/* @__PURE__ */ new Map());
4628
+ const handleApprovalRequest = useCallback10((event) => {
4629
+ console.log("[useToolExecution] Tool approval requested:", event.toolCallName, event.toolCallId);
4630
+ setPendingApprovals((prev) => [
4631
+ ...prev,
4632
+ {
4633
+ toolCallId: event.toolCallId,
4634
+ toolCallName: event.toolCallName,
4635
+ toolCallArgs: event.toolCallArgs,
4636
+ annotations: event.annotations
4637
+ }
4638
+ ]);
4639
+ }, []);
4640
+ const executeToolCall = useCallback10(async (toolCallId, name, input) => {
4641
+ const client = clientRef.current;
4642
+ if (!client) {
4643
+ console.error("[useToolExecution] No client available for tool execution");
4644
+ return;
4645
+ }
4646
+ try {
4647
+ const ownerId = toolOwnershipRef.current.get(name);
4648
+ console.log(`[useToolExecution] Tool "${name}" owned by component:`, ownerId);
4649
+ console.log("[useToolExecution] Executing tool...");
4650
+ const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
4651
+ const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
4652
+ const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
4653
+ if (ownerId && !isErrorResult && !ownerIsInvisible) {
4654
+ const waiter = getWaiter(ownerId);
4655
+ if (waiter) {
4656
+ console.log(`[useToolExecution] Waiting for prompt change from ${ownerId}...`);
4657
+ await waiter();
4658
+ console.log("[useToolExecution] Prompt change wait complete");
4659
+ }
4660
+ } else if (isErrorResult) {
4661
+ console.log("[useToolExecution] Tool returned error, skipping prompt wait");
4662
+ } else if (ownerIsInvisible) {
4663
+ console.log("[useToolExecution] Component is invisible, skipping prompt wait");
4664
+ }
4665
+ let updatedState = null;
4666
+ if (ownerId) {
4667
+ const prompt = promptsRef.current.get(ownerId);
4668
+ if (prompt) {
4669
+ updatedState = { context: prompt };
4670
+ console.log(`[useToolExecution] Updated state from ${ownerId}`);
4671
+ }
4672
+ }
4673
+ client.sendToolResponse(toolCallId, result, updatedState);
4674
+ } catch (err) {
4675
+ console.error("Tool execution error:", err);
4676
+ client.sendToolResponse(toolCallId, {
4677
+ error: err instanceof Error ? err.message : "Unknown error"
4678
+ });
4679
+ }
4680
+ }, [clientRef, aggregatedToolsRef, toolOwnershipRef, promptsRef, isInvisible, getWaiter]);
4681
+ const storePendingToolCall = useCallback10((toolCallId, name, input, toolCallData) => {
4682
+ console.log(`[useToolExecution] Storing pending tool call "${name}" for approval`);
4683
+ pendingApprovalToolCallsRef.current.set(toolCallId, { name, input, toolCallData });
4684
+ }, []);
4685
+ const executePendingToolAfterApproval = useCallback10(async (toolCallId) => {
4686
+ const pendingTool = pendingApprovalToolCallsRef.current.get(toolCallId);
4687
+ if (!pendingTool) {
4688
+ console.warn(`[useToolExecution] No pending tool found for ${toolCallId}`);
4689
+ return;
4690
+ }
4691
+ pendingApprovalToolCallsRef.current.delete(toolCallId);
4692
+ await executeToolCall(toolCallId, pendingTool.name, pendingTool.input);
4693
+ }, [executeToolCall]);
4694
+ const approveAll = useCallback10(async () => {
4695
+ if (!clientRef.current) return;
4696
+ console.log("[useToolExecution] Approving all tool calls:", pendingApprovals.length);
4697
+ const pendingTools = [...pendingApprovals];
4698
+ for (const pending of pendingTools) {
4699
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
4700
+ }
4701
+ setPendingApprovals([]);
4702
+ for (const tool of pendingTools) {
4703
+ await executePendingToolAfterApproval(tool.toolCallId);
4704
+ }
4705
+ }, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
4706
+ const rejectAll = useCallback10((reason) => {
4707
+ if (!clientRef.current) return;
4708
+ console.log("[useToolExecution] Rejecting all tool calls:", pendingApprovals.length, reason);
4709
+ const pendingTools = [...pendingApprovals];
4710
+ for (const pending of pendingTools) {
4711
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
4712
+ }
4713
+ setPendingApprovals([]);
4714
+ for (const tool of pendingTools) {
4715
+ pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
4716
+ }
4717
+ }, [clientRef, pendingApprovals]);
4718
+ return {
4719
+ pendingApprovals,
4720
+ handleApprovalRequest,
4721
+ executeToolCall,
4722
+ storePendingToolCall,
4723
+ approveAll,
4724
+ rejectAll
4725
+ };
4726
+ }
4727
+
4318
4728
  // src/providers/useAIProvider.tsx
4319
- import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
4729
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
4320
4730
  var __UseAIContext = createContext4(null);
4321
4731
  var hasWarnedAboutMissingProvider = false;
4322
4732
  var noOpContextValue = {
@@ -4396,24 +4806,24 @@ function UseAIProvider({
4396
4806
  const fileUploadConfig = fileUploadConfigProp === false ? void 0 : fileUploadConfigProp ?? DEFAULT_FILE_UPLOAD_CONFIG;
4397
4807
  const theme = { ...defaultTheme, ...customTheme };
4398
4808
  const strings = { ...defaultStrings, ...customStrings };
4399
- const [connected, setConnected] = useState11(false);
4400
- const [isChatOpen, setIsChatOpen] = useState11(false);
4401
- const [loading, setLoading] = useState11(false);
4402
- const [messages, setMessages] = useState11([]);
4403
- const [fileProcessingState, setFileProcessingState] = useState11(null);
4404
- const handleSetChatOpen = useCallback10((open) => {
4809
+ const [connected, setConnected] = useState13(false);
4810
+ const [isChatOpen, setIsChatOpen] = useState13(false);
4811
+ const [loading, setLoading] = useState13(false);
4812
+ const [messages, setMessages] = useState13([]);
4813
+ const [fileProcessingState, setFileProcessingState] = useState13(null);
4814
+ const handleSetChatOpen = useCallback11((open) => {
4405
4815
  setIsChatOpen(open);
4406
4816
  onOpenChange?.(open);
4407
4817
  }, [onOpenChange]);
4408
- const [streamingText, setStreamingText] = useState11("");
4409
- const streamingChatIdRef = useRef10(null);
4410
- const [executingTool, setExecutingTool] = useState11(null);
4411
- const executingToolFallbackRef = useRef10(null);
4412
- const clientRef = useRef10(null);
4413
- const repositoryRef = useRef10(
4818
+ const [streamingText, setStreamingText] = useState13("");
4819
+ const streamingChatIdRef = useRef11(null);
4820
+ const [executingTool, setExecutingTool] = useState13(null);
4821
+ const executingToolFallbackRef = useRef11(null);
4822
+ const clientRef = useRef11(null);
4823
+ const repositoryRef = useRef11(
4414
4824
  chatRepository || new LocalStorageChatRepository()
4415
4825
  );
4416
- const handleSendMessageRef = useRef10(null);
4826
+ const handleSendMessageRef = useRef11(null);
4417
4827
  const {
4418
4828
  registerTools,
4419
4829
  unregisterTools,
@@ -4435,11 +4845,19 @@ function UseAIProvider({
4435
4845
  clientRef,
4436
4846
  connected
4437
4847
  });
4438
- const stableSendMessage = useCallback10(async (message, attachments) => {
4848
+ const stableSendMessage = useCallback11(async (message, attachments) => {
4439
4849
  if (handleSendMessageRef.current) {
4440
4850
  await handleSendMessageRef.current(message, attachments);
4441
4851
  }
4442
4852
  }, []);
4853
+ const toolExecution = useToolExecution({
4854
+ clientRef,
4855
+ aggregatedToolsRef,
4856
+ toolOwnershipRef,
4857
+ promptsRef,
4858
+ isInvisible,
4859
+ getWaiter
4860
+ });
4443
4861
  const chatManagement = useChatManagement({
4444
4862
  repository: repositoryRef.current,
4445
4863
  clientRef,
@@ -4448,7 +4866,8 @@ function UseAIProvider({
4448
4866
  onSendMessage: stableSendMessage,
4449
4867
  setOpen: handleSetChatOpen,
4450
4868
  connected,
4451
- loading
4869
+ loading,
4870
+ hasPendingApproval: toolExecution.pendingApprovals.length > 0
4452
4871
  });
4453
4872
  const {
4454
4873
  currentChatId,
@@ -4518,44 +4937,20 @@ function UseAIProvider({
4518
4937
  }
4519
4938
  const name = toolCallData.name;
4520
4939
  const input = JSON.parse(toolCallData.args);
4521
- if (!aggregatedToolsRef.current[name]) {
4940
+ const tool = aggregatedToolsRef.current[name];
4941
+ if (!tool) {
4522
4942
  console.log(`[Provider] Tool "${name}" not found in useAI tools, skipping (likely a workflow tool)`);
4523
4943
  return;
4524
4944
  }
4525
- try {
4526
- const ownerId = toolOwnershipRef.current.get(name);
4527
- console.log(`[useAI] Tool "${name}" owned by component:`, ownerId);
4528
- console.log("[useAI] Executing tool...");
4529
- const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
4530
- const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
4531
- const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
4532
- if (ownerId && !isErrorResult && !ownerIsInvisible) {
4533
- const waiter = getWaiter(ownerId);
4534
- if (waiter) {
4535
- console.log(`[useAI] Waiting for prompt change from ${ownerId}...`);
4536
- await waiter();
4537
- console.log("[useAI] Prompt change wait complete");
4538
- }
4539
- } else if (isErrorResult) {
4540
- console.log("[useAI] Tool returned error, skipping prompt wait");
4541
- } else if (ownerIsInvisible) {
4542
- console.log("[useAI] Component is invisible, skipping prompt wait");
4543
- }
4544
- let updatedState = null;
4545
- if (ownerId) {
4546
- const prompt = promptsRef.current.get(ownerId);
4547
- if (prompt) {
4548
- updatedState = { context: prompt };
4549
- console.log(`[useAI] Updated state from ${ownerId}`);
4550
- }
4551
- }
4552
- client.sendToolResponse(toolCallId, result, updatedState);
4553
- } catch (err) {
4554
- console.error("Tool execution error:", err);
4555
- client.sendToolResponse(toolCallId, {
4556
- error: err instanceof Error ? err.message : "Unknown error"
4557
- });
4945
+ if (tool._options?.annotations?.destructiveHint === true) {
4946
+ console.log(`[Provider] Tool "${name}" requires approval, deferring execution`);
4947
+ toolExecution.storePendingToolCall(toolCallId, name, input, toolCallData);
4948
+ return;
4558
4949
  }
4950
+ await toolExecution.executeToolCall(toolCallId, name, input);
4951
+ } else if (event.type === TOOL_APPROVAL_REQUEST) {
4952
+ const e = event;
4953
+ toolExecution.handleApprovalRequest(e);
4559
4954
  } else if (event.type === EventType.TEXT_MESSAGE_CONTENT) {
4560
4955
  const contentEvent = event;
4561
4956
  setStreamingText((prev) => prev + contentEvent.delta);
@@ -4595,7 +4990,7 @@ function UseAIProvider({
4595
4990
  client.setMcpHeadersProvider(mcpHeadersProvider);
4596
4991
  }
4597
4992
  }, [mcpHeadersProvider]);
4598
- const lastRegisteredToolsRef = useRef10("");
4993
+ const lastRegisteredToolsRef = useRef11("");
4599
4994
  useEffect10(() => {
4600
4995
  const client = clientRef.current;
4601
4996
  if (!client || !client.isConnected() || !hasTools) return;
@@ -4614,7 +5009,7 @@ function UseAIProvider({
4614
5009
  console.error("Failed to register tools:", err);
4615
5010
  }
4616
5011
  }, [hasTools, aggregatedTools, connected]);
4617
- const handleSendMessage = useCallback10(async (message, attachments) => {
5012
+ const handleSendMessage = useCallback11(async (message, attachments) => {
4618
5013
  if (!clientRef.current) return;
4619
5014
  setStreamingText("");
4620
5015
  const activatedChatId = activatePendingChat();
@@ -4746,7 +5141,14 @@ function UseAIProvider({
4746
5141
  isOpen: isChatOpen,
4747
5142
  setOpen: handleSetChatOpen
4748
5143
  },
4749
- executingTool: executingToolDisplay,
5144
+ tools: {
5145
+ executing: executingToolDisplay,
5146
+ pending: {
5147
+ tools: toolExecution.pendingApprovals,
5148
+ approveAll: toolExecution.approveAll,
5149
+ rejectAll: toolExecution.rejectAll
5150
+ }
5151
+ },
4750
5152
  feedback: {
4751
5153
  enabled: feedback.enabled,
4752
5154
  submit: feedback.submitFeedback
@@ -4779,21 +5181,24 @@ function UseAIProvider({
4779
5181
  onDeleteCommand: deleteCommand,
4780
5182
  executingTool: executingToolDisplay,
4781
5183
  feedbackEnabled: feedback.enabled,
4782
- onFeedback: feedback.submitFeedback
5184
+ onFeedback: feedback.submitFeedback,
5185
+ pendingApprovals: toolExecution.pendingApprovals,
5186
+ onApproveToolCall: toolExecution.pendingApprovals.length > 0 ? toolExecution.approveAll : void 0,
5187
+ onRejectToolCall: toolExecution.pendingApprovals.length > 0 ? toolExecution.rejectAll : void 0
4783
5188
  };
4784
5189
  const renderDefaultChat = () => {
4785
5190
  if (isUIDisabled) return null;
4786
- return /* @__PURE__ */ jsx13(UseAIFloatingChatWrapper, { isOpen: isChatOpen, onClose: () => handleSetChatOpen(false), children: /* @__PURE__ */ jsx13(
5191
+ return /* @__PURE__ */ jsx14(UseAIFloatingChatWrapper, { isOpen: isChatOpen, onClose: () => handleSetChatOpen(false), children: /* @__PURE__ */ jsx14(
4787
5192
  UseAIChatPanel,
4788
5193
  {
4789
5194
  ...chatPanelProps,
4790
- closeButton: /* @__PURE__ */ jsx13(CloseButton, { onClick: () => handleSetChatOpen(false) })
5195
+ closeButton: /* @__PURE__ */ jsx14(CloseButton, { onClick: () => handleSetChatOpen(false) })
4791
5196
  }
4792
5197
  ) });
4793
5198
  };
4794
5199
  const renderCustomChat = () => {
4795
5200
  if (!CustomChat) return null;
4796
- return /* @__PURE__ */ jsx13(
5201
+ return /* @__PURE__ */ jsx14(
4797
5202
  CustomChat,
4798
5203
  {
4799
5204
  isOpen: isChatOpen,
@@ -4812,8 +5217,8 @@ function UseAIProvider({
4812
5217
  };
4813
5218
  const renderBuiltInChat = () => {
4814
5219
  if (!renderChat) return null;
4815
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
4816
- ButtonComponent && /* @__PURE__ */ jsx13(
5220
+ return /* @__PURE__ */ jsxs10(Fragment3, { children: [
5221
+ ButtonComponent && /* @__PURE__ */ jsx14(
4817
5222
  ButtonComponent,
4818
5223
  {
4819
5224
  onClick: () => handleSetChatOpen(true),
@@ -4823,7 +5228,7 @@ function UseAIProvider({
4823
5228
  hasCustomChat ? renderCustomChat() : renderDefaultChat()
4824
5229
  ] });
4825
5230
  };
4826
- return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ jsx13(StringsContext.Provider, { value: strings, children: /* @__PURE__ */ jsx13(__UseAIContext.Provider, { value, children: /* @__PURE__ */ jsxs9(__UseAIChatContext.Provider, { value: chatUIContextValue, children: [
5231
+ return /* @__PURE__ */ jsx14(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ jsx14(StringsContext.Provider, { value: strings, children: /* @__PURE__ */ jsx14(__UseAIContext.Provider, { value, children: /* @__PURE__ */ jsxs10(__UseAIChatContext.Provider, { value: chatUIContextValue, children: [
4827
5232
  children,
4828
5233
  renderBuiltInChat()
4829
5234
  ] }) }) }) });
@@ -4843,11 +5248,11 @@ function useAIContext() {
4843
5248
  }
4844
5249
 
4845
5250
  // src/hooks/useStableTools.ts
4846
- import { useRef as useRef11 } from "react";
5251
+ import { useRef as useRef12 } from "react";
4847
5252
  function useStableTools(tools) {
4848
- const latestToolsRef = useRef11({});
4849
- const stableToolsRef = useRef11({});
4850
- const prevToolNamesRef = useRef11("");
5253
+ const latestToolsRef = useRef12({});
5254
+ const stableToolsRef = useRef12({});
5255
+ const prevToolNamesRef = useRef12("");
4851
5256
  if (!tools) {
4852
5257
  latestToolsRef.current = {};
4853
5258
  return void 0;
@@ -4917,13 +5322,13 @@ function useAI(options = {}) {
4917
5322
  const { connected, tools, client, prompts } = useAIContext();
4918
5323
  const { register: registerTools, unregister: unregisterTools } = tools;
4919
5324
  const { update: updatePrompt, registerWaiter, unregisterWaiter } = prompts;
4920
- const [response, setResponse] = useState12(null);
4921
- const [loading, setLoading] = useState12(false);
4922
- const [error, setError] = useState12(null);
4923
- const hookId = useRef12(`useAI-${Math.random().toString(36).substr(2, 9)}`);
4924
- const toolsRef = useRef12({});
4925
- const componentRef = useRef12(null);
4926
- const promptChangeResolvers = useRef12([]);
5325
+ const [response, setResponse] = useState14(null);
5326
+ const [loading, setLoading] = useState14(false);
5327
+ const [error, setError] = useState14(null);
5328
+ const hookId = useRef13(`useAI-${Math.random().toString(36).substr(2, 9)}`);
5329
+ const toolsRef = useRef13({});
5330
+ const componentRef = useRef13(null);
5331
+ const promptChangeResolvers = useRef13([]);
4927
5332
  const stableTools = useStableTools(options.tools);
4928
5333
  const toolsKey = useMemo6(() => {
4929
5334
  if (!options.tools) return "";
@@ -4935,7 +5340,7 @@ function useAI(options = {}) {
4935
5340
  componentRef.current.setAttribute("data-useai-context", "true");
4936
5341
  }
4937
5342
  }, []);
4938
- const waitForPromptChange = useCallback11(() => {
5343
+ const waitForPromptChange = useCallback12(() => {
4939
5344
  return new Promise((resolve) => {
4940
5345
  const timeoutMs = 100;
4941
5346
  const timeoutId = setTimeout(() => {
@@ -4967,7 +5372,7 @@ function useAI(options = {}) {
4967
5372
  promptChangeResolvers.current = [];
4968
5373
  }
4969
5374
  }, [enabled, options.prompt, memoizedSuggestions, updatePrompt]);
4970
- const updatePromptRef = useRef12(updatePrompt);
5375
+ const updatePromptRef = useRef13(updatePrompt);
4971
5376
  updatePromptRef.current = updatePrompt;
4972
5377
  useEffect11(() => {
4973
5378
  const id = hookId.current;
@@ -4998,7 +5403,7 @@ function useAI(options = {}) {
4998
5403
  unsubscribe();
4999
5404
  };
5000
5405
  }, [enabled, client]);
5001
- const handleAGUIEvent = useCallback11(async (event) => {
5406
+ const handleAGUIEvent = useCallback12(async (event) => {
5002
5407
  switch (event.type) {
5003
5408
  case EventType.TEXT_MESSAGE_END: {
5004
5409
  const content = client?.currentMessageContent;
@@ -5018,7 +5423,7 @@ function useAI(options = {}) {
5018
5423
  }
5019
5424
  }
5020
5425
  }, [client, options.onError]);
5021
- const generate = useCallback11(async (prompt) => {
5426
+ const generate = useCallback12(async (prompt) => {
5022
5427
  if (!enabled) {
5023
5428
  const error2 = new Error("AI features are disabled");
5024
5429
  setError(error2);
@@ -5054,17 +5459,17 @@ function useAI(options = {}) {
5054
5459
  }
5055
5460
 
5056
5461
  // src/useAIWorkflow.ts
5057
- import { useState as useState13, useCallback as useCallback12, useRef as useRef13, useEffect as useEffect12 } from "react";
5462
+ import { useState as useState15, useCallback as useCallback13, useRef as useRef14, useEffect as useEffect12 } from "react";
5058
5463
  import { EventType as EventType3 } from "@meetsmore-oss/use-ai-core";
5059
5464
  import { v4 as uuidv43 } from "uuid";
5060
5465
  function useAIWorkflow(runner, workflowId) {
5061
5466
  const { connected, client } = useAIContext();
5062
- const [status, setStatus] = useState13("idle");
5063
- const [text, setText] = useState13(null);
5064
- const [error, setError] = useState13(null);
5065
- const currentWorkflowRef = useRef13(null);
5066
- const eventListenerIdRef = useRef13(`useAIWorkflow-${Math.random().toString(36).substr(2, 9)}`);
5067
- const handleWorkflowEvent = useCallback12(async (event) => {
5467
+ const [status, setStatus] = useState15("idle");
5468
+ const [text, setText] = useState15(null);
5469
+ const [error, setError] = useState15(null);
5470
+ const currentWorkflowRef = useRef14(null);
5471
+ const eventListenerIdRef = useRef14(`useAIWorkflow-${Math.random().toString(36).substr(2, 9)}`);
5472
+ const handleWorkflowEvent = useCallback13(async (event) => {
5068
5473
  const currentWorkflow = currentWorkflowRef.current;
5069
5474
  if (!currentWorkflow) return;
5070
5475
  if (event.type === EventType3.RUN_STARTED) {
@@ -5156,7 +5561,7 @@ function useAIWorkflow(runner, workflowId) {
5156
5561
  unsubscribe();
5157
5562
  };
5158
5563
  }, [client, handleWorkflowEvent]);
5159
- const trigger = useCallback12(async (options) => {
5564
+ const trigger = useCallback13(async (options) => {
5160
5565
  if (!client?.isConnected()) {
5161
5566
  const err = new Error("Not connected to server");
5162
5567
  setError(err);
@@ -5232,7 +5637,7 @@ export {
5232
5637
  defaultTheme,
5233
5638
  defineTool,
5234
5639
  executeDefinedTool,
5235
- findTransformer,
5640
+ findTransformerPattern,
5236
5641
  generateChatId,
5237
5642
  generateCommandId,
5238
5643
  generateMessageId,