@meetsmore-oss/use-ai-client 1.5.1 → 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/bundled.js CHANGED
@@ -1254,10 +1254,10 @@ var require_style_to_object = __commonJS({
1254
1254
  });
1255
1255
 
1256
1256
  // src/useAI.ts
1257
- import { useState as useState12, useEffect as useEffect11, useRef as useRef12, useCallback as useCallback11, useMemo as useMemo6 } from "react";
1257
+ import { useState as useState14, useEffect as useEffect11, useRef as useRef13, useCallback as useCallback12, useMemo as useMemo6 } from "react";
1258
1258
 
1259
1259
  // src/providers/useAIProvider.tsx
1260
- import { createContext as createContext4, useContext as useContext4, useState as useState11, useEffect as useEffect10, useCallback as useCallback10, useRef as useRef10 } from "react";
1260
+ import { createContext as createContext4, useContext as useContext4, useState as useState13, useEffect as useEffect10, useCallback as useCallback11, useRef as useRef11 } from "react";
1261
1261
 
1262
1262
  // ../core/dist/index.js
1263
1263
  var __create = Object.create;
@@ -5712,6 +5712,7 @@ var ErrorCode;
5712
5712
  ErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
5713
5713
  ErrorCode2["UNKNOWN_ERROR"] = "UNKNOWN_ERROR";
5714
5714
  })(ErrorCode ||= {});
5715
+ var TOOL_APPROVAL_REQUEST = "TOOL_APPROVAL_REQUEST";
5715
5716
  var export_EventType = import_core.EventType;
5716
5717
 
5717
5718
  // src/theme/strings.ts
@@ -5811,6 +5812,25 @@ var defaultStrings = {
5811
5812
  toolExecution: {
5812
5813
  /** Fallback messages when no tool title is provided (one randomly selected) */
5813
5814
  fallbackMessages: ["Working", "Processing", "Thinking"]
5815
+ },
5816
+ // Tool approval dialog
5817
+ toolApproval: {
5818
+ /** Title shown in the approval dialog */
5819
+ title: "Confirmation Required",
5820
+ /** Message shown in the approval dialog. {toolName} is replaced with tool name. */
5821
+ message: '"{toolName}" is waiting for your approval.',
5822
+ /** Message shown when multiple tools are awaiting approval. {count} is replaced with number. */
5823
+ batchMessage: "{count} actions are waiting for your approval.",
5824
+ /** Label for approve button */
5825
+ approve: "Allow",
5826
+ /** Label for approve all button (batch mode) */
5827
+ approveAll: "Allow All",
5828
+ /** Label for reject button */
5829
+ reject: "Deny",
5830
+ /** Label for reject all button (batch mode) */
5831
+ rejectAll: "Deny All",
5832
+ /** Label for showing tool arguments */
5833
+ showDetails: "Show details"
5814
5834
  }
5815
5835
  };
5816
5836
  var StringsContext = createContext(defaultStrings);
@@ -5957,7 +5977,7 @@ function UseAIFloatingButton({
5957
5977
  }
5958
5978
 
5959
5979
  // src/components/UseAIChatPanel.tsx
5960
- import { useState as useState4, useRef as useRef4, useEffect as useEffect4 } from "react";
5980
+ import { useState as useState5, useRef as useRef4, useEffect as useEffect4 } from "react";
5961
5981
 
5962
5982
  // ../../node_modules/.bun/react-markdown@8.0.7+9cdd050739dc4c16/node_modules/react-markdown/lib/uri-transformer.js
5963
5983
  var protocols = ["http", "https", "mailto", "tel"];
@@ -7840,17 +7860,13 @@ function tokenizeCharacterEscape(effects, ok2, nok) {
7840
7860
  }
7841
7861
  }
7842
7862
 
7843
- // ../../node_modules/.bun/decode-named-character-reference@1.2.0/node_modules/decode-named-character-reference/index.dom.js
7863
+ // ../../node_modules/.bun/decode-named-character-reference@1.3.0/node_modules/decode-named-character-reference/index.dom.js
7844
7864
  var element = document.createElement("i");
7845
7865
  function decodeNamedCharacterReference(value2) {
7846
7866
  const characterReference2 = "&" + value2 + ";";
7847
7867
  element.innerHTML = characterReference2;
7848
7868
  const character = element.textContent;
7849
- if (
7850
- // @ts-expect-error: TypeScript is wrong that `textContent` on elements can
7851
- // yield `null`.
7852
- character.charCodeAt(character.length - 1) === 59 && value2 !== "semi"
7853
- ) {
7869
+ if (character.charCodeAt(character.length - 1) === 59 && value2 !== "semi") {
7854
7870
  return false;
7855
7871
  }
7856
7872
  return character === characterReference2 ? false : character;
@@ -15483,30 +15499,30 @@ function matchesMimeType(mimeType, pattern) {
15483
15499
  const regex = new RegExp(`^${regexPattern}$`);
15484
15500
  return regex.test(mimeType);
15485
15501
  }
15486
- function findTransformer(mimeType, transformers) {
15502
+ function findTransformerPattern(mimeType, transformers) {
15487
15503
  if (!transformers) {
15488
15504
  return void 0;
15489
15505
  }
15490
- let bestMatch;
15506
+ let bestKey;
15491
15507
  let bestIsExact = false;
15492
15508
  let bestLength = -1;
15493
- for (const [pattern, transformer] of Object.entries(transformers)) {
15509
+ for (const pattern of Object.keys(transformers)) {
15494
15510
  if (!matchesMimeType(mimeType, pattern)) {
15495
15511
  continue;
15496
15512
  }
15497
15513
  const isExact = !pattern.includes("*");
15498
15514
  if (isExact && !bestIsExact) {
15499
- bestMatch = transformer;
15515
+ bestKey = pattern;
15500
15516
  bestIsExact = true;
15501
15517
  bestLength = pattern.length;
15502
15518
  continue;
15503
15519
  }
15504
15520
  if (isExact === bestIsExact && pattern.length > bestLength) {
15505
- bestMatch = transformer;
15521
+ bestKey = pattern;
15506
15522
  bestLength = pattern.length;
15507
15523
  }
15508
15524
  }
15509
- return bestMatch;
15525
+ return bestKey;
15510
15526
  }
15511
15527
 
15512
15528
  // src/fileUpload/EmbedFileUploadBackend.ts
@@ -15537,75 +15553,104 @@ var EmbedFileUploadBackend = class {
15537
15553
  };
15538
15554
 
15539
15555
  // src/fileUpload/processAttachments.ts
15556
+ function groupBy(items, keyFn) {
15557
+ const map2 = /* @__PURE__ */ new Map();
15558
+ for (const item of items) {
15559
+ const key = keyFn(item);
15560
+ const list3 = map2.get(key);
15561
+ list3 ? list3.push(item) : map2.set(key, [item]);
15562
+ }
15563
+ return map2;
15564
+ }
15540
15565
  var transformationCache = /* @__PURE__ */ new Map();
15541
15566
  function getFileCacheKey(file2) {
15542
15567
  return `${file2.name}:${file2.size}:${file2.lastModified}`;
15543
15568
  }
15544
- async function getTransformedContent(file2, transformer, context, onProgress) {
15545
- const cacheKey = getFileCacheKey(file2);
15569
+ async function hashGroupCacheKey(files) {
15570
+ const raw = files.map(getFileCacheKey).join(", ");
15571
+ const data = new TextEncoder().encode(raw);
15572
+ const hash2 = await crypto.subtle.digest("SHA-256", data);
15573
+ return Array.from(new Uint8Array(hash2)).map((b) => b.toString(16).padStart(2, "0")).join("");
15574
+ }
15575
+ async function getTransformedContent(files, transformer, context, onProgress) {
15576
+ if (files.length === 0) {
15577
+ return [];
15578
+ }
15579
+ const cacheKey = await hashGroupCacheKey(files);
15546
15580
  const cached2 = transformationCache.get(cacheKey);
15547
- if (cached2 !== void 0) {
15581
+ if (cached2) {
15548
15582
  return cached2;
15549
15583
  }
15550
- const result = await transformer.transform(file2, context, onProgress);
15551
- transformationCache.set(cacheKey, result);
15552
- return result;
15584
+ const results = await transformer.transform(files, context, onProgress);
15585
+ transformationCache.set(cacheKey, results);
15586
+ return results;
15587
+ }
15588
+ async function toContentPart(attachment, backend) {
15589
+ if (attachment.transformedContent !== void 0) {
15590
+ return {
15591
+ type: "transformed_file",
15592
+ text: attachment.transformedContent,
15593
+ originalFile: {
15594
+ name: attachment.file.name,
15595
+ mimeType: attachment.file.type,
15596
+ size: attachment.file.size
15597
+ }
15598
+ };
15599
+ }
15600
+ const url3 = await backend.prepareForSend(attachment.file);
15601
+ if (attachment.file.type.startsWith("image/")) {
15602
+ return { type: "image", url: url3 };
15603
+ }
15604
+ return {
15605
+ type: "file",
15606
+ url: url3,
15607
+ mimeType: attachment.file.type,
15608
+ name: attachment.file.name
15609
+ };
15553
15610
  }
15554
15611
  async function processAttachments(attachments, config2) {
15555
15612
  const { getCurrentChat, backend = new EmbedFileUploadBackend(), transformers = {}, onFileProgress } = config2;
15556
15613
  const contentParts = [];
15557
15614
  const chat = await getCurrentChat();
15558
15615
  const context = { chat };
15559
- for (const attachment of attachments) {
15616
+ const groups = groupBy(
15617
+ attachments,
15618
+ (attachment) => attachment.transformedContent !== void 0 ? null : findTransformerPattern(attachment.file.type, transformers) ?? null
15619
+ );
15620
+ for (const [key, groupAttachments] of groups) {
15621
+ if (key === null) {
15622
+ const parts2 = await Promise.all(
15623
+ groupAttachments.map((a) => toContentPart(a, backend))
15624
+ );
15625
+ contentParts.push(...parts2);
15626
+ continue;
15627
+ }
15628
+ const transformer = transformers[key];
15629
+ const files = groupAttachments.map((a) => a.file);
15630
+ groupAttachments.forEach((a) => onFileProgress?.(a.id, { status: "processing" }));
15560
15631
  try {
15561
- if (attachment.transformedContent !== void 0) {
15562
- contentParts.push({
15563
- type: "transformed_file",
15564
- text: attachment.transformedContent,
15565
- originalFile: {
15566
- name: attachment.file.name,
15567
- mimeType: attachment.file.type,
15568
- size: attachment.file.size
15569
- }
15570
- });
15571
- continue;
15572
- }
15573
- const transformer = findTransformer(attachment.file.type, transformers);
15574
- if (transformer) {
15575
- onFileProgress?.(attachment.id, { status: "processing" });
15576
- const transformedText = await getTransformedContent(
15577
- attachment.file,
15578
- transformer,
15579
- context,
15580
- (progress) => {
15581
- onFileProgress?.(attachment.id, { status: "processing", progress });
15582
- }
15583
- );
15632
+ const results = await getTransformedContent(
15633
+ files,
15634
+ transformer,
15635
+ context,
15636
+ (progress) => {
15637
+ groupAttachments.forEach((a) => onFileProgress?.(a.id, { status: "processing", progress }));
15638
+ }
15639
+ );
15640
+ results.forEach((text4, i) => {
15584
15641
  contentParts.push({
15585
15642
  type: "transformed_file",
15586
- text: transformedText,
15643
+ text: text4,
15587
15644
  originalFile: {
15588
- name: attachment.file.name,
15589
- mimeType: attachment.file.type,
15590
- size: attachment.file.size
15645
+ name: files[i].name,
15646
+ mimeType: files[i].type,
15647
+ size: files[i].size
15591
15648
  }
15592
15649
  });
15593
- onFileProgress?.(attachment.id, { status: "done" });
15594
- } else {
15595
- const url3 = await backend.prepareForSend(attachment.file);
15596
- if (attachment.file.type.startsWith("image/")) {
15597
- contentParts.push({ type: "image", url: url3 });
15598
- } else {
15599
- contentParts.push({
15600
- type: "file",
15601
- url: url3,
15602
- mimeType: attachment.file.type,
15603
- name: attachment.file.name
15604
- });
15605
- }
15606
- }
15650
+ onFileProgress?.(groupAttachments[i].id, { status: "done" });
15651
+ });
15607
15652
  } catch (error48) {
15608
- onFileProgress?.(attachment.id, { status: "error" });
15653
+ groupAttachments.forEach((a) => onFileProgress?.(a.id, { status: "error" }));
15609
15654
  throw error48;
15610
15655
  }
15611
15656
  }
@@ -15727,12 +15772,14 @@ function useFileUpload({
15727
15772
  setFileError(null);
15728
15773
  setProcessingState(/* @__PURE__ */ new Map());
15729
15774
  }, [resetDependency]);
15730
- const runTransformer = useCallback2(async (attachmentId, file2, transformer) => {
15775
+ const runTransformer = useCallback2(async (attachmentId, file2, transformerKey) => {
15776
+ const transformer = transformers?.[transformerKey];
15777
+ if (!transformer) return;
15731
15778
  setProcessingState((prev) => new Map(prev).set(attachmentId, { status: "processing" }));
15732
15779
  try {
15733
15780
  const chat = await getCurrentChat();
15734
15781
  const context = { chat };
15735
- const transformedContent = await getTransformedContent(file2, transformer, context, (progress) => {
15782
+ const [transformedContent] = await getTransformedContent([file2], transformer, context, (progress) => {
15736
15783
  setProcessingState((prev) => new Map(prev).set(attachmentId, {
15737
15784
  status: "processing",
15738
15785
  progress
@@ -15746,7 +15793,7 @@ function useFileUpload({
15746
15793
  console.error(`[useFileUpload] Transformation failed for ${file2.name}:`, error48);
15747
15794
  setProcessingState((prev) => new Map(prev).set(attachmentId, { status: "error" }));
15748
15795
  }
15749
- }, [getCurrentChat]);
15796
+ }, [getCurrentChat, transformers]);
15750
15797
  const handleFiles = useCallback2(async (files) => {
15751
15798
  const fileArray = Array.from(files);
15752
15799
  for (const file2 of fileArray) {
@@ -15768,9 +15815,9 @@ function useFileUpload({
15768
15815
  preview
15769
15816
  };
15770
15817
  setAttachments((prev) => [...prev, attachment]);
15771
- const transformer = findTransformer(file2.type, transformers);
15772
- if (transformer) {
15773
- runTransformer(attachmentId, file2, transformer);
15818
+ const transformerKey = findTransformerPattern(file2.type, transformers);
15819
+ if (transformerKey) {
15820
+ runTransformer(attachmentId, file2, transformerKey);
15774
15821
  }
15775
15822
  }
15776
15823
  }, [maxFileSize, acceptedTypes, strings, transformers, runTransformer]);
@@ -15931,8 +15978,210 @@ function useDropdownState(options = {}) {
15931
15978
  };
15932
15979
  }
15933
15980
 
15981
+ // src/components/ToolApprovalDialog.tsx
15982
+ import { useState as useState4 } from "react";
15983
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
15984
+ function ToolApprovalDialog({
15985
+ toolCallName,
15986
+ toolCallArgs,
15987
+ annotations,
15988
+ toolCount = 1,
15989
+ pendingTools = [],
15990
+ onApprove,
15991
+ onReject,
15992
+ theme,
15993
+ strings
15994
+ }) {
15995
+ const [showDetails, setShowDetails] = useState4(false);
15996
+ const displayName = annotations?.title || toolCallName;
15997
+ const isBatch = toolCount > 1;
15998
+ const message = isBatch ? strings.toolApproval.batchMessage?.replace("{count}", String(toolCount)) ?? `${toolCount} actions are waiting for your approval` : strings.toolApproval.message.replace("{toolName}", displayName);
15999
+ const getToolDisplayName = (tool) => tool.annotations?.title || tool.toolCallName;
16000
+ return /* @__PURE__ */ jsxs7(
16001
+ "div",
16002
+ {
16003
+ "data-testid": "tool-approval-dialog",
16004
+ style: {
16005
+ border: `2px solid ${theme.primaryColor}`,
16006
+ borderRadius: "12px",
16007
+ background: theme.backgroundColor,
16008
+ overflow: "hidden"
16009
+ },
16010
+ children: [
16011
+ /* @__PURE__ */ jsxs7(
16012
+ "div",
16013
+ {
16014
+ style: {
16015
+ padding: "12px 14px",
16016
+ borderBottom: `1px solid ${theme.borderColor}`,
16017
+ background: theme.assistantMessageBackground
16018
+ },
16019
+ children: [
16020
+ /* @__PURE__ */ jsxs7("div", { style: {
16021
+ display: "flex",
16022
+ alignItems: "center",
16023
+ gap: "8px",
16024
+ marginBottom: "4px"
16025
+ }, children: [
16026
+ /* @__PURE__ */ jsxs7("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: theme.primaryColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16027
+ /* @__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" }),
16028
+ /* @__PURE__ */ jsx10("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
16029
+ /* @__PURE__ */ jsx10("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
16030
+ ] }),
16031
+ /* @__PURE__ */ jsx10("span", { style: {
16032
+ fontWeight: 600,
16033
+ fontSize: "14px",
16034
+ color: theme.textColor
16035
+ }, children: strings.toolApproval.title })
16036
+ ] }),
16037
+ /* @__PURE__ */ jsx10("div", { style: {
16038
+ fontSize: "13px",
16039
+ color: theme.secondaryTextColor,
16040
+ paddingLeft: "24px"
16041
+ }, children: message })
16042
+ ]
16043
+ }
16044
+ ),
16045
+ /* @__PURE__ */ jsxs7("div", { style: { padding: "8px 14px" }, children: [
16046
+ /* @__PURE__ */ jsxs7(
16047
+ "button",
16048
+ {
16049
+ onClick: () => setShowDetails(!showDetails),
16050
+ style: {
16051
+ background: "transparent",
16052
+ border: "none",
16053
+ padding: 0,
16054
+ cursor: "pointer",
16055
+ fontSize: "12px",
16056
+ color: theme.secondaryTextColor,
16057
+ display: "flex",
16058
+ alignItems: "center",
16059
+ gap: "4px"
16060
+ },
16061
+ children: [
16062
+ /* @__PURE__ */ jsx10(
16063
+ "svg",
16064
+ {
16065
+ width: "10",
16066
+ height: "10",
16067
+ viewBox: "0 0 12 12",
16068
+ fill: "none",
16069
+ style: {
16070
+ transform: showDetails ? "rotate(90deg)" : "rotate(0deg)",
16071
+ transition: "transform 0.15s"
16072
+ },
16073
+ children: /* @__PURE__ */ jsx10("path", { d: "M4 2L8 6L4 10", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
16074
+ }
16075
+ ),
16076
+ strings.toolApproval.showDetails
16077
+ ]
16078
+ }
16079
+ ),
16080
+ showDetails && /* @__PURE__ */ jsx10("div", { style: {
16081
+ marginTop: "6px",
16082
+ display: "flex",
16083
+ flexDirection: "column",
16084
+ gap: "8px",
16085
+ maxHeight: "200px",
16086
+ overflow: "auto"
16087
+ }, children: (pendingTools.length > 0 ? pendingTools : [{
16088
+ toolCallId: "single",
16089
+ toolCallName,
16090
+ toolCallArgs,
16091
+ annotations
16092
+ }]).map((tool, index2) => /* @__PURE__ */ jsxs7(
16093
+ "div",
16094
+ {
16095
+ style: {
16096
+ padding: "8px",
16097
+ background: theme.hoverBackground,
16098
+ borderRadius: "6px"
16099
+ },
16100
+ children: [
16101
+ /* @__PURE__ */ jsx10("div", { style: {
16102
+ fontSize: "12px",
16103
+ fontWeight: 500,
16104
+ color: theme.textColor,
16105
+ marginBottom: "4px"
16106
+ }, children: getToolDisplayName(tool) }),
16107
+ /* @__PURE__ */ jsx10("pre", { style: {
16108
+ margin: 0,
16109
+ fontSize: "11px",
16110
+ overflow: "auto",
16111
+ color: theme.secondaryTextColor,
16112
+ whiteSpace: "pre-wrap",
16113
+ wordBreak: "break-word"
16114
+ }, children: JSON.stringify(tool.toolCallArgs, null, 2) })
16115
+ ]
16116
+ },
16117
+ tool.toolCallId
16118
+ )) })
16119
+ ] }),
16120
+ /* @__PURE__ */ jsxs7("div", { style: {
16121
+ display: "flex",
16122
+ gap: "8px",
16123
+ padding: "8px 14px 12px"
16124
+ }, children: [
16125
+ /* @__PURE__ */ jsx10(
16126
+ "button",
16127
+ {
16128
+ "data-testid": "approve-tool-button",
16129
+ onClick: onApprove,
16130
+ style: {
16131
+ flex: 1,
16132
+ padding: "8px 16px",
16133
+ borderRadius: "8px",
16134
+ border: "none",
16135
+ background: theme.primaryGradient,
16136
+ color: "white",
16137
+ fontWeight: 500,
16138
+ cursor: "pointer",
16139
+ fontSize: "13px",
16140
+ transition: "opacity 0.15s"
16141
+ },
16142
+ onMouseEnter: (e) => {
16143
+ e.currentTarget.style.opacity = "0.9";
16144
+ },
16145
+ onMouseLeave: (e) => {
16146
+ e.currentTarget.style.opacity = "1";
16147
+ },
16148
+ children: isBatch ? strings.toolApproval.approveAll ?? "Approve All" : strings.toolApproval.approve
16149
+ }
16150
+ ),
16151
+ /* @__PURE__ */ jsx10(
16152
+ "button",
16153
+ {
16154
+ "data-testid": "reject-tool-button",
16155
+ onClick: () => onReject(),
16156
+ style: {
16157
+ flex: 1,
16158
+ padding: "8px 16px",
16159
+ borderRadius: "8px",
16160
+ border: `1px solid ${theme.borderColor}`,
16161
+ background: "transparent",
16162
+ color: theme.textColor,
16163
+ fontWeight: 500,
16164
+ cursor: "pointer",
16165
+ fontSize: "13px",
16166
+ transition: "all 0.15s"
16167
+ },
16168
+ onMouseEnter: (e) => {
16169
+ e.currentTarget.style.background = theme.hoverBackground;
16170
+ },
16171
+ onMouseLeave: (e) => {
16172
+ e.currentTarget.style.background = "transparent";
16173
+ },
16174
+ children: isBatch ? strings.toolApproval.rejectAll ?? "Reject All" : strings.toolApproval.reject
16175
+ }
16176
+ )
16177
+ ] })
16178
+ ]
16179
+ }
16180
+ );
16181
+ }
16182
+
15934
16183
  // src/components/UseAIChatPanel.tsx
15935
- import { Fragment, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
16184
+ import { Fragment, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
15936
16185
  function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedColor }) {
15937
16186
  const buttonRef = useRef4(null);
15938
16187
  const handleClick = () => {
@@ -15948,7 +16197,7 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
15948
16197
  };
15949
16198
  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";
15950
16199
  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";
15951
- return /* @__PURE__ */ jsx10(
16200
+ return /* @__PURE__ */ jsx11(
15952
16201
  "button",
15953
16202
  {
15954
16203
  ref: buttonRef,
@@ -15981,7 +16230,7 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
15981
16230
  e.currentTarget.style.color = unselectedColor;
15982
16231
  }
15983
16232
  },
15984
- children: /* @__PURE__ */ jsx10(
16233
+ children: /* @__PURE__ */ jsx11(
15985
16234
  "svg",
15986
16235
  {
15987
16236
  width: "14",
@@ -15992,7 +16241,7 @@ function FeedbackButton({ type, isSelected, onClick, selectedColor, unselectedCo
15992
16241
  strokeWidth: "2",
15993
16242
  strokeLinecap: "round",
15994
16243
  strokeLinejoin: "round",
15995
- children: /* @__PURE__ */ jsx10("path", { d: type === "upvote" ? thumbsUpPath : thumbsDownPath })
16244
+ children: /* @__PURE__ */ jsx11("path", { d: type === "upvote" ? thumbsUpPath : thumbsDownPath })
15996
16245
  }
15997
16246
  )
15998
16247
  }
@@ -16033,18 +16282,21 @@ function UseAIChatPanel({
16033
16282
  closeButton,
16034
16283
  executingTool,
16035
16284
  feedbackEnabled,
16036
- onFeedback
16285
+ onFeedback,
16286
+ pendingApprovals = [],
16287
+ onApproveToolCall,
16288
+ onRejectToolCall
16037
16289
  }) {
16038
16290
  const strings = useStrings();
16039
16291
  const theme = useTheme();
16040
- const [input, setInput] = useState4("");
16292
+ const [input, setInput] = useState5("");
16041
16293
  const chatHistoryDropdown = useDropdownState();
16042
16294
  const agentDropdown = useDropdownState();
16043
- const [chatHistory, setChatHistory] = useState4([]);
16295
+ const [chatHistory, setChatHistory] = useState5([]);
16044
16296
  const messagesEndRef = useRef4(null);
16045
- const [displayedSuggestions, setDisplayedSuggestions] = useState4([]);
16297
+ const [displayedSuggestions, setDisplayedSuggestions] = useState5([]);
16046
16298
  const textareaRef = useRef4(null);
16047
- const [hoveredMessageId, setHoveredMessageId] = useState4(null);
16299
+ const [hoveredMessageId, setHoveredMessageId] = useState5(null);
16048
16300
  const {
16049
16301
  attachments,
16050
16302
  fileError,
@@ -16131,7 +16383,7 @@ function UseAIChatPanel({
16131
16383
  chatHistoryDropdown.close();
16132
16384
  }
16133
16385
  };
16134
- return /* @__PURE__ */ jsxs7(
16386
+ return /* @__PURE__ */ jsxs8(
16135
16387
  "div",
16136
16388
  {
16137
16389
  onClick: () => {
@@ -16149,7 +16401,7 @@ function UseAIChatPanel({
16149
16401
  },
16150
16402
  children: [
16151
16403
  DropZoneOverlay,
16152
- /* @__PURE__ */ jsxs7(
16404
+ /* @__PURE__ */ jsxs8(
16153
16405
  "div",
16154
16406
  {
16155
16407
  style: {
@@ -16162,7 +16414,7 @@ function UseAIChatPanel({
16162
16414
  gap: "12px"
16163
16415
  },
16164
16416
  children: [
16165
- /* @__PURE__ */ jsx10("div", { style: { flex: 1, minWidth: 0, position: "relative" }, children: onListChats ? /* @__PURE__ */ jsxs7(
16417
+ /* @__PURE__ */ jsx11("div", { style: { flex: 1, minWidth: 0, position: "relative" }, children: onListChats ? /* @__PURE__ */ jsxs8(
16166
16418
  "button",
16167
16419
  {
16168
16420
  "data-testid": "chat-history-dropdown-button",
@@ -16195,7 +16447,7 @@ function UseAIChatPanel({
16195
16447
  e.currentTarget.style.background = "transparent";
16196
16448
  },
16197
16449
  children: [
16198
- /* @__PURE__ */ jsx10("span", { style: {
16450
+ /* @__PURE__ */ jsx11("span", { style: {
16199
16451
  overflow: "hidden",
16200
16452
  textOverflow: "ellipsis",
16201
16453
  whiteSpace: "nowrap",
@@ -16212,13 +16464,13 @@ function UseAIChatPanel({
16212
16464
  }
16213
16465
  return strings.header.newChat;
16214
16466
  })() }),
16215
- /* @__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" }) })
16467
+ /* @__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" }) })
16216
16468
  ]
16217
16469
  }
16218
- ) : /* @__PURE__ */ jsx10("div", { style: { fontSize: "14px", fontWeight: "600", color: theme.textColor, padding: "6px 8px" }, children: strings.header.aiAssistant }) }),
16219
- /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
16220
- availableAgents && availableAgents.length > 1 && onAgentChange && /* @__PURE__ */ jsxs7("div", { style: { position: "relative" }, children: [
16221
- /* @__PURE__ */ jsxs7(
16470
+ ) : /* @__PURE__ */ jsx11("div", { style: { fontSize: "14px", fontWeight: "600", color: theme.textColor, padding: "6px 8px" }, children: strings.header.aiAssistant }) }),
16471
+ /* @__PURE__ */ jsxs8("div", { style: { display: "flex", alignItems: "center", gap: "4px" }, children: [
16472
+ availableAgents && availableAgents.length > 1 && onAgentChange && /* @__PURE__ */ jsxs8("div", { style: { position: "relative" }, children: [
16473
+ /* @__PURE__ */ jsxs8(
16222
16474
  "button",
16223
16475
  {
16224
16476
  "data-testid": "agent-selector",
@@ -16247,7 +16499,7 @@ function UseAIChatPanel({
16247
16499
  },
16248
16500
  title: "Select AI model",
16249
16501
  children: [
16250
- /* @__PURE__ */ jsx10("span", { style: {
16502
+ /* @__PURE__ */ jsx11("span", { style: {
16251
16503
  overflow: "hidden",
16252
16504
  textOverflow: "ellipsis",
16253
16505
  whiteSpace: "nowrap",
@@ -16256,11 +16508,11 @@ function UseAIChatPanel({
16256
16508
  const agent = availableAgents.find((a) => a.id === (selectedAgent ?? defaultAgent));
16257
16509
  return agent?.name || "AI";
16258
16510
  })() }),
16259
- /* @__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" }) })
16511
+ /* @__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" }) })
16260
16512
  ]
16261
16513
  }
16262
16514
  ),
16263
- agentDropdown.isOpen && /* @__PURE__ */ jsx10(
16515
+ agentDropdown.isOpen && /* @__PURE__ */ jsx11(
16264
16516
  "div",
16265
16517
  {
16266
16518
  style: {
@@ -16280,7 +16532,7 @@ function UseAIChatPanel({
16280
16532
  },
16281
16533
  children: availableAgents.map((agent) => {
16282
16534
  const isSelected = agent.id === (selectedAgent ?? defaultAgent);
16283
- return /* @__PURE__ */ jsxs7(
16535
+ return /* @__PURE__ */ jsxs8(
16284
16536
  "div",
16285
16537
  {
16286
16538
  "data-testid": "agent-option",
@@ -16310,13 +16562,13 @@ function UseAIChatPanel({
16310
16562
  }
16311
16563
  },
16312
16564
  children: [
16313
- /* @__PURE__ */ jsxs7("div", { style: { flex: 1, minWidth: 0 }, children: [
16314
- /* @__PURE__ */ jsx10("div", { style: {
16565
+ /* @__PURE__ */ jsxs8("div", { style: { flex: 1, minWidth: 0 }, children: [
16566
+ /* @__PURE__ */ jsx11("div", { style: {
16315
16567
  fontSize: "13px",
16316
16568
  fontWeight: isSelected ? "600" : "500",
16317
16569
  color: isSelected ? theme.primaryColor : theme.textColor
16318
16570
  }, children: agent.name }),
16319
- agent.annotation && /* @__PURE__ */ jsx10("div", { style: {
16571
+ agent.annotation && /* @__PURE__ */ jsx11("div", { style: {
16320
16572
  fontSize: "11px",
16321
16573
  color: theme.secondaryTextColor,
16322
16574
  marginTop: "2px",
@@ -16325,7 +16577,7 @@ function UseAIChatPanel({
16325
16577
  whiteSpace: "nowrap"
16326
16578
  }, children: agent.annotation })
16327
16579
  ] }),
16328
- 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" }) })
16580
+ 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" }) })
16329
16581
  ]
16330
16582
  },
16331
16583
  agent.id
@@ -16334,7 +16586,7 @@ function UseAIChatPanel({
16334
16586
  }
16335
16587
  )
16336
16588
  ] }),
16337
- onNewChat && /* @__PURE__ */ jsx10(
16589
+ onNewChat && /* @__PURE__ */ jsx11(
16338
16590
  "button",
16339
16591
  {
16340
16592
  "data-testid": "new-chat-button",
@@ -16361,10 +16613,10 @@ function UseAIChatPanel({
16361
16613
  e.currentTarget.style.color = theme.secondaryTextColor;
16362
16614
  },
16363
16615
  title: strings.header.newChat,
16364
- 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" }) })
16616
+ 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" }) })
16365
16617
  }
16366
16618
  ),
16367
- onDeleteChat && messages.length > 0 && /* @__PURE__ */ jsx10(
16619
+ onDeleteChat && messages.length > 0 && /* @__PURE__ */ jsx11(
16368
16620
  "button",
16369
16621
  {
16370
16622
  "data-testid": "delete-chat-button",
@@ -16388,7 +16640,7 @@ function UseAIChatPanel({
16388
16640
  e.currentTarget.style.color = theme.secondaryTextColor;
16389
16641
  },
16390
16642
  title: strings.header.deleteChat,
16391
- 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" }) })
16643
+ 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" }) })
16392
16644
  }
16393
16645
  ),
16394
16646
  closeButton
@@ -16396,7 +16648,7 @@ function UseAIChatPanel({
16396
16648
  ]
16397
16649
  }
16398
16650
  ),
16399
- chatHistoryDropdown.isOpen && onListChats && /* @__PURE__ */ jsx10(
16651
+ chatHistoryDropdown.isOpen && onListChats && /* @__PURE__ */ jsx11(
16400
16652
  "div",
16401
16653
  {
16402
16654
  style: {
@@ -16413,7 +16665,7 @@ function UseAIChatPanel({
16413
16665
  flexDirection: "column",
16414
16666
  overflow: "hidden"
16415
16667
  },
16416
- children: /* @__PURE__ */ jsx10(
16668
+ children: /* @__PURE__ */ jsx11(
16417
16669
  "div",
16418
16670
  {
16419
16671
  style: {
@@ -16421,7 +16673,7 @@ function UseAIChatPanel({
16421
16673
  overflowY: "auto",
16422
16674
  padding: "8px"
16423
16675
  },
16424
- children: chatHistory.length === 0 ? /* @__PURE__ */ jsx10(
16676
+ children: chatHistory.length === 0 ? /* @__PURE__ */ jsx11(
16425
16677
  "div",
16426
16678
  {
16427
16679
  style: {
@@ -16430,9 +16682,9 @@ function UseAIChatPanel({
16430
16682
  padding: "32px 16px",
16431
16683
  fontSize: "13px"
16432
16684
  },
16433
- children: /* @__PURE__ */ jsx10("p", { style: { margin: 0 }, children: strings.chatHistory.noChatHistory })
16685
+ children: /* @__PURE__ */ jsx11("p", { style: { margin: 0 }, children: strings.chatHistory.noChatHistory })
16434
16686
  }
16435
- ) : chatHistory.map((chat) => /* @__PURE__ */ jsxs7(
16687
+ ) : chatHistory.map((chat) => /* @__PURE__ */ jsxs8(
16436
16688
  "div",
16437
16689
  {
16438
16690
  "data-testid": "chat-history-item",
@@ -16456,10 +16708,10 @@ function UseAIChatPanel({
16456
16708
  }
16457
16709
  },
16458
16710
  children: [
16459
- /* @__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 }),
16460
- /* @__PURE__ */ jsxs7("div", { style: { fontSize: "11px", color: theme.secondaryTextColor }, children: [
16711
+ /* @__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 }),
16712
+ /* @__PURE__ */ jsxs8("div", { style: { fontSize: "11px", color: theme.secondaryTextColor }, children: [
16461
16713
  new Date(chat.updatedAt).toLocaleDateString([], { month: "short", day: "numeric" }),
16462
- currentChatId === chat.id && /* @__PURE__ */ jsxs7("span", { style: {
16714
+ currentChatId === chat.id && /* @__PURE__ */ jsxs8("span", { style: {
16463
16715
  marginLeft: "8px",
16464
16716
  color: theme.primaryColor,
16465
16717
  fontWeight: "600"
@@ -16478,7 +16730,7 @@ function UseAIChatPanel({
16478
16730
  ),
16479
16731
  chatHistoryDropdown.Backdrop,
16480
16732
  agentDropdown.Backdrop,
16481
- /* @__PURE__ */ jsxs7(
16733
+ /* @__PURE__ */ jsxs8(
16482
16734
  "div",
16483
16735
  {
16484
16736
  style: {
@@ -16490,7 +16742,7 @@ function UseAIChatPanel({
16490
16742
  gap: "12px"
16491
16743
  },
16492
16744
  children: [
16493
- messages.length === 0 && /* @__PURE__ */ jsxs7(
16745
+ messages.length === 0 && /* @__PURE__ */ jsxs8(
16494
16746
  "div",
16495
16747
  {
16496
16748
  style: {
@@ -16501,12 +16753,12 @@ function UseAIChatPanel({
16501
16753
  gap: "20px"
16502
16754
  },
16503
16755
  children: [
16504
- /* @__PURE__ */ jsxs7("div", { style: { textAlign: "center", color: theme.secondaryTextColor, fontSize: "14px" }, children: [
16505
- /* @__PURE__ */ jsx10("p", { style: { margin: 0, fontSize: "32px", marginBottom: "12px" }, children: "\u{1F4AC}" }),
16506
- /* @__PURE__ */ jsx10("p", { style: { margin: 0 }, children: strings.emptyChat.startConversation }),
16507
- /* @__PURE__ */ jsx10("p", { style: { margin: "8px 0 0", fontSize: "12px" }, children: strings.emptyChat.askMeToHelp })
16756
+ /* @__PURE__ */ jsxs8("div", { style: { textAlign: "center", color: theme.secondaryTextColor, fontSize: "14px" }, children: [
16757
+ /* @__PURE__ */ jsx11("p", { style: { margin: 0, fontSize: "32px", marginBottom: "12px" }, children: "\u{1F4AC}" }),
16758
+ /* @__PURE__ */ jsx11("p", { style: { margin: 0 }, children: strings.emptyChat.startConversation }),
16759
+ /* @__PURE__ */ jsx11("p", { style: { margin: "8px 0 0", fontSize: "12px" }, children: strings.emptyChat.askMeToHelp })
16508
16760
  ] }),
16509
- displayedSuggestions.length > 0 && /* @__PURE__ */ jsx10(
16761
+ displayedSuggestions.length > 0 && /* @__PURE__ */ jsx11(
16510
16762
  "div",
16511
16763
  {
16512
16764
  style: {
@@ -16516,7 +16768,7 @@ function UseAIChatPanel({
16516
16768
  width: "100%",
16517
16769
  maxWidth: "320px"
16518
16770
  },
16519
- children: displayedSuggestions.map((suggestion, index2) => /* @__PURE__ */ jsx10(
16771
+ children: displayedSuggestions.map((suggestion, index2) => /* @__PURE__ */ jsx11(
16520
16772
  "button",
16521
16773
  {
16522
16774
  "data-testid": "chat-suggestion-button",
@@ -16560,7 +16812,7 @@ function UseAIChatPanel({
16560
16812
  ]
16561
16813
  }
16562
16814
  ),
16563
- messages.map((message) => /* @__PURE__ */ jsxs7(
16815
+ messages.map((message) => /* @__PURE__ */ jsxs8(
16564
16816
  "div",
16565
16817
  {
16566
16818
  "data-testid": `chat-message-${message.role}`,
@@ -16573,7 +16825,7 @@ function UseAIChatPanel({
16573
16825
  onMouseEnter: () => message.role === "user" && setHoveredMessageId(message.id),
16574
16826
  onMouseLeave: () => setHoveredMessageId(null),
16575
16827
  children: [
16576
- /* @__PURE__ */ jsxs7(
16828
+ /* @__PURE__ */ jsxs8(
16577
16829
  "div",
16578
16830
  {
16579
16831
  style: {
@@ -16581,7 +16833,7 @@ function UseAIChatPanel({
16581
16833
  maxWidth: "80%"
16582
16834
  },
16583
16835
  children: [
16584
- message.role === "user" && hoveredMessageId === message.id && onSaveCommand && !slashCommands.isSavingCommand(message.id) && /* @__PURE__ */ jsx10(
16836
+ message.role === "user" && hoveredMessageId === message.id && onSaveCommand && !slashCommands.isSavingCommand(message.id) && /* @__PURE__ */ jsx11(
16585
16837
  "button",
16586
16838
  {
16587
16839
  "data-testid": "save-command-button",
@@ -16617,14 +16869,14 @@ function UseAIChatPanel({
16617
16869
  e.currentTarget.style.transform = "scale(1)";
16618
16870
  e.currentTarget.style.boxShadow = "0 2px 6px rgba(0, 0, 0, 0.15)";
16619
16871
  },
16620
- children: /* @__PURE__ */ jsxs7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16621
- /* @__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" }),
16622
- /* @__PURE__ */ jsx10("polyline", { points: "17 21 17 13 7 13 7 21" }),
16623
- /* @__PURE__ */ jsx10("polyline", { points: "7 3 7 8 15 8" })
16872
+ children: /* @__PURE__ */ jsxs8("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16873
+ /* @__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" }),
16874
+ /* @__PURE__ */ jsx11("polyline", { points: "17 21 17 13 7 13 7 21" }),
16875
+ /* @__PURE__ */ jsx11("polyline", { points: "7 3 7 8 15 8" })
16624
16876
  ] })
16625
16877
  }
16626
16878
  ),
16627
- /* @__PURE__ */ jsxs7(
16879
+ /* @__PURE__ */ jsxs8(
16628
16880
  "div",
16629
16881
  {
16630
16882
  "data-testid": "chat-message-content",
@@ -16639,7 +16891,7 @@ function UseAIChatPanel({
16639
16891
  wordWrap: "break-word"
16640
16892
  },
16641
16893
  children: [
16642
- 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(
16894
+ 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(
16643
16895
  FilePlaceholder,
16644
16896
  {
16645
16897
  name: part.file.name,
@@ -16647,7 +16899,7 @@ function UseAIChatPanel({
16647
16899
  },
16648
16900
  idx
16649
16901
  )) }),
16650
- message.role === "assistant" ? /* @__PURE__ */ jsx10(MarkdownContent, { content: getTextContent(message.content) }) : getTextContent(message.content)
16902
+ message.role === "assistant" ? /* @__PURE__ */ jsx11(MarkdownContent, { content: getTextContent(message.content) }) : getTextContent(message.content)
16651
16903
  ]
16652
16904
  }
16653
16905
  ),
@@ -16658,7 +16910,7 @@ function UseAIChatPanel({
16658
16910
  ]
16659
16911
  }
16660
16912
  ),
16661
- message.role === "assistant" && message.traceId && feedbackEnabled && onFeedback && /* @__PURE__ */ jsxs7(
16913
+ message.role === "assistant" && message.traceId && feedbackEnabled && onFeedback && /* @__PURE__ */ jsxs8(
16662
16914
  "div",
16663
16915
  {
16664
16916
  "data-testid": "feedback-buttons",
@@ -16669,7 +16921,7 @@ function UseAIChatPanel({
16669
16921
  padding: "0 4px"
16670
16922
  },
16671
16923
  children: [
16672
- /* @__PURE__ */ jsx10(
16924
+ /* @__PURE__ */ jsx11(
16673
16925
  FeedbackButton,
16674
16926
  {
16675
16927
  type: "upvote",
@@ -16682,7 +16934,7 @@ function UseAIChatPanel({
16682
16934
  unselectedColor: theme.secondaryTextColor
16683
16935
  }
16684
16936
  ),
16685
- /* @__PURE__ */ jsx10(
16937
+ /* @__PURE__ */ jsx11(
16686
16938
  FeedbackButton,
16687
16939
  {
16688
16940
  type: "downvote",
@@ -16698,7 +16950,7 @@ function UseAIChatPanel({
16698
16950
  ]
16699
16951
  }
16700
16952
  ),
16701
- /* @__PURE__ */ jsx10(
16953
+ /* @__PURE__ */ jsx11(
16702
16954
  "div",
16703
16955
  {
16704
16956
  style: {
@@ -16717,14 +16969,14 @@ function UseAIChatPanel({
16717
16969
  },
16718
16970
  message.id
16719
16971
  )),
16720
- loading && /* @__PURE__ */ jsx10(
16972
+ loading && /* @__PURE__ */ jsx11(
16721
16973
  "div",
16722
16974
  {
16723
16975
  style: {
16724
16976
  display: "flex",
16725
16977
  alignItems: "flex-start"
16726
16978
  },
16727
- children: /* @__PURE__ */ jsx10(
16979
+ children: /* @__PURE__ */ jsx11(
16728
16980
  "div",
16729
16981
  {
16730
16982
  className: "markdown-content",
@@ -16737,20 +16989,20 @@ function UseAIChatPanel({
16737
16989
  color: theme.textColor,
16738
16990
  maxWidth: "80%"
16739
16991
  },
16740
- children: streamingText ? /* @__PURE__ */ jsx10(MarkdownContent, { content: streamingText }) : fileProcessing && fileProcessing.status === "processing" ? /* @__PURE__ */ jsxs7("div", { children: [
16741
- /* @__PURE__ */ jsx10("span", { style: { opacity: 0.6 }, children: strings.input.processingFile }),
16742
- fileProcessing.progress != null && /* @__PURE__ */ jsxs7(Fragment, { children: [
16743
- /* @__PURE__ */ jsxs7("span", { style: { opacity: 0.6, marginLeft: "4px" }, children: [
16992
+ children: streamingText ? /* @__PURE__ */ jsx11(MarkdownContent, { content: streamingText }) : fileProcessing && fileProcessing.status === "processing" ? /* @__PURE__ */ jsxs8("div", { children: [
16993
+ /* @__PURE__ */ jsx11("span", { style: { opacity: 0.6 }, children: strings.input.processingFile }),
16994
+ fileProcessing.progress != null && /* @__PURE__ */ jsxs8(Fragment, { children: [
16995
+ /* @__PURE__ */ jsxs8("span", { style: { opacity: 0.6, marginLeft: "4px" }, children: [
16744
16996
  Math.round(fileProcessing.progress),
16745
16997
  "%"
16746
16998
  ] }),
16747
- /* @__PURE__ */ jsx10("div", { style: {
16999
+ /* @__PURE__ */ jsx11("div", { style: {
16748
17000
  marginTop: "6px",
16749
17001
  height: "4px",
16750
17002
  borderRadius: "2px",
16751
17003
  background: theme.borderColor,
16752
17004
  overflow: "hidden"
16753
- }, children: /* @__PURE__ */ jsx10("div", { style: {
17005
+ }, children: /* @__PURE__ */ jsx11("div", { style: {
16754
17006
  height: "100%",
16755
17007
  width: `${fileProcessing.progress}%`,
16756
17008
  borderRadius: "2px",
@@ -16758,17 +17010,17 @@ function UseAIChatPanel({
16758
17010
  transition: "width 0.3s ease"
16759
17011
  } }) })
16760
17012
  ] }),
16761
- fileProcessing.progress == null && /* @__PURE__ */ jsx10("span", { className: "dots", style: { marginLeft: "4px" }, children: "..." })
16762
- ] }) : /* @__PURE__ */ jsx10("span", { className: "dots", style: { opacity: 0.6 }, children: "..." })
17013
+ fileProcessing.progress == null && /* @__PURE__ */ jsx11("span", { className: "dots", style: { marginLeft: "4px" }, children: "..." })
17014
+ ] }) : /* @__PURE__ */ jsx11("span", { className: "dots", style: { opacity: 0.6 }, children: "..." })
16763
17015
  }
16764
17016
  )
16765
17017
  }
16766
17018
  ),
16767
- /* @__PURE__ */ jsx10("div", { ref: messagesEndRef })
17019
+ /* @__PURE__ */ jsx11("div", { ref: messagesEndRef })
16768
17020
  ]
16769
17021
  }
16770
17022
  ),
16771
- /* @__PURE__ */ jsxs7(
17023
+ /* @__PURE__ */ jsxs8(
16772
17024
  "div",
16773
17025
  {
16774
17026
  style: {
@@ -16776,7 +17028,7 @@ function UseAIChatPanel({
16776
17028
  borderTop: `1px solid ${theme.borderColor}`
16777
17029
  },
16778
17030
  children: [
16779
- fileError && /* @__PURE__ */ jsx10(
17031
+ fileError && /* @__PURE__ */ jsx11(
16780
17032
  "div",
16781
17033
  {
16782
17034
  "data-testid": "file-error",
@@ -16791,7 +17043,7 @@ function UseAIChatPanel({
16791
17043
  children: fileError
16792
17044
  }
16793
17045
  ),
16794
- attachments.length > 0 && /* @__PURE__ */ jsx10(
17046
+ attachments.length > 0 && /* @__PURE__ */ jsx11(
16795
17047
  "div",
16796
17048
  {
16797
17049
  "data-testid": "file-attachments",
@@ -16801,7 +17053,7 @@ function UseAIChatPanel({
16801
17053
  gap: "8px",
16802
17054
  marginBottom: "8px"
16803
17055
  },
16804
- children: attachments.map((attachment) => /* @__PURE__ */ jsx10(
17056
+ children: attachments.map((attachment) => /* @__PURE__ */ jsx11(
16805
17057
  FileChip,
16806
17058
  {
16807
17059
  attachment,
@@ -16813,143 +17065,159 @@ function UseAIChatPanel({
16813
17065
  ))
16814
17066
  }
16815
17067
  ),
16816
- /* @__PURE__ */ jsxs7(
16817
- "div",
17068
+ /* @__PURE__ */ jsx11(
17069
+ "input",
16818
17070
  {
16819
- style: {
16820
- border: `1px solid ${theme.borderColor}`,
16821
- borderRadius: "12px",
16822
- background: theme.backgroundColor,
16823
- overflow: "hidden",
16824
- position: "relative"
16825
- },
16826
- children: [
16827
- slashCommands.AutocompleteComponent,
16828
- /* @__PURE__ */ jsx10(
16829
- "input",
16830
- {
16831
- ref: fileInputRef,
16832
- type: "file",
16833
- multiple: true,
16834
- "data-testid": "file-input",
16835
- style: { display: "none" },
16836
- onChange: handleFileInputChange,
16837
- accept: acceptedTypes?.join(",")
16838
- }
16839
- ),
16840
- /* @__PURE__ */ jsx10(
16841
- "textarea",
16842
- {
16843
- ref: textareaRef,
16844
- "data-testid": "chat-input",
16845
- className: "chat-input",
16846
- value: input,
16847
- onChange: handleInputChange,
16848
- onKeyDown: handleKeyDown,
16849
- placeholder: !connected ? strings.input.connectingPlaceholder : loading ? `${executingTool?.displayText ?? strings.input.thinking}...` : strings.input.placeholder,
16850
- disabled: !connected || loading,
16851
- rows: 1,
16852
- style: {
16853
- width: "100%",
16854
- padding: "10px 14px 6px",
16855
- border: "none",
16856
- fontSize: "14px",
16857
- lineHeight: "1.4",
16858
- resize: "none",
16859
- maxHeight: `${maxTextareaHeight}px`,
16860
- fontFamily: "inherit",
16861
- outline: "none",
16862
- background: "transparent",
16863
- overflowY: "auto",
16864
- boxSizing: "border-box"
16865
- }
16866
- }
16867
- ),
16868
- /* @__PURE__ */ jsxs7(
16869
- "div",
16870
- {
16871
- style: {
16872
- display: "flex",
16873
- alignItems: "center",
16874
- justifyContent: "space-between",
16875
- padding: "4px 8px"
16876
- },
16877
- children: [
16878
- /* @__PURE__ */ jsx10("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: fileUploadEnabled && /* @__PURE__ */ jsx10(
16879
- "button",
16880
- {
16881
- "data-testid": "file-picker-button",
16882
- onClick: openFilePicker,
16883
- disabled: !connected || loading,
16884
- style: {
16885
- padding: "4px",
16886
- background: "transparent",
16887
- border: `1px solid ${theme.borderColor}`,
16888
- borderRadius: "50%",
16889
- cursor: connected && !loading ? "pointer" : "not-allowed",
16890
- color: theme.secondaryTextColor,
16891
- display: "flex",
16892
- alignItems: "center",
16893
- justifyContent: "center",
16894
- width: "28px",
16895
- height: "28px",
16896
- transition: "all 0.15s",
16897
- opacity: connected && !loading ? 1 : 0.5
16898
- },
16899
- onMouseEnter: (e) => {
16900
- if (connected && !loading) {
16901
- e.currentTarget.style.color = theme.primaryColor;
16902
- e.currentTarget.style.borderColor = theme.primaryColor;
16903
- }
16904
- },
16905
- onMouseLeave: (e) => {
16906
- e.currentTarget.style.color = theme.secondaryTextColor;
16907
- e.currentTarget.style.borderColor = theme.borderColor;
16908
- },
16909
- title: strings.fileUpload.attachFiles,
16910
- 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: [
16911
- /* @__PURE__ */ jsx10("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
16912
- /* @__PURE__ */ jsx10("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
16913
- ] })
16914
- }
16915
- ) }),
16916
- /* @__PURE__ */ jsx10(
16917
- "button",
16918
- {
16919
- "data-testid": "chat-send-button",
16920
- className: "chat-send-button",
16921
- onClick: handleSend,
16922
- disabled: !connected || loading || !input.trim() && attachments.length === 0,
16923
- style: {
16924
- padding: "6px",
16925
- background: connected && !loading && (input.trim() || attachments.length > 0) ? theme.primaryGradient : theme.buttonDisabledBackground,
16926
- color: connected && !loading && (input.trim() || attachments.length > 0) ? "white" : theme.secondaryTextColor,
16927
- border: "none",
16928
- borderRadius: "50%",
16929
- cursor: connected && !loading && (input.trim() || attachments.length > 0) ? "pointer" : "not-allowed",
16930
- display: "flex",
16931
- alignItems: "center",
16932
- justifyContent: "center",
16933
- width: "32px",
16934
- height: "32px",
16935
- transition: "all 0.2s"
16936
- },
16937
- 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: [
16938
- /* @__PURE__ */ jsx10("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
16939
- /* @__PURE__ */ jsx10("polyline", { points: "5 12 12 5 19 12" })
16940
- ] })
16941
- }
16942
- )
16943
- ]
16944
- }
16945
- )
16946
- ]
17071
+ ref: fileInputRef,
17072
+ type: "file",
17073
+ multiple: true,
17074
+ "data-testid": "file-input",
17075
+ style: { display: "none" },
17076
+ onChange: handleFileInputChange,
17077
+ accept: acceptedTypes?.join(",")
16947
17078
  }
17079
+ ),
17080
+ pendingApprovals.length > 0 && onApproveToolCall && onRejectToolCall ? /* @__PURE__ */ jsx11(
17081
+ ToolApprovalDialog,
17082
+ {
17083
+ toolCallName: pendingApprovals[0].toolCallName,
17084
+ toolCallArgs: pendingApprovals[0].toolCallArgs,
17085
+ annotations: pendingApprovals[0].annotations,
17086
+ toolCount: pendingApprovals.length,
17087
+ pendingTools: pendingApprovals,
17088
+ onApprove: onApproveToolCall,
17089
+ onReject: onRejectToolCall,
17090
+ theme,
17091
+ strings
17092
+ }
17093
+ ) : (
17094
+ /* Input container - single border around everything */
17095
+ /* @__PURE__ */ jsxs8(
17096
+ "div",
17097
+ {
17098
+ style: {
17099
+ border: `1px solid ${theme.borderColor}`,
17100
+ borderRadius: "12px",
17101
+ background: theme.backgroundColor,
17102
+ overflow: "hidden",
17103
+ position: "relative"
17104
+ },
17105
+ children: [
17106
+ slashCommands.AutocompleteComponent,
17107
+ /* @__PURE__ */ jsx11(
17108
+ "textarea",
17109
+ {
17110
+ ref: textareaRef,
17111
+ "data-testid": "chat-input",
17112
+ className: "chat-input",
17113
+ value: input,
17114
+ onChange: handleInputChange,
17115
+ onKeyDown: handleKeyDown,
17116
+ placeholder: !connected ? strings.input.connectingPlaceholder : loading ? `${executingTool?.displayText ?? strings.input.thinking}...` : strings.input.placeholder,
17117
+ disabled: !connected || loading || pendingApprovals.length > 0,
17118
+ rows: 1,
17119
+ style: {
17120
+ width: "100%",
17121
+ padding: "10px 14px 6px",
17122
+ border: "none",
17123
+ fontSize: "14px",
17124
+ lineHeight: "1.4",
17125
+ resize: "none",
17126
+ maxHeight: `${maxTextareaHeight}px`,
17127
+ fontFamily: "inherit",
17128
+ outline: "none",
17129
+ background: "transparent",
17130
+ overflowY: "auto",
17131
+ boxSizing: "border-box"
17132
+ }
17133
+ }
17134
+ ),
17135
+ /* @__PURE__ */ jsxs8(
17136
+ "div",
17137
+ {
17138
+ style: {
17139
+ display: "flex",
17140
+ alignItems: "center",
17141
+ justifyContent: "space-between",
17142
+ padding: "4px 8px"
17143
+ },
17144
+ children: [
17145
+ /* @__PURE__ */ jsx11("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: fileUploadEnabled && /* @__PURE__ */ jsx11(
17146
+ "button",
17147
+ {
17148
+ "data-testid": "file-picker-button",
17149
+ onClick: openFilePicker,
17150
+ disabled: !connected || loading || pendingApprovals.length > 0,
17151
+ style: {
17152
+ padding: "4px",
17153
+ background: "transparent",
17154
+ border: `1px solid ${theme.borderColor}`,
17155
+ borderRadius: "50%",
17156
+ cursor: connected && !loading && pendingApprovals.length === 0 ? "pointer" : "not-allowed",
17157
+ color: theme.secondaryTextColor,
17158
+ display: "flex",
17159
+ alignItems: "center",
17160
+ justifyContent: "center",
17161
+ width: "28px",
17162
+ height: "28px",
17163
+ transition: "all 0.15s",
17164
+ opacity: connected && !loading && pendingApprovals.length === 0 ? 1 : 0.5
17165
+ },
17166
+ onMouseEnter: (e) => {
17167
+ if (connected && !loading && pendingApprovals.length === 0) {
17168
+ e.currentTarget.style.color = theme.primaryColor;
17169
+ e.currentTarget.style.borderColor = theme.primaryColor;
17170
+ }
17171
+ },
17172
+ onMouseLeave: (e) => {
17173
+ e.currentTarget.style.color = theme.secondaryTextColor;
17174
+ e.currentTarget.style.borderColor = theme.borderColor;
17175
+ },
17176
+ title: strings.fileUpload.attachFiles,
17177
+ 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: [
17178
+ /* @__PURE__ */ jsx11("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
17179
+ /* @__PURE__ */ jsx11("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
17180
+ ] })
17181
+ }
17182
+ ) }),
17183
+ /* @__PURE__ */ jsx11(
17184
+ "button",
17185
+ {
17186
+ "data-testid": "chat-send-button",
17187
+ className: "chat-send-button",
17188
+ onClick: handleSend,
17189
+ disabled: !connected || loading || pendingApprovals.length > 0 || !input.trim() && attachments.length === 0,
17190
+ style: {
17191
+ padding: "6px",
17192
+ background: connected && !loading && pendingApprovals.length === 0 && (input.trim() || attachments.length > 0) ? theme.primaryGradient : theme.buttonDisabledBackground,
17193
+ color: connected && !loading && pendingApprovals.length === 0 && (input.trim() || attachments.length > 0) ? "white" : theme.secondaryTextColor,
17194
+ border: "none",
17195
+ borderRadius: "50%",
17196
+ cursor: connected && !loading && pendingApprovals.length === 0 && (input.trim() || attachments.length > 0) ? "pointer" : "not-allowed",
17197
+ display: "flex",
17198
+ alignItems: "center",
17199
+ justifyContent: "center",
17200
+ width: "32px",
17201
+ height: "32px",
17202
+ transition: "all 0.2s"
17203
+ },
17204
+ 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: [
17205
+ /* @__PURE__ */ jsx11("line", { x1: "12", y1: "19", x2: "12", y2: "5" }),
17206
+ /* @__PURE__ */ jsx11("polyline", { points: "5 12 12 5 19 12" })
17207
+ ] })
17208
+ }
17209
+ )
17210
+ ]
17211
+ }
17212
+ )
17213
+ ]
17214
+ }
17215
+ )
16948
17216
  )
16949
17217
  ]
16950
17218
  }
16951
17219
  ),
16952
- /* @__PURE__ */ jsx10("style", { children: `
17220
+ /* @__PURE__ */ jsx11("style", { children: `
16953
17221
  /* Markdown content styles */
16954
17222
  .markdown-content > :first-child {
16955
17223
  margin-top: 0 !important;
@@ -16974,7 +17242,7 @@ function UseAIChatPanel({
16974
17242
  }
16975
17243
 
16976
17244
  // src/components/UseAIFloatingChatWrapper.tsx
16977
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
17245
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
16978
17246
  function UseAIFloatingChatWrapper({
16979
17247
  isOpen,
16980
17248
  onClose,
@@ -16982,8 +17250,8 @@ function UseAIFloatingChatWrapper({
16982
17250
  }) {
16983
17251
  const theme = useTheme();
16984
17252
  if (!isOpen) return null;
16985
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
16986
- /* @__PURE__ */ jsx11(
17253
+ return /* @__PURE__ */ jsxs9(Fragment2, { children: [
17254
+ /* @__PURE__ */ jsx12(
16987
17255
  "div",
16988
17256
  {
16989
17257
  style: {
@@ -16999,7 +17267,7 @@ function UseAIFloatingChatWrapper({
16999
17267
  onClick: onClose
17000
17268
  }
17001
17269
  ),
17002
- /* @__PURE__ */ jsx11(
17270
+ /* @__PURE__ */ jsx12(
17003
17271
  "div",
17004
17272
  {
17005
17273
  style: {
@@ -17018,7 +17286,7 @@ function UseAIFloatingChatWrapper({
17018
17286
  children
17019
17287
  }
17020
17288
  ),
17021
- /* @__PURE__ */ jsx11("style", { children: `
17289
+ /* @__PURE__ */ jsx12("style", { children: `
17022
17290
  @keyframes fadeIn {
17023
17291
  from { opacity: 0; }
17024
17292
  to { opacity: 1; }
@@ -17038,7 +17306,7 @@ function UseAIFloatingChatWrapper({
17038
17306
  }
17039
17307
  function CloseButton({ onClick }) {
17040
17308
  const theme = useTheme();
17041
- return /* @__PURE__ */ jsx11(
17309
+ return /* @__PURE__ */ jsx12(
17042
17310
  "button",
17043
17311
  {
17044
17312
  "data-testid": "chat-close-button",
@@ -17073,7 +17341,7 @@ function CloseButton({ onClick }) {
17073
17341
 
17074
17342
  // src/components/UseAIChat.tsx
17075
17343
  import { createContext as createContext3, useContext as useContext3 } from "react";
17076
- import { jsx as jsx12 } from "react/jsx-runtime";
17344
+ import { jsx as jsx13 } from "react/jsx-runtime";
17077
17345
  var __UseAIChatContext = createContext3(null);
17078
17346
  function useChatUIContext() {
17079
17347
  const context = useContext3(__UseAIChatContext);
@@ -17109,27 +17377,30 @@ function UseAIChat({ floating = false }) {
17109
17377
  onSaveCommand: ctx.commands.save,
17110
17378
  onRenameCommand: ctx.commands.rename,
17111
17379
  onDeleteCommand: ctx.commands.delete,
17112
- executingTool: ctx.executingTool,
17380
+ executingTool: ctx.tools.executing,
17113
17381
  feedbackEnabled: ctx.feedback?.enabled,
17114
- onFeedback: ctx.feedback?.submit
17382
+ onFeedback: ctx.feedback?.submit,
17383
+ pendingApprovals: ctx.tools.pending.tools,
17384
+ onApproveToolCall: ctx.tools.pending.tools.length > 0 ? ctx.tools.pending.approveAll : void 0,
17385
+ onRejectToolCall: ctx.tools.pending.tools.length > 0 ? ctx.tools.pending.rejectAll : void 0
17115
17386
  };
17116
17387
  if (floating) {
17117
- return /* @__PURE__ */ jsx12(
17388
+ return /* @__PURE__ */ jsx13(
17118
17389
  UseAIFloatingChatWrapper,
17119
17390
  {
17120
17391
  isOpen: ctx.ui.isOpen,
17121
17392
  onClose: () => ctx.ui.setOpen(false),
17122
- children: /* @__PURE__ */ jsx12(
17393
+ children: /* @__PURE__ */ jsx13(
17123
17394
  UseAIChatPanel,
17124
17395
  {
17125
17396
  ...chatPanelProps,
17126
- closeButton: /* @__PURE__ */ jsx12(CloseButton, { onClick: () => ctx.ui.setOpen(false) })
17397
+ closeButton: /* @__PURE__ */ jsx13(CloseButton, { onClick: () => ctx.ui.setOpen(false) })
17127
17398
  }
17128
17399
  )
17129
17400
  }
17130
17401
  );
17131
17402
  }
17132
- return /* @__PURE__ */ jsx12(UseAIChatPanel, { ...chatPanelProps });
17403
+ return /* @__PURE__ */ jsx13(UseAIChatPanel, { ...chatPanelProps });
17133
17404
  }
17134
17405
 
17135
17406
  // ../../node_modules/.bun/engine.io-parser@5.2.3/node_modules/engine.io-parser/build/esm/commons.js
@@ -20767,7 +21038,8 @@ var UseAIClient = class {
20767
21038
  tools: this._tools.map((t) => ({
20768
21039
  name: t.name,
20769
21040
  description: t.description,
20770
- parameters: t.parameters
21041
+ parameters: t.parameters,
21042
+ annotations: t.annotations
20771
21043
  })),
20772
21044
  state: this._state,
20773
21045
  context: [],
@@ -20810,6 +21082,24 @@ var UseAIClient = class {
20810
21082
  this._messages.push(toolResultMsg);
20811
21083
  this.send(toolResultMessage);
20812
21084
  }
21085
+ /**
21086
+ * Sends a tool approval response back to the server.
21087
+ *
21088
+ * @param toolCallId - The ID of the tool call being approved/rejected
21089
+ * @param approved - Whether the tool execution is approved
21090
+ * @param reason - Optional reason for rejection (shown to AI)
21091
+ */
21092
+ sendToolApprovalResponse(toolCallId, approved, reason) {
21093
+ const message = {
21094
+ type: "tool_approval_response",
21095
+ data: {
21096
+ toolCallId,
21097
+ approved,
21098
+ reason
21099
+ }
21100
+ };
21101
+ this.send(message);
21102
+ }
20813
21103
  /**
20814
21104
  * Retrieves accumulated tool call data for a specific tool call ID.
20815
21105
  * Used to get the complete tool name and arguments after they've been streamed
@@ -35049,7 +35339,7 @@ var LocalStorageChatRepository = class {
35049
35339
  };
35050
35340
 
35051
35341
  // src/hooks/useChatManagement.ts
35052
- import { useState as useState5, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect5 } from "react";
35342
+ import { useState as useState6, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect5 } from "react";
35053
35343
  var CHAT_TITLE_MAX_LENGTH = 50;
35054
35344
  function deepEquals(a, b) {
35055
35345
  return JSON.stringify(a) === JSON.stringify(b);
@@ -35092,10 +35382,11 @@ function useChatManagement({
35092
35382
  onSendMessage,
35093
35383
  setOpen,
35094
35384
  connected,
35095
- loading
35385
+ loading,
35386
+ hasPendingApproval
35096
35387
  }) {
35097
- const [currentChatId, setCurrentChatId] = useState5(null);
35098
- const [pendingChatId, setPendingChatId] = useState5(null);
35388
+ const [currentChatId, setCurrentChatId] = useState6(null);
35389
+ const [pendingChatId, setPendingChatId] = useState6(null);
35099
35390
  const currentChatIdSnapshot = useRef5(null);
35100
35391
  const pendingChatIdSnapshot = useRef5(null);
35101
35392
  useEffect5(() => {
@@ -35314,6 +35605,10 @@ function useChatManagement({
35314
35605
  useEffect5(() => {
35315
35606
  loadingRef.current = loading;
35316
35607
  }, [loading]);
35608
+ const hasPendingApprovalRef = useRef5(hasPendingApproval);
35609
+ useEffect5(() => {
35610
+ hasPendingApprovalRef.current = hasPendingApproval;
35611
+ }, [hasPendingApproval]);
35317
35612
  const processMessageQueue = useCallback4(async () => {
35318
35613
  if (isProcessingQueueRef.current || pendingMessagesRef.current.length === 0 || !onSendMessage) {
35319
35614
  return;
@@ -35348,16 +35643,16 @@ function useChatManagement({
35348
35643
  setOpen(true);
35349
35644
  }
35350
35645
  await new Promise((resolve) => {
35351
- const checkLoading = () => {
35646
+ const checkReady = () => {
35352
35647
  setTimeout(() => {
35353
- if (!loadingRef.current) {
35648
+ if (!loadingRef.current && !hasPendingApprovalRef.current) {
35354
35649
  resolve();
35355
35650
  } else {
35356
- checkLoading();
35651
+ checkReady();
35357
35652
  }
35358
35653
  }, 100);
35359
35654
  };
35360
- checkLoading();
35655
+ checkReady();
35361
35656
  });
35362
35657
  }
35363
35658
  isProcessingQueueRef.current = false;
@@ -35394,7 +35689,7 @@ function useChatManagement({
35394
35689
  }
35395
35690
 
35396
35691
  // src/hooks/useAgentSelection.ts
35397
- import { useState as useState6, useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3 } from "react";
35692
+ import { useState as useState7, useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3 } from "react";
35398
35693
  function filterAgents(serverAgents, defaultAgentId, visibleAgentIds) {
35399
35694
  const getDefaultAgentFallback = () => {
35400
35695
  const defaultAgentInfo = serverAgents.find((a) => a.id === defaultAgentId);
@@ -35420,9 +35715,9 @@ function useAgentSelection({
35420
35715
  connected,
35421
35716
  visibleAgentIds
35422
35717
  }) {
35423
- const [serverAgents, setServerAgents] = useState6([]);
35424
- const [defaultAgent, setDefaultAgent] = useState6(null);
35425
- const [selectedAgent, setSelectedAgent] = useState6(null);
35718
+ const [serverAgents, setServerAgents] = useState7([]);
35719
+ const [defaultAgent, setDefaultAgent] = useState7(null);
35720
+ const [selectedAgent, setSelectedAgent] = useState7(null);
35426
35721
  const availableAgents = useMemo3(
35427
35722
  () => filterAgents(serverAgents, defaultAgent, visibleAgentIds),
35428
35723
  [serverAgents, defaultAgent, visibleAgentIds]
@@ -35459,7 +35754,7 @@ function useAgentSelection({
35459
35754
  }
35460
35755
 
35461
35756
  // src/hooks/useCommandManagement.ts
35462
- import { useState as useState7, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect7 } from "react";
35757
+ import { useState as useState8, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect7 } from "react";
35463
35758
 
35464
35759
  // src/commands/LocalStorageCommandRepository.ts
35465
35760
  var STORAGE_KEY_PREFIX2 = "use-ai:command:";
@@ -35592,7 +35887,7 @@ function useCommandManagement({
35592
35887
  const repositoryRef = useRef6(
35593
35888
  repository || new LocalStorageCommandRepository()
35594
35889
  );
35595
- const [commands, setCommands] = useState7([]);
35890
+ const [commands, setCommands] = useState8([]);
35596
35891
  const refreshCommands = useCallback6(async () => {
35597
35892
  try {
35598
35893
  const cmdList = await repositoryRef.current.listCommands();
@@ -35634,10 +35929,10 @@ function useCommandManagement({
35634
35929
  }
35635
35930
 
35636
35931
  // src/hooks/useToolRegistry.ts
35637
- import { useState as useState8, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
35932
+ import { useState as useState9, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
35638
35933
  function useToolRegistry() {
35639
35934
  const toolRegistryRef = useRef7(/* @__PURE__ */ new Map());
35640
- const [toolRegistryVersion, setToolRegistryVersion] = useState8(0);
35935
+ const [toolRegistryVersion, setToolRegistryVersion] = useState9(0);
35641
35936
  const toolOwnershipRef = useRef7(/* @__PURE__ */ new Map());
35642
35937
  const invisibleRef = useRef7(/* @__PURE__ */ new Set());
35643
35938
  const registerTools = useCallback7((id, tools, options) => {
@@ -35697,7 +35992,7 @@ function useToolRegistry() {
35697
35992
  }
35698
35993
 
35699
35994
  // src/hooks/usePromptState.ts
35700
- import { useState as useState9, useCallback as useCallback8, useRef as useRef8, useMemo as useMemo5, useEffect as useEffect8 } from "react";
35995
+ import { useState as useState10, useCallback as useCallback8, useRef as useRef8, useMemo as useMemo5, useEffect as useEffect8 } from "react";
35701
35996
  function usePromptState({
35702
35997
  systemPrompt,
35703
35998
  clientRef,
@@ -35706,7 +36001,7 @@ function usePromptState({
35706
36001
  const promptsRef = useRef8(/* @__PURE__ */ new Map());
35707
36002
  const suggestionsRef = useRef8(/* @__PURE__ */ new Map());
35708
36003
  const waitersRef = useRef8(/* @__PURE__ */ new Map());
35709
- const [suggestionsVersion, setSuggestionsVersion] = useState9(0);
36004
+ const [suggestionsVersion, setSuggestionsVersion] = useState10(0);
35710
36005
  const buildStateFromPrompts = useCallback8(() => {
35711
36006
  const promptParts = [];
35712
36007
  if (systemPrompt) {
@@ -35769,14 +36064,14 @@ function usePromptState({
35769
36064
  }
35770
36065
 
35771
36066
  // src/hooks/useFeedback.ts
35772
- import { useState as useState10, useEffect as useEffect9, useRef as useRef9, useCallback as useCallback9 } from "react";
36067
+ import { useState as useState11, useEffect as useEffect9, useRef as useRef9, useCallback as useCallback9 } from "react";
35773
36068
  function useFeedback({
35774
36069
  clientRef,
35775
36070
  repository,
35776
36071
  getDisplayedChatId,
35777
36072
  setMessages
35778
36073
  }) {
35779
- const [enabled, setEnabled] = useState10(false);
36074
+ const [enabled, setEnabled] = useState11(false);
35780
36075
  const enabledRef = useRef9(false);
35781
36076
  useEffect9(() => {
35782
36077
  enabledRef.current = enabled;
@@ -35830,8 +36125,120 @@ function useFeedback({
35830
36125
  };
35831
36126
  }
35832
36127
 
36128
+ // src/hooks/useToolExecution.ts
36129
+ import { useState as useState12, useCallback as useCallback10, useRef as useRef10 } from "react";
36130
+ function useToolExecution({
36131
+ clientRef,
36132
+ aggregatedToolsRef,
36133
+ toolOwnershipRef,
36134
+ promptsRef,
36135
+ isInvisible,
36136
+ getWaiter
36137
+ }) {
36138
+ const [pendingApprovals, setPendingApprovals] = useState12([]);
36139
+ const pendingApprovalToolCallsRef = useRef10(/* @__PURE__ */ new Map());
36140
+ const handleApprovalRequest = useCallback10((event) => {
36141
+ console.log("[useToolExecution] Tool approval requested:", event.toolCallName, event.toolCallId);
36142
+ setPendingApprovals((prev) => [
36143
+ ...prev,
36144
+ {
36145
+ toolCallId: event.toolCallId,
36146
+ toolCallName: event.toolCallName,
36147
+ toolCallArgs: event.toolCallArgs,
36148
+ annotations: event.annotations
36149
+ }
36150
+ ]);
36151
+ }, []);
36152
+ const executeToolCall = useCallback10(async (toolCallId, name, input) => {
36153
+ const client = clientRef.current;
36154
+ if (!client) {
36155
+ console.error("[useToolExecution] No client available for tool execution");
36156
+ return;
36157
+ }
36158
+ try {
36159
+ const ownerId = toolOwnershipRef.current.get(name);
36160
+ console.log(`[useToolExecution] Tool "${name}" owned by component:`, ownerId);
36161
+ console.log("[useToolExecution] Executing tool...");
36162
+ const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
36163
+ const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
36164
+ const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
36165
+ if (ownerId && !isErrorResult && !ownerIsInvisible) {
36166
+ const waiter = getWaiter(ownerId);
36167
+ if (waiter) {
36168
+ console.log(`[useToolExecution] Waiting for prompt change from ${ownerId}...`);
36169
+ await waiter();
36170
+ console.log("[useToolExecution] Prompt change wait complete");
36171
+ }
36172
+ } else if (isErrorResult) {
36173
+ console.log("[useToolExecution] Tool returned error, skipping prompt wait");
36174
+ } else if (ownerIsInvisible) {
36175
+ console.log("[useToolExecution] Component is invisible, skipping prompt wait");
36176
+ }
36177
+ let updatedState = null;
36178
+ if (ownerId) {
36179
+ const prompt = promptsRef.current.get(ownerId);
36180
+ if (prompt) {
36181
+ updatedState = { context: prompt };
36182
+ console.log(`[useToolExecution] Updated state from ${ownerId}`);
36183
+ }
36184
+ }
36185
+ client.sendToolResponse(toolCallId, result, updatedState);
36186
+ } catch (err) {
36187
+ console.error("Tool execution error:", err);
36188
+ client.sendToolResponse(toolCallId, {
36189
+ error: err instanceof Error ? err.message : "Unknown error"
36190
+ });
36191
+ }
36192
+ }, [clientRef, aggregatedToolsRef, toolOwnershipRef, promptsRef, isInvisible, getWaiter]);
36193
+ const storePendingToolCall = useCallback10((toolCallId, name, input, toolCallData) => {
36194
+ console.log(`[useToolExecution] Storing pending tool call "${name}" for approval`);
36195
+ pendingApprovalToolCallsRef.current.set(toolCallId, { name, input, toolCallData });
36196
+ }, []);
36197
+ const executePendingToolAfterApproval = useCallback10(async (toolCallId) => {
36198
+ const pendingTool = pendingApprovalToolCallsRef.current.get(toolCallId);
36199
+ if (!pendingTool) {
36200
+ console.warn(`[useToolExecution] No pending tool found for ${toolCallId}`);
36201
+ return;
36202
+ }
36203
+ pendingApprovalToolCallsRef.current.delete(toolCallId);
36204
+ await executeToolCall(toolCallId, pendingTool.name, pendingTool.input);
36205
+ }, [executeToolCall]);
36206
+ const approveAll = useCallback10(async () => {
36207
+ if (!clientRef.current) return;
36208
+ console.log("[useToolExecution] Approving all tool calls:", pendingApprovals.length);
36209
+ const pendingTools = [...pendingApprovals];
36210
+ for (const pending of pendingTools) {
36211
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
36212
+ }
36213
+ setPendingApprovals([]);
36214
+ for (const tool of pendingTools) {
36215
+ await executePendingToolAfterApproval(tool.toolCallId);
36216
+ }
36217
+ }, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
36218
+ const rejectAll = useCallback10((reason) => {
36219
+ if (!clientRef.current) return;
36220
+ console.log("[useToolExecution] Rejecting all tool calls:", pendingApprovals.length, reason);
36221
+ const pendingTools = [...pendingApprovals];
36222
+ for (const pending of pendingTools) {
36223
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
36224
+ }
36225
+ setPendingApprovals([]);
36226
+ for (const tool of pendingTools) {
36227
+ pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
36228
+ }
36229
+ }, [clientRef, pendingApprovals]);
36230
+ return {
36231
+ pendingApprovals,
36232
+ handleApprovalRequest,
36233
+ executeToolCall,
36234
+ storePendingToolCall,
36235
+ approveAll,
36236
+ rejectAll
36237
+ };
36238
+ }
36239
+
35833
36240
  // src/providers/useAIProvider.tsx
35834
- import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
36241
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
35835
36242
  var __UseAIContext = createContext4(null);
35836
36243
  var hasWarnedAboutMissingProvider = false;
35837
36244
  var noOpContextValue = {
@@ -35911,24 +36318,24 @@ function UseAIProvider({
35911
36318
  const fileUploadConfig = fileUploadConfigProp === false ? void 0 : fileUploadConfigProp ?? DEFAULT_FILE_UPLOAD_CONFIG;
35912
36319
  const theme = { ...defaultTheme, ...customTheme };
35913
36320
  const strings = { ...defaultStrings, ...customStrings };
35914
- const [connected, setConnected] = useState11(false);
35915
- const [isChatOpen, setIsChatOpen] = useState11(false);
35916
- const [loading, setLoading] = useState11(false);
35917
- const [messages, setMessages] = useState11([]);
35918
- const [fileProcessingState, setFileProcessingState] = useState11(null);
35919
- const handleSetChatOpen = useCallback10((open) => {
36321
+ const [connected, setConnected] = useState13(false);
36322
+ const [isChatOpen, setIsChatOpen] = useState13(false);
36323
+ const [loading, setLoading] = useState13(false);
36324
+ const [messages, setMessages] = useState13([]);
36325
+ const [fileProcessingState, setFileProcessingState] = useState13(null);
36326
+ const handleSetChatOpen = useCallback11((open) => {
35920
36327
  setIsChatOpen(open);
35921
36328
  onOpenChange?.(open);
35922
36329
  }, [onOpenChange]);
35923
- const [streamingText, setStreamingText] = useState11("");
35924
- const streamingChatIdRef = useRef10(null);
35925
- const [executingTool, setExecutingTool] = useState11(null);
35926
- const executingToolFallbackRef = useRef10(null);
35927
- const clientRef = useRef10(null);
35928
- const repositoryRef = useRef10(
36330
+ const [streamingText, setStreamingText] = useState13("");
36331
+ const streamingChatIdRef = useRef11(null);
36332
+ const [executingTool, setExecutingTool] = useState13(null);
36333
+ const executingToolFallbackRef = useRef11(null);
36334
+ const clientRef = useRef11(null);
36335
+ const repositoryRef = useRef11(
35929
36336
  chatRepository || new LocalStorageChatRepository()
35930
36337
  );
35931
- const handleSendMessageRef = useRef10(null);
36338
+ const handleSendMessageRef = useRef11(null);
35932
36339
  const {
35933
36340
  registerTools,
35934
36341
  unregisterTools,
@@ -35950,11 +36357,19 @@ function UseAIProvider({
35950
36357
  clientRef,
35951
36358
  connected
35952
36359
  });
35953
- const stableSendMessage = useCallback10(async (message, attachments) => {
36360
+ const stableSendMessage = useCallback11(async (message, attachments) => {
35954
36361
  if (handleSendMessageRef.current) {
35955
36362
  await handleSendMessageRef.current(message, attachments);
35956
36363
  }
35957
36364
  }, []);
36365
+ const toolExecution = useToolExecution({
36366
+ clientRef,
36367
+ aggregatedToolsRef,
36368
+ toolOwnershipRef,
36369
+ promptsRef,
36370
+ isInvisible,
36371
+ getWaiter
36372
+ });
35958
36373
  const chatManagement = useChatManagement({
35959
36374
  repository: repositoryRef.current,
35960
36375
  clientRef,
@@ -35963,7 +36378,8 @@ function UseAIProvider({
35963
36378
  onSendMessage: stableSendMessage,
35964
36379
  setOpen: handleSetChatOpen,
35965
36380
  connected,
35966
- loading
36381
+ loading,
36382
+ hasPendingApproval: toolExecution.pendingApprovals.length > 0
35967
36383
  });
35968
36384
  const {
35969
36385
  currentChatId,
@@ -36033,44 +36449,20 @@ function UseAIProvider({
36033
36449
  }
36034
36450
  const name = toolCallData.name;
36035
36451
  const input = JSON.parse(toolCallData.args);
36036
- if (!aggregatedToolsRef.current[name]) {
36452
+ const tool = aggregatedToolsRef.current[name];
36453
+ if (!tool) {
36037
36454
  console.log(`[Provider] Tool "${name}" not found in useAI tools, skipping (likely a workflow tool)`);
36038
36455
  return;
36039
36456
  }
36040
- try {
36041
- const ownerId = toolOwnershipRef.current.get(name);
36042
- console.log(`[useAI] Tool "${name}" owned by component:`, ownerId);
36043
- console.log("[useAI] Executing tool...");
36044
- const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
36045
- const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
36046
- const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
36047
- if (ownerId && !isErrorResult && !ownerIsInvisible) {
36048
- const waiter = getWaiter(ownerId);
36049
- if (waiter) {
36050
- console.log(`[useAI] Waiting for prompt change from ${ownerId}...`);
36051
- await waiter();
36052
- console.log("[useAI] Prompt change wait complete");
36053
- }
36054
- } else if (isErrorResult) {
36055
- console.log("[useAI] Tool returned error, skipping prompt wait");
36056
- } else if (ownerIsInvisible) {
36057
- console.log("[useAI] Component is invisible, skipping prompt wait");
36058
- }
36059
- let updatedState = null;
36060
- if (ownerId) {
36061
- const prompt = promptsRef.current.get(ownerId);
36062
- if (prompt) {
36063
- updatedState = { context: prompt };
36064
- console.log(`[useAI] Updated state from ${ownerId}`);
36065
- }
36066
- }
36067
- client.sendToolResponse(toolCallId, result, updatedState);
36068
- } catch (err) {
36069
- console.error("Tool execution error:", err);
36070
- client.sendToolResponse(toolCallId, {
36071
- error: err instanceof Error ? err.message : "Unknown error"
36072
- });
36457
+ if (tool._options?.annotations?.destructiveHint === true) {
36458
+ console.log(`[Provider] Tool "${name}" requires approval, deferring execution`);
36459
+ toolExecution.storePendingToolCall(toolCallId, name, input, toolCallData);
36460
+ return;
36073
36461
  }
36462
+ await toolExecution.executeToolCall(toolCallId, name, input);
36463
+ } else if (event.type === TOOL_APPROVAL_REQUEST) {
36464
+ const e = event;
36465
+ toolExecution.handleApprovalRequest(e);
36074
36466
  } else if (event.type === export_EventType.TEXT_MESSAGE_CONTENT) {
36075
36467
  const contentEvent = event;
36076
36468
  setStreamingText((prev) => prev + contentEvent.delta);
@@ -36110,7 +36502,7 @@ function UseAIProvider({
36110
36502
  client.setMcpHeadersProvider(mcpHeadersProvider);
36111
36503
  }
36112
36504
  }, [mcpHeadersProvider]);
36113
- const lastRegisteredToolsRef = useRef10("");
36505
+ const lastRegisteredToolsRef = useRef11("");
36114
36506
  useEffect10(() => {
36115
36507
  const client = clientRef.current;
36116
36508
  if (!client || !client.isConnected() || !hasTools) return;
@@ -36129,7 +36521,7 @@ function UseAIProvider({
36129
36521
  console.error("Failed to register tools:", err);
36130
36522
  }
36131
36523
  }, [hasTools, aggregatedTools, connected]);
36132
- const handleSendMessage = useCallback10(async (message, attachments) => {
36524
+ const handleSendMessage = useCallback11(async (message, attachments) => {
36133
36525
  if (!clientRef.current) return;
36134
36526
  setStreamingText("");
36135
36527
  const activatedChatId = activatePendingChat();
@@ -36261,7 +36653,14 @@ function UseAIProvider({
36261
36653
  isOpen: isChatOpen,
36262
36654
  setOpen: handleSetChatOpen
36263
36655
  },
36264
- executingTool: executingToolDisplay,
36656
+ tools: {
36657
+ executing: executingToolDisplay,
36658
+ pending: {
36659
+ tools: toolExecution.pendingApprovals,
36660
+ approveAll: toolExecution.approveAll,
36661
+ rejectAll: toolExecution.rejectAll
36662
+ }
36663
+ },
36265
36664
  feedback: {
36266
36665
  enabled: feedback.enabled,
36267
36666
  submit: feedback.submitFeedback
@@ -36294,21 +36693,24 @@ function UseAIProvider({
36294
36693
  onDeleteCommand: deleteCommand,
36295
36694
  executingTool: executingToolDisplay,
36296
36695
  feedbackEnabled: feedback.enabled,
36297
- onFeedback: feedback.submitFeedback
36696
+ onFeedback: feedback.submitFeedback,
36697
+ pendingApprovals: toolExecution.pendingApprovals,
36698
+ onApproveToolCall: toolExecution.pendingApprovals.length > 0 ? toolExecution.approveAll : void 0,
36699
+ onRejectToolCall: toolExecution.pendingApprovals.length > 0 ? toolExecution.rejectAll : void 0
36298
36700
  };
36299
36701
  const renderDefaultChat = () => {
36300
36702
  if (isUIDisabled) return null;
36301
- return /* @__PURE__ */ jsx13(UseAIFloatingChatWrapper, { isOpen: isChatOpen, onClose: () => handleSetChatOpen(false), children: /* @__PURE__ */ jsx13(
36703
+ return /* @__PURE__ */ jsx14(UseAIFloatingChatWrapper, { isOpen: isChatOpen, onClose: () => handleSetChatOpen(false), children: /* @__PURE__ */ jsx14(
36302
36704
  UseAIChatPanel,
36303
36705
  {
36304
36706
  ...chatPanelProps,
36305
- closeButton: /* @__PURE__ */ jsx13(CloseButton, { onClick: () => handleSetChatOpen(false) })
36707
+ closeButton: /* @__PURE__ */ jsx14(CloseButton, { onClick: () => handleSetChatOpen(false) })
36306
36708
  }
36307
36709
  ) });
36308
36710
  };
36309
36711
  const renderCustomChat = () => {
36310
36712
  if (!CustomChat) return null;
36311
- return /* @__PURE__ */ jsx13(
36713
+ return /* @__PURE__ */ jsx14(
36312
36714
  CustomChat,
36313
36715
  {
36314
36716
  isOpen: isChatOpen,
@@ -36327,8 +36729,8 @@ function UseAIProvider({
36327
36729
  };
36328
36730
  const renderBuiltInChat = () => {
36329
36731
  if (!renderChat) return null;
36330
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
36331
- ButtonComponent && /* @__PURE__ */ jsx13(
36732
+ return /* @__PURE__ */ jsxs10(Fragment3, { children: [
36733
+ ButtonComponent && /* @__PURE__ */ jsx14(
36332
36734
  ButtonComponent,
36333
36735
  {
36334
36736
  onClick: () => handleSetChatOpen(true),
@@ -36338,7 +36740,7 @@ function UseAIProvider({
36338
36740
  hasCustomChat ? renderCustomChat() : renderDefaultChat()
36339
36741
  ] });
36340
36742
  };
36341
- return /* @__PURE__ */ jsx13(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ jsx13(StringsContext.Provider, { value: strings, children: /* @__PURE__ */ jsx13(__UseAIContext.Provider, { value: value2, children: /* @__PURE__ */ jsxs9(__UseAIChatContext.Provider, { value: chatUIContextValue, children: [
36743
+ return /* @__PURE__ */ jsx14(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ jsx14(StringsContext.Provider, { value: strings, children: /* @__PURE__ */ jsx14(__UseAIContext.Provider, { value: value2, children: /* @__PURE__ */ jsxs10(__UseAIChatContext.Provider, { value: chatUIContextValue, children: [
36342
36744
  children,
36343
36745
  renderBuiltInChat()
36344
36746
  ] }) }) }) });
@@ -36358,11 +36760,11 @@ function useAIContext() {
36358
36760
  }
36359
36761
 
36360
36762
  // src/hooks/useStableTools.ts
36361
- import { useRef as useRef11 } from "react";
36763
+ import { useRef as useRef12 } from "react";
36362
36764
  function useStableTools(tools) {
36363
- const latestToolsRef = useRef11({});
36364
- const stableToolsRef = useRef11({});
36365
- const prevToolNamesRef = useRef11("");
36765
+ const latestToolsRef = useRef12({});
36766
+ const stableToolsRef = useRef12({});
36767
+ const prevToolNamesRef = useRef12("");
36366
36768
  if (!tools) {
36367
36769
  latestToolsRef.current = {};
36368
36770
  return void 0;
@@ -36432,13 +36834,13 @@ function useAI(options = {}) {
36432
36834
  const { connected, tools, client, prompts } = useAIContext();
36433
36835
  const { register: registerTools, unregister: unregisterTools } = tools;
36434
36836
  const { update: updatePrompt, registerWaiter, unregisterWaiter } = prompts;
36435
- const [response, setResponse] = useState12(null);
36436
- const [loading, setLoading] = useState12(false);
36437
- const [error48, setError] = useState12(null);
36438
- const hookId = useRef12(`useAI-${Math.random().toString(36).substr(2, 9)}`);
36439
- const toolsRef = useRef12({});
36440
- const componentRef = useRef12(null);
36441
- const promptChangeResolvers = useRef12([]);
36837
+ const [response, setResponse] = useState14(null);
36838
+ const [loading, setLoading] = useState14(false);
36839
+ const [error48, setError] = useState14(null);
36840
+ const hookId = useRef13(`useAI-${Math.random().toString(36).substr(2, 9)}`);
36841
+ const toolsRef = useRef13({});
36842
+ const componentRef = useRef13(null);
36843
+ const promptChangeResolvers = useRef13([]);
36442
36844
  const stableTools = useStableTools(options.tools);
36443
36845
  const toolsKey = useMemo6(() => {
36444
36846
  if (!options.tools) return "";
@@ -36450,7 +36852,7 @@ function useAI(options = {}) {
36450
36852
  componentRef.current.setAttribute("data-useai-context", "true");
36451
36853
  }
36452
36854
  }, []);
36453
- const waitForPromptChange = useCallback11(() => {
36855
+ const waitForPromptChange = useCallback12(() => {
36454
36856
  return new Promise((resolve) => {
36455
36857
  const timeoutMs = 100;
36456
36858
  const timeoutId = setTimeout(() => {
@@ -36482,7 +36884,7 @@ function useAI(options = {}) {
36482
36884
  promptChangeResolvers.current = [];
36483
36885
  }
36484
36886
  }, [enabled, options.prompt, memoizedSuggestions, updatePrompt]);
36485
- const updatePromptRef = useRef12(updatePrompt);
36887
+ const updatePromptRef = useRef13(updatePrompt);
36486
36888
  updatePromptRef.current = updatePrompt;
36487
36889
  useEffect11(() => {
36488
36890
  const id = hookId.current;
@@ -36513,7 +36915,7 @@ function useAI(options = {}) {
36513
36915
  unsubscribe();
36514
36916
  };
36515
36917
  }, [enabled, client]);
36516
- const handleAGUIEvent = useCallback11(async (event) => {
36918
+ const handleAGUIEvent = useCallback12(async (event) => {
36517
36919
  switch (event.type) {
36518
36920
  case export_EventType.TEXT_MESSAGE_END: {
36519
36921
  const content3 = client?.currentMessageContent;
@@ -36533,7 +36935,7 @@ function useAI(options = {}) {
36533
36935
  }
36534
36936
  }
36535
36937
  }, [client, options.onError]);
36536
- const generate = useCallback11(async (prompt) => {
36938
+ const generate = useCallback12(async (prompt) => {
36537
36939
  if (!enabled) {
36538
36940
  const error49 = new Error("AI features are disabled");
36539
36941
  setError(error49);
@@ -36569,15 +36971,15 @@ function useAI(options = {}) {
36569
36971
  }
36570
36972
 
36571
36973
  // src/useAIWorkflow.ts
36572
- import { useState as useState13, useCallback as useCallback12, useRef as useRef13, useEffect as useEffect12 } from "react";
36974
+ import { useState as useState15, useCallback as useCallback13, useRef as useRef14, useEffect as useEffect12 } from "react";
36573
36975
  function useAIWorkflow(runner, workflowId) {
36574
36976
  const { connected, client } = useAIContext();
36575
- const [status, setStatus] = useState13("idle");
36576
- const [text4, setText] = useState13(null);
36577
- const [error48, setError] = useState13(null);
36578
- const currentWorkflowRef = useRef13(null);
36579
- const eventListenerIdRef = useRef13(`useAIWorkflow-${Math.random().toString(36).substr(2, 9)}`);
36580
- const handleWorkflowEvent = useCallback12(async (event) => {
36977
+ const [status, setStatus] = useState15("idle");
36978
+ const [text4, setText] = useState15(null);
36979
+ const [error48, setError] = useState15(null);
36980
+ const currentWorkflowRef = useRef14(null);
36981
+ const eventListenerIdRef = useRef14(`useAIWorkflow-${Math.random().toString(36).substr(2, 9)}`);
36982
+ const handleWorkflowEvent = useCallback13(async (event) => {
36581
36983
  const currentWorkflow = currentWorkflowRef.current;
36582
36984
  if (!currentWorkflow) return;
36583
36985
  if (event.type === export_EventType.RUN_STARTED) {
@@ -36669,7 +37071,7 @@ function useAIWorkflow(runner, workflowId) {
36669
37071
  unsubscribe();
36670
37072
  };
36671
37073
  }, [client, handleWorkflowEvent]);
36672
- const trigger = useCallback12(async (options) => {
37074
+ const trigger = useCallback13(async (options) => {
36673
37075
  if (!client?.isConnected()) {
36674
37076
  const err = new Error("Not connected to server");
36675
37077
  setError(err);
@@ -36742,7 +37144,7 @@ export {
36742
37144
  defaultTheme,
36743
37145
  defineTool,
36744
37146
  executeDefinedTool,
36745
- findTransformer,
37147
+ findTransformerPattern,
36746
37148
  generateChatId,
36747
37149
  generateCommandId,
36748
37150
  generateMessageId,