@meetsmore-oss/use-ai-client 1.5.1 → 1.7.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(",")
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
16947
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
@@ -20546,8 +20817,6 @@ var UseAIClient = class {
20546
20817
  _tools = [];
20547
20818
  _messages = [];
20548
20819
  _state = null;
20549
- // MCP headers provider
20550
- mcpHeadersProvider;
20551
20820
  // Agent selection
20552
20821
  _availableAgents = [];
20553
20822
  _defaultAgent = null;
@@ -20706,22 +20975,15 @@ var UseAIClient = class {
20706
20975
  updateState(state) {
20707
20976
  this._state = state;
20708
20977
  }
20709
- /**
20710
- * Sets the MCP headers provider.
20711
- * The provider will be called each time a message is sent to get fresh headers.
20712
- *
20713
- * @param provider - Function that returns MCP headers configuration
20714
- */
20715
- setMcpHeadersProvider(provider) {
20716
- this.mcpHeadersProvider = provider;
20717
- }
20718
20978
  /**
20719
20979
  * Sends a user prompt to the AI.
20720
20980
  *
20721
20981
  * @param prompt - The user's prompt/question (text part)
20722
20982
  * @param multimodalContent - Optional multimodal content (text, images, files)
20983
+ * @param forwardedProps - Optional props to forward to the server (e.g., telemetryMetadata, mcpHeaders).
20984
+ * Internally merged with other forwardedProps.
20723
20985
  */
20724
- async sendPrompt(prompt, multimodalContent) {
20986
+ async sendPrompt(prompt, multimodalContent, forwardedProps) {
20725
20987
  let messageContent = prompt;
20726
20988
  if (multimodalContent && multimodalContent.length > 0) {
20727
20989
  messageContent = multimodalContent.map((part) => {
@@ -20751,14 +21013,6 @@ var UseAIClient = class {
20751
21013
  // Type cast needed for Message type compatibility
20752
21014
  };
20753
21015
  this._messages.push(userMessage);
20754
- let mcpHeaders;
20755
- if (this.mcpHeadersProvider) {
20756
- try {
20757
- mcpHeaders = await this.mcpHeadersProvider();
20758
- } catch (error48) {
20759
- console.error("[UseAIClient] Failed to get MCP headers:", error48);
20760
- }
20761
- }
20762
21016
  const runInput = {
20763
21017
  threadId: this.threadId,
20764
21018
  // Use getter to ensure non-null
@@ -20767,13 +21021,14 @@ var UseAIClient = class {
20767
21021
  tools: this._tools.map((t) => ({
20768
21022
  name: t.name,
20769
21023
  description: t.description,
20770
- parameters: t.parameters
21024
+ parameters: t.parameters,
21025
+ annotations: t.annotations
20771
21026
  })),
20772
21027
  state: this._state,
20773
21028
  context: [],
20774
21029
  forwardedProps: {
20775
- ...mcpHeaders ? { mcpHeaders } : {},
20776
- ...this._selectedAgent ? { agent: this._selectedAgent } : {}
21030
+ ...this._selectedAgent ? { agent: this._selectedAgent } : {},
21031
+ ...forwardedProps || {}
20777
21032
  }
20778
21033
  };
20779
21034
  this.send({
@@ -20810,6 +21065,24 @@ var UseAIClient = class {
20810
21065
  this._messages.push(toolResultMsg);
20811
21066
  this.send(toolResultMessage);
20812
21067
  }
21068
+ /**
21069
+ * Sends a tool approval response back to the server.
21070
+ *
21071
+ * @param toolCallId - The ID of the tool call being approved/rejected
21072
+ * @param approved - Whether the tool execution is approved
21073
+ * @param reason - Optional reason for rejection (shown to AI)
21074
+ */
21075
+ sendToolApprovalResponse(toolCallId, approved, reason) {
21076
+ const message = {
21077
+ type: "tool_approval_response",
21078
+ data: {
21079
+ toolCallId,
21080
+ approved,
21081
+ reason
21082
+ }
21083
+ };
21084
+ this.send(message);
21085
+ }
20813
21086
  /**
20814
21087
  * Retrieves accumulated tool call data for a specific tool call ID.
20815
21088
  * Used to get the complete tool name and arguments after they've been streamed
@@ -35049,7 +35322,7 @@ var LocalStorageChatRepository = class {
35049
35322
  };
35050
35323
 
35051
35324
  // src/hooks/useChatManagement.ts
35052
- import { useState as useState5, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect5 } from "react";
35325
+ import { useState as useState6, useCallback as useCallback4, useRef as useRef5, useEffect as useEffect5 } from "react";
35053
35326
  var CHAT_TITLE_MAX_LENGTH = 50;
35054
35327
  function deepEquals(a, b) {
35055
35328
  return JSON.stringify(a) === JSON.stringify(b);
@@ -35092,10 +35365,11 @@ function useChatManagement({
35092
35365
  onSendMessage,
35093
35366
  setOpen,
35094
35367
  connected,
35095
- loading
35368
+ loading,
35369
+ hasPendingApproval
35096
35370
  }) {
35097
- const [currentChatId, setCurrentChatId] = useState5(null);
35098
- const [pendingChatId, setPendingChatId] = useState5(null);
35371
+ const [currentChatId, setCurrentChatId] = useState6(null);
35372
+ const [pendingChatId, setPendingChatId] = useState6(null);
35099
35373
  const currentChatIdSnapshot = useRef5(null);
35100
35374
  const pendingChatIdSnapshot = useRef5(null);
35101
35375
  useEffect5(() => {
@@ -35314,6 +35588,10 @@ function useChatManagement({
35314
35588
  useEffect5(() => {
35315
35589
  loadingRef.current = loading;
35316
35590
  }, [loading]);
35591
+ const hasPendingApprovalRef = useRef5(hasPendingApproval);
35592
+ useEffect5(() => {
35593
+ hasPendingApprovalRef.current = hasPendingApproval;
35594
+ }, [hasPendingApproval]);
35317
35595
  const processMessageQueue = useCallback4(async () => {
35318
35596
  if (isProcessingQueueRef.current || pendingMessagesRef.current.length === 0 || !onSendMessage) {
35319
35597
  return;
@@ -35321,7 +35599,7 @@ function useChatManagement({
35321
35599
  isProcessingQueueRef.current = true;
35322
35600
  while (pendingMessagesRef.current.length > 0) {
35323
35601
  const { message, options } = pendingMessagesRef.current.shift();
35324
- const { newChat = false, attachments = [], openChat = true, metadata } = options ?? {};
35602
+ const { newChat = false, attachments = [], openChat = true, metadata, forwardedProps } = options ?? {};
35325
35603
  if (newChat) {
35326
35604
  await createNewChat({ metadata });
35327
35605
  }
@@ -35343,21 +35621,21 @@ function useChatManagement({
35343
35621
  };
35344
35622
  })
35345
35623
  );
35346
- await onSendMessage(message, fileAttachments.length > 0 ? fileAttachments : void 0);
35624
+ await onSendMessage(message, fileAttachments.length > 0 ? fileAttachments : void 0, forwardedProps);
35347
35625
  if (openChat && setOpen) {
35348
35626
  setOpen(true);
35349
35627
  }
35350
35628
  await new Promise((resolve) => {
35351
- const checkLoading = () => {
35629
+ const checkReady = () => {
35352
35630
  setTimeout(() => {
35353
- if (!loadingRef.current) {
35631
+ if (!loadingRef.current && !hasPendingApprovalRef.current) {
35354
35632
  resolve();
35355
35633
  } else {
35356
- checkLoading();
35634
+ checkReady();
35357
35635
  }
35358
35636
  }, 100);
35359
35637
  };
35360
- checkLoading();
35638
+ checkReady();
35361
35639
  });
35362
35640
  }
35363
35641
  isProcessingQueueRef.current = false;
@@ -35394,7 +35672,7 @@ function useChatManagement({
35394
35672
  }
35395
35673
 
35396
35674
  // src/hooks/useAgentSelection.ts
35397
- import { useState as useState6, useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3 } from "react";
35675
+ import { useState as useState7, useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo3 } from "react";
35398
35676
  function filterAgents(serverAgents, defaultAgentId, visibleAgentIds) {
35399
35677
  const getDefaultAgentFallback = () => {
35400
35678
  const defaultAgentInfo = serverAgents.find((a) => a.id === defaultAgentId);
@@ -35420,9 +35698,9 @@ function useAgentSelection({
35420
35698
  connected,
35421
35699
  visibleAgentIds
35422
35700
  }) {
35423
- const [serverAgents, setServerAgents] = useState6([]);
35424
- const [defaultAgent, setDefaultAgent] = useState6(null);
35425
- const [selectedAgent, setSelectedAgent] = useState6(null);
35701
+ const [serverAgents, setServerAgents] = useState7([]);
35702
+ const [defaultAgent, setDefaultAgent] = useState7(null);
35703
+ const [selectedAgent, setSelectedAgent] = useState7(null);
35426
35704
  const availableAgents = useMemo3(
35427
35705
  () => filterAgents(serverAgents, defaultAgent, visibleAgentIds),
35428
35706
  [serverAgents, defaultAgent, visibleAgentIds]
@@ -35459,7 +35737,7 @@ function useAgentSelection({
35459
35737
  }
35460
35738
 
35461
35739
  // src/hooks/useCommandManagement.ts
35462
- import { useState as useState7, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect7 } from "react";
35740
+ import { useState as useState8, useCallback as useCallback6, useRef as useRef6, useEffect as useEffect7 } from "react";
35463
35741
 
35464
35742
  // src/commands/LocalStorageCommandRepository.ts
35465
35743
  var STORAGE_KEY_PREFIX2 = "use-ai:command:";
@@ -35592,7 +35870,7 @@ function useCommandManagement({
35592
35870
  const repositoryRef = useRef6(
35593
35871
  repository || new LocalStorageCommandRepository()
35594
35872
  );
35595
- const [commands, setCommands] = useState7([]);
35873
+ const [commands, setCommands] = useState8([]);
35596
35874
  const refreshCommands = useCallback6(async () => {
35597
35875
  try {
35598
35876
  const cmdList = await repositoryRef.current.listCommands();
@@ -35634,10 +35912,10 @@ function useCommandManagement({
35634
35912
  }
35635
35913
 
35636
35914
  // src/hooks/useToolRegistry.ts
35637
- import { useState as useState8, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
35915
+ import { useState as useState9, useCallback as useCallback7, useRef as useRef7, useMemo as useMemo4 } from "react";
35638
35916
  function useToolRegistry() {
35639
35917
  const toolRegistryRef = useRef7(/* @__PURE__ */ new Map());
35640
- const [toolRegistryVersion, setToolRegistryVersion] = useState8(0);
35918
+ const [toolRegistryVersion, setToolRegistryVersion] = useState9(0);
35641
35919
  const toolOwnershipRef = useRef7(/* @__PURE__ */ new Map());
35642
35920
  const invisibleRef = useRef7(/* @__PURE__ */ new Set());
35643
35921
  const registerTools = useCallback7((id, tools, options) => {
@@ -35697,7 +35975,7 @@ function useToolRegistry() {
35697
35975
  }
35698
35976
 
35699
35977
  // src/hooks/usePromptState.ts
35700
- import { useState as useState9, useCallback as useCallback8, useRef as useRef8, useMemo as useMemo5, useEffect as useEffect8 } from "react";
35978
+ import { useState as useState10, useCallback as useCallback8, useRef as useRef8, useMemo as useMemo5, useEffect as useEffect8 } from "react";
35701
35979
  function usePromptState({
35702
35980
  systemPrompt,
35703
35981
  clientRef,
@@ -35706,7 +35984,7 @@ function usePromptState({
35706
35984
  const promptsRef = useRef8(/* @__PURE__ */ new Map());
35707
35985
  const suggestionsRef = useRef8(/* @__PURE__ */ new Map());
35708
35986
  const waitersRef = useRef8(/* @__PURE__ */ new Map());
35709
- const [suggestionsVersion, setSuggestionsVersion] = useState9(0);
35987
+ const [suggestionsVersion, setSuggestionsVersion] = useState10(0);
35710
35988
  const buildStateFromPrompts = useCallback8(() => {
35711
35989
  const promptParts = [];
35712
35990
  if (systemPrompt) {
@@ -35769,14 +36047,14 @@ function usePromptState({
35769
36047
  }
35770
36048
 
35771
36049
  // src/hooks/useFeedback.ts
35772
- import { useState as useState10, useEffect as useEffect9, useRef as useRef9, useCallback as useCallback9 } from "react";
36050
+ import { useState as useState11, useEffect as useEffect9, useRef as useRef9, useCallback as useCallback9 } from "react";
35773
36051
  function useFeedback({
35774
36052
  clientRef,
35775
36053
  repository,
35776
36054
  getDisplayedChatId,
35777
36055
  setMessages
35778
36056
  }) {
35779
- const [enabled, setEnabled] = useState10(false);
36057
+ const [enabled, setEnabled] = useState11(false);
35780
36058
  const enabledRef = useRef9(false);
35781
36059
  useEffect9(() => {
35782
36060
  enabledRef.current = enabled;
@@ -35830,8 +36108,120 @@ function useFeedback({
35830
36108
  };
35831
36109
  }
35832
36110
 
36111
+ // src/hooks/useToolExecution.ts
36112
+ import { useState as useState12, useCallback as useCallback10, useRef as useRef10 } from "react";
36113
+ function useToolExecution({
36114
+ clientRef,
36115
+ aggregatedToolsRef,
36116
+ toolOwnershipRef,
36117
+ promptsRef,
36118
+ isInvisible,
36119
+ getWaiter
36120
+ }) {
36121
+ const [pendingApprovals, setPendingApprovals] = useState12([]);
36122
+ const pendingApprovalToolCallsRef = useRef10(/* @__PURE__ */ new Map());
36123
+ const handleApprovalRequest = useCallback10((event) => {
36124
+ console.log("[useToolExecution] Tool approval requested:", event.toolCallName, event.toolCallId);
36125
+ setPendingApprovals((prev) => [
36126
+ ...prev,
36127
+ {
36128
+ toolCallId: event.toolCallId,
36129
+ toolCallName: event.toolCallName,
36130
+ toolCallArgs: event.toolCallArgs,
36131
+ annotations: event.annotations
36132
+ }
36133
+ ]);
36134
+ }, []);
36135
+ const executeToolCall = useCallback10(async (toolCallId, name, input) => {
36136
+ const client = clientRef.current;
36137
+ if (!client) {
36138
+ console.error("[useToolExecution] No client available for tool execution");
36139
+ return;
36140
+ }
36141
+ try {
36142
+ const ownerId = toolOwnershipRef.current.get(name);
36143
+ console.log(`[useToolExecution] Tool "${name}" owned by component:`, ownerId);
36144
+ console.log("[useToolExecution] Executing tool...");
36145
+ const result = await executeDefinedTool(aggregatedToolsRef.current, name, input);
36146
+ const isErrorResult = result && typeof result === "object" && ("error" in result || result.success === false);
36147
+ const ownerIsInvisible = ownerId ? isInvisible(ownerId) : false;
36148
+ if (ownerId && !isErrorResult && !ownerIsInvisible) {
36149
+ const waiter = getWaiter(ownerId);
36150
+ if (waiter) {
36151
+ console.log(`[useToolExecution] Waiting for prompt change from ${ownerId}...`);
36152
+ await waiter();
36153
+ console.log("[useToolExecution] Prompt change wait complete");
36154
+ }
36155
+ } else if (isErrorResult) {
36156
+ console.log("[useToolExecution] Tool returned error, skipping prompt wait");
36157
+ } else if (ownerIsInvisible) {
36158
+ console.log("[useToolExecution] Component is invisible, skipping prompt wait");
36159
+ }
36160
+ let updatedState = null;
36161
+ if (ownerId) {
36162
+ const prompt = promptsRef.current.get(ownerId);
36163
+ if (prompt) {
36164
+ updatedState = { context: prompt };
36165
+ console.log(`[useToolExecution] Updated state from ${ownerId}`);
36166
+ }
36167
+ }
36168
+ client.sendToolResponse(toolCallId, result, updatedState);
36169
+ } catch (err) {
36170
+ console.error("Tool execution error:", err);
36171
+ client.sendToolResponse(toolCallId, {
36172
+ error: err instanceof Error ? err.message : "Unknown error"
36173
+ });
36174
+ }
36175
+ }, [clientRef, aggregatedToolsRef, toolOwnershipRef, promptsRef, isInvisible, getWaiter]);
36176
+ const storePendingToolCall = useCallback10((toolCallId, name, input, toolCallData) => {
36177
+ console.log(`[useToolExecution] Storing pending tool call "${name}" for approval`);
36178
+ pendingApprovalToolCallsRef.current.set(toolCallId, { name, input, toolCallData });
36179
+ }, []);
36180
+ const executePendingToolAfterApproval = useCallback10(async (toolCallId) => {
36181
+ const pendingTool = pendingApprovalToolCallsRef.current.get(toolCallId);
36182
+ if (!pendingTool) {
36183
+ console.warn(`[useToolExecution] No pending tool found for ${toolCallId}`);
36184
+ return;
36185
+ }
36186
+ pendingApprovalToolCallsRef.current.delete(toolCallId);
36187
+ await executeToolCall(toolCallId, pendingTool.name, pendingTool.input);
36188
+ }, [executeToolCall]);
36189
+ const approveAll = useCallback10(async () => {
36190
+ if (!clientRef.current) return;
36191
+ console.log("[useToolExecution] Approving all tool calls:", pendingApprovals.length);
36192
+ const pendingTools = [...pendingApprovals];
36193
+ for (const pending of pendingTools) {
36194
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, true);
36195
+ }
36196
+ setPendingApprovals([]);
36197
+ for (const tool of pendingTools) {
36198
+ await executePendingToolAfterApproval(tool.toolCallId);
36199
+ }
36200
+ }, [clientRef, pendingApprovals, executePendingToolAfterApproval]);
36201
+ const rejectAll = useCallback10((reason) => {
36202
+ if (!clientRef.current) return;
36203
+ console.log("[useToolExecution] Rejecting all tool calls:", pendingApprovals.length, reason);
36204
+ const pendingTools = [...pendingApprovals];
36205
+ for (const pending of pendingTools) {
36206
+ clientRef.current.sendToolApprovalResponse(pending.toolCallId, false, reason);
36207
+ }
36208
+ setPendingApprovals([]);
36209
+ for (const tool of pendingTools) {
36210
+ pendingApprovalToolCallsRef.current.delete(tool.toolCallId);
36211
+ }
36212
+ }, [clientRef, pendingApprovals]);
36213
+ return {
36214
+ pendingApprovals,
36215
+ handleApprovalRequest,
36216
+ executeToolCall,
36217
+ storePendingToolCall,
36218
+ approveAll,
36219
+ rejectAll
36220
+ };
36221
+ }
36222
+
35833
36223
  // src/providers/useAIProvider.tsx
35834
- import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
36224
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
35835
36225
  var __UseAIContext = createContext4(null);
35836
36226
  var hasWarnedAboutMissingProvider = false;
35837
36227
  var noOpContextValue = {
@@ -35899,7 +36289,7 @@ function UseAIProvider({
35899
36289
  CustomButton,
35900
36290
  CustomChat,
35901
36291
  chatRepository,
35902
- mcpHeadersProvider,
36292
+ forwardedPropsProvider,
35903
36293
  fileUploadConfig: fileUploadConfigProp,
35904
36294
  commandRepository,
35905
36295
  renderChat = true,
@@ -35911,24 +36301,24 @@ function UseAIProvider({
35911
36301
  const fileUploadConfig = fileUploadConfigProp === false ? void 0 : fileUploadConfigProp ?? DEFAULT_FILE_UPLOAD_CONFIG;
35912
36302
  const theme = { ...defaultTheme, ...customTheme };
35913
36303
  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) => {
36304
+ const [connected, setConnected] = useState13(false);
36305
+ const [isChatOpen, setIsChatOpen] = useState13(false);
36306
+ const [loading, setLoading] = useState13(false);
36307
+ const [messages, setMessages] = useState13([]);
36308
+ const [fileProcessingState, setFileProcessingState] = useState13(null);
36309
+ const handleSetChatOpen = useCallback11((open) => {
35920
36310
  setIsChatOpen(open);
35921
36311
  onOpenChange?.(open);
35922
36312
  }, [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(
36313
+ const [streamingText, setStreamingText] = useState13("");
36314
+ const streamingChatIdRef = useRef11(null);
36315
+ const [executingTool, setExecutingTool] = useState13(null);
36316
+ const executingToolFallbackRef = useRef11(null);
36317
+ const clientRef = useRef11(null);
36318
+ const repositoryRef = useRef11(
35929
36319
  chatRepository || new LocalStorageChatRepository()
35930
36320
  );
35931
- const handleSendMessageRef = useRef10(null);
36321
+ const handleSendMessageRef = useRef11(null);
35932
36322
  const {
35933
36323
  registerTools,
35934
36324
  unregisterTools,
@@ -35950,11 +36340,19 @@ function UseAIProvider({
35950
36340
  clientRef,
35951
36341
  connected
35952
36342
  });
35953
- const stableSendMessage = useCallback10(async (message, attachments) => {
36343
+ const stableSendMessage = useCallback11(async (message, attachments, forwardedProps) => {
35954
36344
  if (handleSendMessageRef.current) {
35955
- await handleSendMessageRef.current(message, attachments);
36345
+ await handleSendMessageRef.current(message, attachments, forwardedProps);
35956
36346
  }
35957
36347
  }, []);
36348
+ const toolExecution = useToolExecution({
36349
+ clientRef,
36350
+ aggregatedToolsRef,
36351
+ toolOwnershipRef,
36352
+ promptsRef,
36353
+ isInvisible,
36354
+ getWaiter
36355
+ });
35958
36356
  const chatManagement = useChatManagement({
35959
36357
  repository: repositoryRef.current,
35960
36358
  clientRef,
@@ -35963,7 +36361,8 @@ function UseAIProvider({
35963
36361
  onSendMessage: stableSendMessage,
35964
36362
  setOpen: handleSetChatOpen,
35965
36363
  connected,
35966
- loading
36364
+ loading,
36365
+ hasPendingApproval: toolExecution.pendingApprovals.length > 0
35967
36366
  });
35968
36367
  const {
35969
36368
  currentChatId,
@@ -36003,9 +36402,6 @@ function UseAIProvider({
36003
36402
  useEffect10(() => {
36004
36403
  console.log("[UseAIProvider] Initializing client with serverUrl:", serverUrl);
36005
36404
  const client = new UseAIClient(serverUrl);
36006
- if (mcpHeadersProvider) {
36007
- client.setMcpHeadersProvider(mcpHeadersProvider);
36008
- }
36009
36405
  const unsubscribeConnection = client.onConnectionStateChange((isConnected) => {
36010
36406
  console.log("[UseAIProvider] Connection state changed:", isConnected);
36011
36407
  setConnected(isConnected);
@@ -36033,44 +36429,20 @@ function UseAIProvider({
36033
36429
  }
36034
36430
  const name = toolCallData.name;
36035
36431
  const input = JSON.parse(toolCallData.args);
36036
- if (!aggregatedToolsRef.current[name]) {
36432
+ const tool = aggregatedToolsRef.current[name];
36433
+ if (!tool) {
36037
36434
  console.log(`[Provider] Tool "${name}" not found in useAI tools, skipping (likely a workflow tool)`);
36038
36435
  return;
36039
36436
  }
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
- });
36437
+ if (tool._options?.annotations?.destructiveHint === true) {
36438
+ console.log(`[Provider] Tool "${name}" requires approval, deferring execution`);
36439
+ toolExecution.storePendingToolCall(toolCallId, name, input, toolCallData);
36440
+ return;
36073
36441
  }
36442
+ await toolExecution.executeToolCall(toolCallId, name, input);
36443
+ } else if (event.type === TOOL_APPROVAL_REQUEST) {
36444
+ const e = event;
36445
+ toolExecution.handleApprovalRequest(e);
36074
36446
  } else if (event.type === export_EventType.TEXT_MESSAGE_CONTENT) {
36075
36447
  const contentEvent = event;
36076
36448
  setStreamingText((prev) => prev + contentEvent.delta);
@@ -36103,14 +36475,7 @@ function UseAIProvider({
36103
36475
  client.disconnect();
36104
36476
  };
36105
36477
  }, [serverUrl]);
36106
- useEffect10(() => {
36107
- const client = clientRef.current;
36108
- if (!client) return;
36109
- if (mcpHeadersProvider) {
36110
- client.setMcpHeadersProvider(mcpHeadersProvider);
36111
- }
36112
- }, [mcpHeadersProvider]);
36113
- const lastRegisteredToolsRef = useRef10("");
36478
+ const lastRegisteredToolsRef = useRef11("");
36114
36479
  useEffect10(() => {
36115
36480
  const client = clientRef.current;
36116
36481
  if (!client || !client.isConnected() || !hasTools) return;
@@ -36129,7 +36494,7 @@ function UseAIProvider({
36129
36494
  console.error("Failed to register tools:", err);
36130
36495
  }
36131
36496
  }, [hasTools, aggregatedTools, connected]);
36132
- const handleSendMessage = useCallback10(async (message, attachments) => {
36497
+ const handleSendMessage = useCallback11(async (message, attachments, messageForwardedProps) => {
36133
36498
  if (!clientRef.current) return;
36134
36499
  setStreamingText("");
36135
36500
  const activatedChatId = activatePendingChat();
@@ -36183,8 +36548,18 @@ function UseAIProvider({
36183
36548
  }
36184
36549
  setLoading(true);
36185
36550
  }
36186
- await clientRef.current.sendPrompt(message, multimodalContent);
36187
- }, [activatePendingChat, currentChatId, saveUserMessage, fileUploadConfig, getCurrentChat]);
36551
+ const providerResult = forwardedPropsProvider ? forwardedPropsProvider() : {};
36552
+ const providerProps = providerResult instanceof Promise ? await providerResult : providerResult;
36553
+ const mergedForwardedProps = {
36554
+ ...providerProps,
36555
+ ...messageForwardedProps
36556
+ };
36557
+ await clientRef.current.sendPrompt(
36558
+ message,
36559
+ multimodalContent,
36560
+ Object.keys(mergedForwardedProps).length > 0 ? mergedForwardedProps : void 0
36561
+ );
36562
+ }, [activatePendingChat, currentChatId, saveUserMessage, fileUploadConfig, getCurrentChat, forwardedPropsProvider]);
36188
36563
  handleSendMessageRef.current = handleSendMessage;
36189
36564
  const value2 = {
36190
36565
  serverUrl,
@@ -36261,7 +36636,14 @@ function UseAIProvider({
36261
36636
  isOpen: isChatOpen,
36262
36637
  setOpen: handleSetChatOpen
36263
36638
  },
36264
- executingTool: executingToolDisplay,
36639
+ tools: {
36640
+ executing: executingToolDisplay,
36641
+ pending: {
36642
+ tools: toolExecution.pendingApprovals,
36643
+ approveAll: toolExecution.approveAll,
36644
+ rejectAll: toolExecution.rejectAll
36645
+ }
36646
+ },
36265
36647
  feedback: {
36266
36648
  enabled: feedback.enabled,
36267
36649
  submit: feedback.submitFeedback
@@ -36294,21 +36676,24 @@ function UseAIProvider({
36294
36676
  onDeleteCommand: deleteCommand,
36295
36677
  executingTool: executingToolDisplay,
36296
36678
  feedbackEnabled: feedback.enabled,
36297
- onFeedback: feedback.submitFeedback
36679
+ onFeedback: feedback.submitFeedback,
36680
+ pendingApprovals: toolExecution.pendingApprovals,
36681
+ onApproveToolCall: toolExecution.pendingApprovals.length > 0 ? toolExecution.approveAll : void 0,
36682
+ onRejectToolCall: toolExecution.pendingApprovals.length > 0 ? toolExecution.rejectAll : void 0
36298
36683
  };
36299
36684
  const renderDefaultChat = () => {
36300
36685
  if (isUIDisabled) return null;
36301
- return /* @__PURE__ */ jsx13(UseAIFloatingChatWrapper, { isOpen: isChatOpen, onClose: () => handleSetChatOpen(false), children: /* @__PURE__ */ jsx13(
36686
+ return /* @__PURE__ */ jsx14(UseAIFloatingChatWrapper, { isOpen: isChatOpen, onClose: () => handleSetChatOpen(false), children: /* @__PURE__ */ jsx14(
36302
36687
  UseAIChatPanel,
36303
36688
  {
36304
36689
  ...chatPanelProps,
36305
- closeButton: /* @__PURE__ */ jsx13(CloseButton, { onClick: () => handleSetChatOpen(false) })
36690
+ closeButton: /* @__PURE__ */ jsx14(CloseButton, { onClick: () => handleSetChatOpen(false) })
36306
36691
  }
36307
36692
  ) });
36308
36693
  };
36309
36694
  const renderCustomChat = () => {
36310
36695
  if (!CustomChat) return null;
36311
- return /* @__PURE__ */ jsx13(
36696
+ return /* @__PURE__ */ jsx14(
36312
36697
  CustomChat,
36313
36698
  {
36314
36699
  isOpen: isChatOpen,
@@ -36327,8 +36712,8 @@ function UseAIProvider({
36327
36712
  };
36328
36713
  const renderBuiltInChat = () => {
36329
36714
  if (!renderChat) return null;
36330
- return /* @__PURE__ */ jsxs9(Fragment3, { children: [
36331
- ButtonComponent && /* @__PURE__ */ jsx13(
36715
+ return /* @__PURE__ */ jsxs10(Fragment3, { children: [
36716
+ ButtonComponent && /* @__PURE__ */ jsx14(
36332
36717
  ButtonComponent,
36333
36718
  {
36334
36719
  onClick: () => handleSetChatOpen(true),
@@ -36338,7 +36723,7 @@ function UseAIProvider({
36338
36723
  hasCustomChat ? renderCustomChat() : renderDefaultChat()
36339
36724
  ] });
36340
36725
  };
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: [
36726
+ 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
36727
  children,
36343
36728
  renderBuiltInChat()
36344
36729
  ] }) }) }) });
@@ -36358,11 +36743,11 @@ function useAIContext() {
36358
36743
  }
36359
36744
 
36360
36745
  // src/hooks/useStableTools.ts
36361
- import { useRef as useRef11 } from "react";
36746
+ import { useRef as useRef12 } from "react";
36362
36747
  function useStableTools(tools) {
36363
- const latestToolsRef = useRef11({});
36364
- const stableToolsRef = useRef11({});
36365
- const prevToolNamesRef = useRef11("");
36748
+ const latestToolsRef = useRef12({});
36749
+ const stableToolsRef = useRef12({});
36750
+ const prevToolNamesRef = useRef12("");
36366
36751
  if (!tools) {
36367
36752
  latestToolsRef.current = {};
36368
36753
  return void 0;
@@ -36432,13 +36817,13 @@ function useAI(options = {}) {
36432
36817
  const { connected, tools, client, prompts } = useAIContext();
36433
36818
  const { register: registerTools, unregister: unregisterTools } = tools;
36434
36819
  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([]);
36820
+ const [response, setResponse] = useState14(null);
36821
+ const [loading, setLoading] = useState14(false);
36822
+ const [error48, setError] = useState14(null);
36823
+ const hookId = useRef13(`useAI-${Math.random().toString(36).substr(2, 9)}`);
36824
+ const toolsRef = useRef13({});
36825
+ const componentRef = useRef13(null);
36826
+ const promptChangeResolvers = useRef13([]);
36442
36827
  const stableTools = useStableTools(options.tools);
36443
36828
  const toolsKey = useMemo6(() => {
36444
36829
  if (!options.tools) return "";
@@ -36450,7 +36835,7 @@ function useAI(options = {}) {
36450
36835
  componentRef.current.setAttribute("data-useai-context", "true");
36451
36836
  }
36452
36837
  }, []);
36453
- const waitForPromptChange = useCallback11(() => {
36838
+ const waitForPromptChange = useCallback12(() => {
36454
36839
  return new Promise((resolve) => {
36455
36840
  const timeoutMs = 100;
36456
36841
  const timeoutId = setTimeout(() => {
@@ -36482,7 +36867,7 @@ function useAI(options = {}) {
36482
36867
  promptChangeResolvers.current = [];
36483
36868
  }
36484
36869
  }, [enabled, options.prompt, memoizedSuggestions, updatePrompt]);
36485
- const updatePromptRef = useRef12(updatePrompt);
36870
+ const updatePromptRef = useRef13(updatePrompt);
36486
36871
  updatePromptRef.current = updatePrompt;
36487
36872
  useEffect11(() => {
36488
36873
  const id = hookId.current;
@@ -36513,7 +36898,7 @@ function useAI(options = {}) {
36513
36898
  unsubscribe();
36514
36899
  };
36515
36900
  }, [enabled, client]);
36516
- const handleAGUIEvent = useCallback11(async (event) => {
36901
+ const handleAGUIEvent = useCallback12(async (event) => {
36517
36902
  switch (event.type) {
36518
36903
  case export_EventType.TEXT_MESSAGE_END: {
36519
36904
  const content3 = client?.currentMessageContent;
@@ -36533,7 +36918,7 @@ function useAI(options = {}) {
36533
36918
  }
36534
36919
  }
36535
36920
  }, [client, options.onError]);
36536
- const generate = useCallback11(async (prompt) => {
36921
+ const generate = useCallback12(async (prompt) => {
36537
36922
  if (!enabled) {
36538
36923
  const error49 = new Error("AI features are disabled");
36539
36924
  setError(error49);
@@ -36569,15 +36954,15 @@ function useAI(options = {}) {
36569
36954
  }
36570
36955
 
36571
36956
  // src/useAIWorkflow.ts
36572
- import { useState as useState13, useCallback as useCallback12, useRef as useRef13, useEffect as useEffect12 } from "react";
36957
+ import { useState as useState15, useCallback as useCallback13, useRef as useRef14, useEffect as useEffect12 } from "react";
36573
36958
  function useAIWorkflow(runner, workflowId) {
36574
36959
  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) => {
36960
+ const [status, setStatus] = useState15("idle");
36961
+ const [text4, setText] = useState15(null);
36962
+ const [error48, setError] = useState15(null);
36963
+ const currentWorkflowRef = useRef14(null);
36964
+ const eventListenerIdRef = useRef14(`useAIWorkflow-${Math.random().toString(36).substr(2, 9)}`);
36965
+ const handleWorkflowEvent = useCallback13(async (event) => {
36581
36966
  const currentWorkflow = currentWorkflowRef.current;
36582
36967
  if (!currentWorkflow) return;
36583
36968
  if (event.type === export_EventType.RUN_STARTED) {
@@ -36669,7 +37054,7 @@ function useAIWorkflow(runner, workflowId) {
36669
37054
  unsubscribe();
36670
37055
  };
36671
37056
  }, [client, handleWorkflowEvent]);
36672
- const trigger = useCallback12(async (options) => {
37057
+ const trigger = useCallback13(async (options) => {
36673
37058
  if (!client?.isConnected()) {
36674
37059
  const err = new Error("Not connected to server");
36675
37060
  setError(err);
@@ -36742,7 +37127,7 @@ export {
36742
37127
  defaultTheme,
36743
37128
  defineTool,
36744
37129
  executeDefinedTool,
36745
- findTransformer,
37130
+ findTransformerPattern,
36746
37131
  generateChatId,
36747
37132
  generateCommandId,
36748
37133
  generateMessageId,