@alpaca-editor/core 1.0.4135 → 1.0.4140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/config/config.js +7 -0
  2. package/dist/config/config.js.map +1 -1
  3. package/dist/editor/FieldListField.js +3 -4
  4. package/dist/editor/FieldListField.js.map +1 -1
  5. package/dist/editor/Terminal.js +1 -1
  6. package/dist/editor/Terminal.js.map +1 -1
  7. package/dist/editor/Titlebar.js +0 -1
  8. package/dist/editor/Titlebar.js.map +1 -1
  9. package/dist/editor/ai/AgentCostDisplay.d.ts +3 -1
  10. package/dist/editor/ai/AgentCostDisplay.js +26 -2
  11. package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
  12. package/dist/editor/ai/AgentStatusBadge.d.ts +26 -0
  13. package/dist/editor/ai/AgentStatusBadge.js +110 -0
  14. package/dist/editor/ai/AgentStatusBadge.js.map +1 -0
  15. package/dist/editor/ai/AgentTerminal.js +289 -198
  16. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  17. package/dist/editor/ai/Agents.d.ts +2 -2
  18. package/dist/editor/ai/Agents.js +115 -19
  19. package/dist/editor/ai/Agents.js.map +1 -1
  20. package/dist/editor/ai/AiResponseMessage.js +259 -45
  21. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  22. package/dist/editor/ai/ContextInfoBar.js +124 -113
  23. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  24. package/dist/editor/ai/ToolCallDisplay.d.ts +1 -0
  25. package/dist/editor/ai/ToolCallDisplay.js +70 -58
  26. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  27. package/dist/editor/ai/useAgentStatus.d.ts +13 -0
  28. package/dist/editor/ai/useAgentStatus.js +101 -0
  29. package/dist/editor/ai/useAgentStatus.js.map +1 -0
  30. package/dist/editor/client/EditorShell.js +23 -8
  31. package/dist/editor/client/EditorShell.js.map +1 -1
  32. package/dist/editor/client/itemsRepository.js.map +1 -1
  33. package/dist/editor/commands/localizeItem/LocalizeItemDialog.js +5 -5
  34. package/dist/editor/commands/localizeItem/LocalizeItemDialog.js.map +1 -1
  35. package/dist/editor/control-center/About.js +1 -1
  36. package/dist/editor/control-center/About.js.map +1 -1
  37. package/dist/editor/control-center/AllAgentsPanel.d.ts +5 -0
  38. package/dist/editor/control-center/AllAgentsPanel.js +126 -0
  39. package/dist/editor/control-center/AllAgentsPanel.js.map +1 -0
  40. package/dist/editor/control-center/WebSocketMessages.js +1 -0
  41. package/dist/editor/control-center/WebSocketMessages.js.map +1 -1
  42. package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js +42 -7
  43. package/dist/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.js.map +1 -1
  44. package/dist/editor/media-selector/AiImageSearch.d.ts +1 -1
  45. package/dist/editor/media-selector/AiImageSearch.js +162 -103
  46. package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
  47. package/dist/editor/media-selector/TreeSelector.js +20 -4
  48. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  49. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +5 -2
  50. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  51. package/dist/editor/page-editor-chrome/PlaceholderDropZone.d.ts +1 -1
  52. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +7 -5
  53. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  54. package/dist/editor/page-viewer/DeviceToolbar.js +2 -2
  55. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  56. package/dist/editor/page-viewer/PageViewerFrame.js +18 -11
  57. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  58. package/dist/editor/services/agentService.d.ts +53 -48
  59. package/dist/editor/services/agentService.js +137 -79
  60. package/dist/editor/services/agentService.js.map +1 -1
  61. package/dist/editor/services/aiService.d.ts +1 -1
  62. package/dist/editor/services/editService.js +1 -0
  63. package/dist/editor/services/editService.js.map +1 -1
  64. package/dist/editor/sidebar/GraphQL.js +20 -7
  65. package/dist/editor/sidebar/GraphQL.js.map +1 -1
  66. package/dist/editor/sidebar/SEOInfo.js +1 -2
  67. package/dist/editor/sidebar/SEOInfo.js.map +1 -1
  68. package/dist/editor/sidebar/Translations.js +10 -7
  69. package/dist/editor/sidebar/Translations.js.map +1 -1
  70. package/dist/editor/ui/ItemNameDialogNew.js +1 -1
  71. package/dist/editor/ui/ItemSearch.js +10 -4
  72. package/dist/editor/ui/ItemSearch.js.map +1 -1
  73. package/dist/page-wizard/steps/CollectStep.js +2 -2
  74. package/dist/page-wizard/steps/CollectStep.js.map +1 -1
  75. package/dist/page-wizard/steps/FieldEditor.js +2 -2
  76. package/dist/page-wizard/steps/FieldEditor.js.map +1 -1
  77. package/dist/revision.d.ts +2 -2
  78. package/dist/revision.js +2 -2
  79. package/dist/splash-screen/NewPage.js +2 -2
  80. package/dist/splash-screen/NewPage.js.map +1 -1
  81. package/dist/splash-screen/RecentPages.js +1 -1
  82. package/dist/splash-screen/RecentPages.js.map +1 -1
  83. package/dist/styles.css +167 -22
  84. package/dist/tour/Tour.js +15 -11
  85. package/dist/tour/Tour.js.map +1 -1
  86. package/package.json +1 -1
  87. package/src/config/config.tsx +7 -0
  88. package/src/editor/FieldListField.tsx +13 -13
  89. package/src/editor/Terminal.tsx +1 -1
  90. package/src/editor/Titlebar.tsx +0 -1
  91. package/src/editor/ai/AgentCostDisplay.tsx +57 -1
  92. package/src/editor/ai/AgentStatusBadge.tsx +144 -0
  93. package/src/editor/ai/AgentTerminal.tsx +345 -219
  94. package/src/editor/ai/Agents.tsx +179 -30
  95. package/src/editor/ai/AiResponseMessage.tsx +411 -114
  96. package/src/editor/ai/ContextInfoBar.tsx +134 -131
  97. package/src/editor/ai/ToolCallDisplay.tsx +217 -176
  98. package/src/editor/ai/useAgentStatus.ts +123 -0
  99. package/src/editor/client/EditorShell.tsx +34 -8
  100. package/src/editor/client/itemsRepository.ts +1 -2
  101. package/src/editor/commands/localizeItem/LocalizeItemDialog.tsx +5 -5
  102. package/src/editor/control-center/About.tsx +0 -14
  103. package/src/editor/control-center/AllAgentsPanel.tsx +300 -0
  104. package/src/editor/control-center/WebSocketMessages.tsx +1 -0
  105. package/src/editor/control-center/setup-steps/AiSetupStep/tools/GenerateToolsSection.tsx +49 -8
  106. package/src/editor/media-selector/AiImageSearch.tsx +162 -172
  107. package/src/editor/media-selector/TreeSelector.tsx +137 -116
  108. package/src/editor/menubar/toolbar-sections/UtilityControls.tsx +9 -1
  109. package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +7 -4
  110. package/src/editor/page-viewer/DeviceToolbar.tsx +15 -11
  111. package/src/editor/page-viewer/PageViewerFrame.tsx +20 -14
  112. package/src/editor/services/agentService.ts +217 -129
  113. package/src/editor/services/aiService.ts +2 -2
  114. package/src/editor/services/editService.ts +1 -0
  115. package/src/editor/sidebar/GraphQL.tsx +143 -117
  116. package/src/editor/sidebar/SEOInfo.tsx +1 -2
  117. package/src/editor/sidebar/Translations.tsx +14 -12
  118. package/src/editor/ui/ItemNameDialogNew.tsx +1 -1
  119. package/src/editor/ui/ItemSearch.tsx +11 -4
  120. package/src/editor/ui/SimpleTabs.tsx +1 -1
  121. package/src/page-wizard/steps/CollectStep.tsx +2 -2
  122. package/src/page-wizard/steps/FieldEditor.tsx +13 -15
  123. package/src/revision.ts +2 -2
  124. package/src/splash-screen/NewPage.tsx +2 -2
  125. package/src/splash-screen/RecentPages.tsx +1 -1
  126. package/src/tour/Tour.tsx +61 -48
@@ -2,22 +2,40 @@ import React, { useState } from "react";
2
2
  import { JsonView, defaultStyles } from "react-json-view-lite";
3
3
  import "react-json-view-lite/dist/index.css";
4
4
 
5
- import {
6
- Popover,
7
- PopoverContent,
8
- PopoverTrigger,
9
- } from "../../components/ui/popover";
10
- import { SimpleTabs, Tab } from "../ui/SimpleTabs";
11
5
  import { Spinner } from "../ui/Spinner";
12
- import { SimpleIconButton } from "../ui/SimpleIconButton";
13
6
  import { Button } from "../../components/ui/button";
14
7
  import { approveToolCall, rejectToolCall } from "../services/agentService";
8
+
9
+ // Custom dark theme styles for JSON view
10
+ const darkJsonStyles = {
11
+ ...defaultStyles,
12
+ container: "dark-json-container",
13
+ label: "dark-json-label",
14
+ punctuation: "dark-json-punctuation",
15
+ stringValue: "dark-json-string",
16
+ numberValue: "dark-json-number",
17
+ booleanValue: "dark-json-boolean",
18
+ nullValue: "dark-json-null",
19
+ undefinedValue: "dark-json-undefined",
20
+ };
21
+
22
+ // JSON view light theme CSS
23
+ const JsonLightThemeStyles = () => (
24
+ <style>{`
25
+ .dark-json-container { color: #1f2937; }
26
+ .dark-json-label { color: #2563eb; font-weight: 500; }
27
+ .dark-json-punctuation { color: #6b7280; }
28
+ .dark-json-string { color: #059669; }
29
+ .dark-json-number { color: #d97706; }
30
+ .dark-json-boolean { color: #7c3aed; }
31
+ .dark-json-null { color: #dc2626; }
32
+ .dark-json-undefined { color: #dc2626; }
33
+ `}</style>
34
+ );
15
35
  import {
16
- X,
17
36
  FileText,
18
37
  Search,
19
38
  Code,
20
- Terminal,
21
39
  FolderOpen,
22
40
  FileSearch,
23
41
  Trash2,
@@ -27,6 +45,8 @@ import {
27
45
  Edit,
28
46
  FileEdit,
29
47
  Wrench,
48
+ ChevronDown,
49
+ ChevronRight,
30
50
  } from "lucide-react";
31
51
 
32
52
  // Function to get the appropriate icon for each tool
@@ -94,7 +114,8 @@ export interface BaseToolCall {
94
114
 
95
115
  export interface AgentToolCall {
96
116
  id: string;
97
- messageId: string;
117
+ messageId: string; // UI message ID (for display association)
118
+ dbMessageId?: string; // Database message ID (for approval/rejection)
98
119
  toolCallId: string;
99
120
  functionName: string;
100
121
  functionArguments: string;
@@ -144,10 +165,11 @@ const renderJsonOrText = (json: string | object) => {
144
165
  if (typeof json === "object" && json !== null) {
145
166
  return (
146
167
  <div className="font-mono text-xs" style={{ fontSize: "12px" }}>
168
+ <JsonLightThemeStyles />
147
169
  <JsonView
148
170
  data={json}
149
171
  shouldExpandNode={(level) => level < 2}
150
- style={defaultStyles}
172
+ style={darkJsonStyles}
151
173
  />
152
174
  </div>
153
175
  );
@@ -174,10 +196,11 @@ const renderJsonOrText = (json: string | object) => {
174
196
 
175
197
  return (
176
198
  <div className="font-mono text-xs" style={{ fontSize: "12px" }}>
199
+ <JsonLightThemeStyles />
177
200
  <JsonView
178
201
  data={parsed}
179
202
  shouldExpandNode={(level) => level < 2}
180
- style={defaultStyles}
203
+ style={darkJsonStyles}
181
204
  />
182
205
  </div>
183
206
  );
@@ -191,10 +214,11 @@ const renderJsonOrText = (json: string | object) => {
191
214
 
192
215
  return (
193
216
  <div className="font-mono text-xs" style={{ fontSize: "12px" }}>
217
+ <JsonLightThemeStyles />
194
218
  <JsonView
195
219
  data={parsed}
196
220
  shouldExpandNode={(level) => level < 2}
197
- style={defaultStyles}
221
+ style={darkJsonStyles}
198
222
  />
199
223
  </div>
200
224
  );
@@ -202,7 +226,7 @@ const renderJsonOrText = (json: string | object) => {
202
226
  console.log("Unescaping also failed:", e2);
203
227
  // If all parsing fails, display as plain text
204
228
  return (
205
- <div className="font-mono text-xs break-words whitespace-pre-wrap">
229
+ <div className="font-mono text-xs break-words whitespace-pre-wrap text-gray-700">
206
230
  {jsonString}
207
231
  </div>
208
232
  );
@@ -210,81 +234,84 @@ const renderJsonOrText = (json: string | object) => {
210
234
  }
211
235
  };
212
236
 
213
- // Helper function to create tabs for a tool call
214
- const createToolCallTabs = (toolCall: BaseToolCall, result: string): Tab[] => {
215
- const tabs: Tab[] = [
216
- {
217
- id: `input-${toolCall.id}`,
218
- label: "Input",
219
- content: (
220
- <div className="h-[250px] w-full overflow-auto p-2">
221
- <div className="text-xs">
222
- {renderJsonOrText(toolCall.function?.arguments || "")}
223
- </div>
224
- </div>
225
- ),
226
- },
227
- ];
228
-
229
- // Add output tab if there's a result or error
230
- if (result || toolCall.function?.error) {
231
- const hasError = toolCall.function?.error;
232
- tabs.push({
233
- id: `output-${toolCall.id}`,
234
- label: hasError ? "Error" : "Output",
235
- content: (
236
- <div className="h-[250px] w-full overflow-auto p-2">
237
- {hasError ? (
238
- <div className="rounded border-l-4 border-red-500 bg-red-50 p-3 text-xs text-red-600">
239
- <div className="mb-1 font-medium">Tool Error:</div>
240
- <div>{toolCall.function?.error}</div>
241
- </div>
242
- ) : (
243
- <div className="text-xs">{renderJsonOrText(result || "")}</div>
244
- )}
245
- </div>
246
- ),
247
- });
248
- }
237
+ // Expandable panel component
238
+ const ExpandablePanel = ({
239
+ title,
240
+ children,
241
+ defaultExpanded = false,
242
+ }: {
243
+ title: string;
244
+ children: React.ReactNode;
245
+ defaultExpanded?: boolean;
246
+ }) => {
247
+ const [isExpanded, setIsExpanded] = useState(defaultExpanded);
249
248
 
250
- return tabs;
249
+ return (
250
+ <div className="border-b border-gray-200/60 last:border-b-0">
251
+ <div
252
+ className="flex cursor-pointer items-center gap-2 px-4 py-2.5 transition-colors hover:bg-white/60"
253
+ onClick={() => setIsExpanded(!isExpanded)}
254
+ >
255
+ {isExpanded ? (
256
+ <ChevronDown
257
+ size={14}
258
+ strokeWidth={1.5}
259
+ className="text-gray-500 transition-transform"
260
+ />
261
+ ) : (
262
+ <ChevronRight
263
+ size={14}
264
+ strokeWidth={1.5}
265
+ className="text-gray-500 transition-transform"
266
+ />
267
+ )}
268
+ <span className="text-xs font-semibold tracking-wide text-gray-600 uppercase">
269
+ {title}
270
+ </span>
271
+ </div>
272
+ {isExpanded && (
273
+ <div className="w-full overflow-auto px-4 pt-1 pb-4">{children}</div>
274
+ )}
275
+ </div>
276
+ );
251
277
  };
252
278
 
253
- // Helper function to create tool call popover content
254
- const ToolCallPopover = ({
279
+ // Helper function to create expandable tool call details
280
+ const ToolCallDetails = ({
255
281
  toolCall,
256
282
  result,
257
- onClose,
258
283
  }: {
259
284
  toolCall: BaseToolCall;
260
285
  result?: string;
261
- onClose: () => void;
262
286
  }) => {
263
- const [activeTab, setActiveTab] = useState(0);
264
- const tabs = createToolCallTabs(toolCall, result || "");
287
+ const hasError = toolCall.function?.error;
288
+ const hasOutput = result || hasError;
265
289
 
266
290
  return (
267
- <div className="flex flex-col p-3">
268
- <div className="mb-3 flex items-center justify-between border-b border-gray-200 px-2 pb-1">
269
- <div className="flex items-center gap-2 text-sm font-semibold text-gray-800">
270
- {getToolIcon(toolCall?.function?.name || "")}
271
- <span>{toolCall.displayName || toolCall.function?.name}</span>
291
+ <div className="mt-2 ml-4 overflow-hidden rounded-lg border border-gray-200/80 bg-gradient-to-br from-gray-50 to-gray-50/30 shadow-sm">
292
+ <ExpandablePanel title="Input" defaultExpanded={!hasOutput}>
293
+ <div className="rounded-md border border-gray-200 bg-white p-3 text-xs shadow-sm">
294
+ {renderJsonOrText(toolCall.function?.arguments || "")}
272
295
  </div>
273
- <SimpleIconButton
274
- onClick={onClose}
275
- icon={<X strokeWidth={1} size={16} />}
276
- label="Close"
277
- showTooltip={false}
278
- size="small"
279
- />
280
- </div>
281
- <SimpleTabs
282
- tabs={tabs}
283
- activeTab={activeTab}
284
- setActiveTab={setActiveTab}
285
- className="mb-3 border-b border-gray-200"
286
- tabClassName="text-xs"
287
- />
296
+ </ExpandablePanel>
297
+
298
+ {hasOutput && (
299
+ <ExpandablePanel
300
+ title={hasError ? "Error" : "Output"}
301
+ defaultExpanded={true}
302
+ >
303
+ {hasError ? (
304
+ <div className="rounded-md border-l-4 border-red-500 bg-red-50/80 p-3 text-xs text-red-700 shadow-sm">
305
+ <div className="mb-1.5 font-semibold">Tool Error:</div>
306
+ <div className="text-red-600">{toolCall.function?.error}</div>
307
+ </div>
308
+ ) : (
309
+ <div className="rounded-md border border-gray-200 bg-white p-3 text-xs shadow-sm">
310
+ {renderJsonOrText(result || "")}
311
+ </div>
312
+ )}
313
+ </ExpandablePanel>
314
+ )}
288
315
  </div>
289
316
  );
290
317
  };
@@ -301,7 +328,7 @@ export function ToolCallDisplay({
301
328
  }
302
329
 
303
330
  return (
304
- <div className="mt-2 flex flex-col gap-2">
331
+ <div className="flex flex-col">
305
332
  {toolCalls.map((originalToolCall, toolIndex) => {
306
333
  const toolCall = normalizeToolCall(originalToolCall);
307
334
  const toolResult = toolCall.function?.result;
@@ -333,140 +360,146 @@ export function ToolCallDisplay({
333
360
 
334
361
  // Debug logging removed for performance
335
362
 
363
+ const isExpanded = openPopovers[popoverKey] || false;
364
+
336
365
  return (
337
366
  <div key={toolIndex}>
338
- <Popover
339
- enableIframeClickDetection={false}
340
- open={openPopovers[popoverKey] || false}
341
- onOpenChange={(open) => {
367
+ <div
368
+ className="group flex cursor-pointer items-center gap-1.5 rounded-md px-1 py-1 text-xs text-gray-600 transition-all hover:bg-gray-100/60 hover:text-gray-800"
369
+ onClick={() => {
342
370
  setOpenPopovers((prev) => ({
343
371
  ...prev,
344
- [popoverKey]: open,
372
+ [popoverKey]: !prev[popoverKey],
345
373
  }));
346
374
  }}
347
375
  >
348
- <PopoverTrigger asChild>
349
- <div className="flex items-center gap-2 text-xs text-gray-500">
350
- {isCompleted ? (
351
- <div
352
- className={`flex items-center ${toolCall.function?.error ? "text-red-500" : ""}`}
353
- >
354
- {getToolIcon(toolCall?.function?.name || "")}
355
- </div>
356
- ) : finalApprovalInfo && !hasApprovalStatus ? (
357
- <div className="flex items-center text-amber-600">
358
- {getToolIcon(toolCall?.function?.name || "")}
359
- </div>
360
- ) : finished ? (
361
- <div className="flex items-center opacity-50">
362
- {getToolIcon(toolCall?.function?.name || "")}
363
- </div>
364
- ) : (
365
- <Spinner size="xs" />
376
+ <div className="flex items-center transition-transform group-hover:scale-110">
377
+ {isExpanded ? (
378
+ <ChevronDown
379
+ size={14}
380
+ strokeWidth={1.5}
381
+ className="text-gray-500"
382
+ />
383
+ ) : (
384
+ <ChevronRight
385
+ size={14}
386
+ strokeWidth={1.5}
387
+ className="text-gray-500"
388
+ />
389
+ )}
390
+ </div>
391
+ {isCompleted ? (
392
+ <div
393
+ className={`flex items-center transition-all ${toolCall.function?.error ? "text-red-500" : "text-green-600"}`}
394
+ >
395
+ {getToolIcon(toolCall?.function?.name || "")}
396
+ </div>
397
+ ) : finalApprovalInfo && !hasApprovalStatus ? (
398
+ <div className="flex items-center text-amber-600 transition-all">
399
+ {getToolIcon(toolCall?.function?.name || "")}
400
+ </div>
401
+ ) : finished ? (
402
+ <div className="flex items-center text-gray-400 opacity-60 transition-all">
403
+ {getToolIcon(toolCall?.function?.name || "")}
404
+ </div>
405
+ ) : (
406
+ <Spinner size="xs" />
407
+ )}
408
+ <div className="inline-flex flex-1 items-center gap-2">
409
+ <span
410
+ className={`font-medium transition-colors ${toolCall.function?.error ? "text-red-600" : ""}`}
411
+ >
412
+ {/* Show clean function name without approval suffix */}
413
+ {(
414
+ originalFunctionName ||
415
+ toolCall?.function?.name ||
416
+ "tool call"
417
+ )
418
+ .replace(" (approved)", "")
419
+ .replace(" (rejected)", "")
420
+ .replace(" (pending approval)", "")}
421
+ {toolCall.function?.error && (
422
+ <span className="ml-1 text-red-500">(error)</span>
366
423
  )}
367
- <div className="inline-flex items-center gap-2">
368
- <span
369
- className={`${toolCall.function?.error ? "text-red-500" : "hover:text-gray-700"} cursor-pointer`}
370
- >
371
- {/* Show clean function name without approval suffix */}
372
- {(
373
- originalFunctionName ||
374
- toolCall?.function?.name ||
375
- "tool call"
376
- )
377
- .replace(" (approved)", "")
378
- .replace(" (rejected)", "")
379
- .replace(" (pending approval)", "")}
380
- {toolCall.function?.error && " (error)"}
381
- {finalApprovalInfo && isApproved && (
382
- <span className="ml-2 text-xs font-medium text-green-600">
383
- ✓ Approved
384
- </span>
385
- )}
386
- {finalApprovalInfo && isRejected && (
387
- <span className="ml-2 text-xs font-medium text-red-600">
388
- ✗ Rejected
389
- </span>
390
- )}
391
- {finalApprovalInfo && isPending && (
392
- <span className="ml-2 text-xs font-medium text-amber-600">
393
- ⏸ Pending approval
394
- </span>
395
- )}
424
+ {finalApprovalInfo && isApproved && (
425
+ <span className="ml-2 inline-flex items-center gap-1 rounded-full bg-green-100 px-2 py-0.5 text-[10px] font-semibold text-green-700">
426
+ <span>✓</span> Approved
396
427
  </span>
397
- </div>
398
- </div>
399
- </PopoverTrigger>
400
- <PopoverContent
401
- className="w-[450px] p-0"
402
- align="start"
403
- side="bottom"
404
- sideOffset={8}
405
- onMouseDown={(e) => e.stopPropagation()}
406
- onClick={(e) => e.stopPropagation()}
407
- >
408
- <ToolCallPopover
409
- toolCall={toolCall}
410
- result={toolResult}
411
- onClose={() => {
412
- setOpenPopovers((prev) => ({
413
- ...prev,
414
- [popoverKey]: false,
415
- }));
416
- }}
417
- />
418
- </PopoverContent>
419
- </Popover>
428
+ )}
429
+ {finalApprovalInfo && isRejected && (
430
+ <span className="ml-2 inline-flex items-center gap-1 rounded-full bg-red-100 px-2 py-0.5 text-[10px] font-semibold text-red-700">
431
+ <span>✗</span> Rejected
432
+ </span>
433
+ )}
434
+ {finalApprovalInfo && isPending && (
435
+ <span className="ml-2 inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 text-[10px] font-semibold text-amber-700">
436
+ <span>⏸</span> Pending approval
437
+ </span>
438
+ )}
439
+ </span>
440
+ </div>
441
+ </div>
442
+ {isExpanded && (
443
+ <ToolCallDetails toolCall={toolCall} result={toolResult} />
444
+ )}
420
445
  {!isCompleted && finalApprovalInfo && !hasApprovalStatus && (
421
- <div className="mt-2 rounded border">
422
- <div className="border-b bg-amber-50 p-3">
423
- <div className="flex items-start gap-2">
446
+ <div className="mt-2 overflow-hidden rounded-lg border border-amber-200 bg-gradient-to-br from-amber-50 to-amber-50/30 shadow-sm">
447
+ <div className="border-b border-amber-200/60 bg-amber-50/80 p-3">
448
+ <div className="flex items-start gap-3">
424
449
  <div
425
- className={`mt-1.5 h-2 w-2 rounded-full ${
450
+ className={`mt-1 h-2.5 w-2.5 rounded-full shadow-sm ${
426
451
  finalApprovalInfo.riskLevel === "high"
427
- ? "bg-red-500"
452
+ ? "bg-red-500 ring-2 ring-red-200"
428
453
  : finalApprovalInfo.riskLevel === "medium"
429
- ? "bg-amber-500"
430
- : "bg-green-500"
454
+ ? "bg-amber-500 ring-2 ring-amber-200"
455
+ : "bg-green-500 ring-2 ring-green-200"
431
456
  }`}
432
457
  />
433
- <div>
434
- <div className="mb-1 text-xs font-medium text-gray-900">
458
+ <div className="flex-1">
459
+ <div className="mb-1.5 text-xs font-semibold text-gray-900">
435
460
  Action requires approval
436
461
  </div>
437
- <div className="text-xs text-gray-700">
462
+ <div className="text-xs leading-relaxed text-gray-700">
438
463
  {finalApprovalInfo.summary}
439
464
  </div>
440
465
  {finalApprovalInfo.riskLevel && (
441
466
  <div
442
- className={`mt-1 text-xs font-medium ${
467
+ className={`mt-2 inline-flex items-center gap-1.5 rounded-full px-2 py-1 text-[10px] font-semibold ${
443
468
  finalApprovalInfo.riskLevel === "high"
444
- ? "text-red-600"
469
+ ? "bg-red-100 text-red-700"
445
470
  : finalApprovalInfo.riskLevel === "medium"
446
- ? "text-amber-600"
447
- : "text-green-600"
471
+ ? "bg-amber-100 text-amber-700"
472
+ : "bg-green-100 text-green-700"
448
473
  }`}
449
474
  >
450
- Risk level: {finalApprovalInfo.riskLevel}
475
+ <span className="font-normal">Risk:</span>
476
+ <span className="uppercase">
477
+ {finalApprovalInfo.riskLevel}
478
+ </span>
451
479
  </div>
452
480
  )}
453
481
  </div>
454
482
  </div>
455
483
  </div>
456
- <div className="flex items-center justify-end gap-2 p-2">
484
+ <div className="flex items-center justify-end gap-2 bg-white/60 p-3">
457
485
  <Button
458
486
  size="sm"
459
487
  variant="secondary"
460
488
  onClick={async () => {
489
+ // Use the dbMessageId from AgentToolCall if available, otherwise fall back to messageId or prop
490
+ const actualMessageId = isAgentToolCall
491
+ ? originalToolCall.dbMessageId ||
492
+ originalToolCall.messageId
493
+ : messageId;
461
494
  console.log("🚫 Rejecting tool call:", {
462
495
  agentId: (window as any)?.currentAgentId,
463
- messageId: messageId,
496
+ messageId: actualMessageId,
464
497
  toolCallId: toolCall.id,
465
498
  });
466
499
  try {
467
500
  const result = await rejectToolCall({
468
501
  agentId: (window as any)?.currentAgentId,
469
- messageId: messageId,
502
+ messageId: actualMessageId,
470
503
  toolCallId: toolCall.id,
471
504
  });
472
505
  console.log("✅ Reject successful:", result);
@@ -474,7 +507,7 @@ export function ToolCallDisplay({
474
507
  "agent:toolApprovalResolved",
475
508
  {
476
509
  detail: {
477
- messageId: messageId,
510
+ messageId: actualMessageId,
478
511
  toolCallId: toolCall.id,
479
512
  approved: false,
480
513
  },
@@ -491,15 +524,20 @@ export function ToolCallDisplay({
491
524
  <Button
492
525
  size="sm"
493
526
  onClick={async () => {
527
+ // Use the dbMessageId from AgentToolCall if available, otherwise fall back to messageId or prop
528
+ const actualMessageId = isAgentToolCall
529
+ ? originalToolCall.dbMessageId ||
530
+ originalToolCall.messageId
531
+ : messageId;
494
532
  console.log("✅ Approving tool call:", {
495
533
  agentId: (window as any)?.currentAgentId,
496
- messageId: messageId,
534
+ messageId: actualMessageId,
497
535
  toolCallId: toolCall.id,
498
536
  });
499
537
  try {
500
538
  const result = await approveToolCall({
501
539
  agentId: (window as any)?.currentAgentId,
502
- messageId: messageId,
540
+ messageId: actualMessageId,
503
541
  toolCallId: toolCall.id,
504
542
  });
505
543
  console.log("✅ Approve successful:", result);
@@ -507,15 +545,18 @@ export function ToolCallDisplay({
507
545
  "agent:toolApprovalResolved",
508
546
  {
509
547
  detail: {
510
- messageId: messageId,
548
+ messageId: actualMessageId,
511
549
  toolCallId: toolCall.id,
512
550
  approved: true,
513
551
  },
514
552
  } as any,
515
553
  );
516
554
  window.dispatchEvent(ev);
517
- } catch (error) {
555
+ } catch (error: any) {
518
556
  console.error("❌ Approve failed:", error);
557
+ alert(
558
+ `Failed to approve: ${error?.message || "Unknown error"}`,
559
+ );
519
560
  }
520
561
  }}
521
562
  >