@alquimia-ai/ui 2.2.4 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -3,6 +3,7 @@ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, Al
3
3
  export { T as Toast, a as ToastAction, b as ToastActionElement, c as ToastClose, d as ToastDescription, e as ToastProps, f as ToastProvider, g as ToastTitle, h as ToastViewport } from './toast-DEc6eGUE.mjs';
4
4
  export { CardImageWithHeadingAndDescriptionAvatarHorizontal, CardImageWithHeadingAndDescriptionHorizontal, CardWithImageHeadingDescriptionAvatarProps, CardWithImageHeadingDescriptionAvatarVertical, CardWithImageHeadingDescriptionProps, CardWithImageHeadingDescriptionVertical, Hero, HeroContent, HeroContentProps, HeroProps, MessagesWindow, QueryBox } from './components/templates/index.mjs';
5
5
  export { Assistant, AssistantInput, AssistantMessageArea, RatingDialog, SpeechToText, Whisper } from './components/organisms/index.mjs';
6
+ export { T as ToolApprovalCard, a as ToolApprovalCardProps, b as ToolApprovalView } from './tool-approval-K8aLzb1_.mjs';
6
7
  export { AssistantButton, CallOut, CallOutActions, CallOutDate, CallOutMessage, CallOutProps, CallOutResponse, Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, PageContainer, RatingComment, RatingStars, RatingThumbs, Sidebar, SidebarFooter, SidebarItem, SidebarProps, SonnerToaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, navigationMenuTriggerStyle } from './components/molecules/index.mjs';
7
8
  export { reducer, toast, useDocumentReader, useTextStreaming, useToast } from './components/hooks/index.mjs';
8
9
  export { blobToBase64, cn, getCookies, getErrorMessage, hasToolResult, parseTextToSpeech, truncateString } from './lib/index.mjs';
@@ -35,6 +36,7 @@ import 'react-day-picker';
35
36
  import '@radix-ui/react-toast';
36
37
  import 'ai';
37
38
  import '@alquimia-ai/tools/sdk';
39
+ import '@alquimia-ai/tools/hooks';
38
40
  import 'lucide-react';
39
41
  import 'embla-carousel-react';
40
42
  import '@radix-ui/react-navigation-menu';
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, Al
3
3
  export { T as Toast, a as ToastAction, b as ToastActionElement, c as ToastClose, d as ToastDescription, e as ToastProps, f as ToastProvider, g as ToastTitle, h as ToastViewport } from './toast-DEc6eGUE.js';
4
4
  export { CardImageWithHeadingAndDescriptionAvatarHorizontal, CardImageWithHeadingAndDescriptionHorizontal, CardWithImageHeadingDescriptionAvatarProps, CardWithImageHeadingDescriptionAvatarVertical, CardWithImageHeadingDescriptionProps, CardWithImageHeadingDescriptionVertical, Hero, HeroContent, HeroContentProps, HeroProps, MessagesWindow, QueryBox } from './components/templates/index.js';
5
5
  export { Assistant, AssistantInput, AssistantMessageArea, RatingDialog, SpeechToText, Whisper } from './components/organisms/index.js';
6
+ export { T as ToolApprovalCard, a as ToolApprovalCardProps, b as ToolApprovalView } from './tool-approval-K8aLzb1_.js';
6
7
  export { AssistantButton, CallOut, CallOutActions, CallOutDate, CallOutMessage, CallOutProps, CallOutResponse, Carousel, CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, PageContainer, RatingComment, RatingStars, RatingThumbs, Sidebar, SidebarFooter, SidebarItem, SidebarProps, SonnerToaster, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, navigationMenuTriggerStyle } from './components/molecules/index.js';
7
8
  export { reducer, toast, useDocumentReader, useTextStreaming, useToast } from './components/hooks/index.js';
8
9
  export { blobToBase64, cn, getCookies, getErrorMessage, hasToolResult, parseTextToSpeech, truncateString } from './lib/index.js';
@@ -35,6 +36,7 @@ import 'react-day-picker';
35
36
  import '@radix-ui/react-toast';
36
37
  import 'ai';
37
38
  import '@alquimia-ai/tools/sdk';
39
+ import '@alquimia-ai/tools/hooks';
38
40
  import 'lucide-react';
39
41
  import 'embla-carousel-react';
40
42
  import '@radix-ui/react-navigation-menu';
package/dist/index.js CHANGED
@@ -823,6 +823,9 @@ __export(src_exports, {
823
823
  Toggle: function() {
824
824
  return Toggle;
825
825
  },
826
+ ToolApprovalCard: function() {
827
+ return ToolApprovalCard;
828
+ },
826
829
  Tooltip: function() {
827
830
  return Tooltip2;
828
831
  },
@@ -4651,6 +4654,197 @@ function RatingDialog(param) {
4651
4654
  })
4652
4655
  });
4653
4656
  }
4657
+ // src/components/organisms/tool-approval.tsx
4658
+ var React38 = __toESM(require("react"));
4659
+ var import_lucide_react19 = require("lucide-react");
4660
+ var import_jsx_runtime55 = require("react/jsx-runtime");
4661
+ function formatArguments(args) {
4662
+ if (args === null || args === void 0) return null;
4663
+ if (typeof args === "string") return args;
4664
+ try {
4665
+ return JSON.stringify(args, null, 2);
4666
+ } catch (e) {
4667
+ return String(args);
4668
+ }
4669
+ }
4670
+ function blockedMessage(approval, channelName) {
4671
+ var _approval_lastResult;
4672
+ var outcome = (_approval_lastResult = approval.lastResult) === null || _approval_lastResult === void 0 ? void 0 : _approval_lastResult.outcome;
4673
+ if (approval.channelOwned || outcome === "wrong-channel") {
4674
+ return "This approval has to be answered in ".concat(channelName !== null && channelName !== void 0 ? channelName : "the channel the conversation came from", ". It can't be answered here.");
4675
+ }
4676
+ switch(outcome){
4677
+ case "already-decided":
4678
+ return "Someone else already answered this request. Waiting for the agent to continue.";
4679
+ case "not-pending":
4680
+ return "This request is no longer waiting for a decision.";
4681
+ case "not-found":
4682
+ return "This conversation has ended, so the request can no longer be answered.";
4683
+ case "forbidden":
4684
+ return "You don't have permission to answer this request.";
4685
+ default:
4686
+ return null;
4687
+ }
4688
+ }
4689
+ function ToolApprovalCard(param) {
4690
+ var approval = param.approval, onDecide = param.onDecide, channelName = param.channelName, className = param.className;
4691
+ var _React38_useState = _sliced_to_array(React38.useState(false), 2), rejecting = _React38_useState[0], setRejecting = _React38_useState[1];
4692
+ var _React38_useState1 = _sliced_to_array(React38.useState(""), 2), reason = _React38_useState1[0], setReason = _React38_useState1[1];
4693
+ var args = formatArguments(approval.arguments);
4694
+ var _approval_toolName;
4695
+ var toolLabel = (_approval_toolName = approval.toolName) !== null && _approval_toolName !== void 0 ? _approval_toolName : "a tool";
4696
+ var submitting = approval.status === "submitting";
4697
+ var settled = approval.status === "approved" || approval.status === "rejected";
4698
+ var blocked = !settled && !submitting && !approval.canAnswer ? blockedMessage(approval, channelName) : null;
4699
+ var failed = !settled && !submitting && approval.canAnswer && approval.lastResult && approval.lastResult.outcome !== "accepted" ? approval.lastResult : null;
4700
+ var decide = function(approved) {
4701
+ var said = reason.trim();
4702
+ void onDecide(approval.controlId, approved, approved || !said ? void 0 : said);
4703
+ };
4704
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("section", {
4705
+ "aria-label": "Approval request for ".concat(toolLabel),
4706
+ "data-status": approval.status,
4707
+ className: cn("alq--tool-approval w-full max-w-[95%] rounded-2xl border bg-card p-4 shadow-sm", settled ? "border-border/60" : "border-amber-500/50", className),
4708
+ children: [
4709
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("header", {
4710
+ className: "flex items-start gap-2",
4711
+ children: [
4712
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react19.ShieldAlert, {
4713
+ "aria-hidden": true,
4714
+ className: cn("mt-0.5 h-4 w-4 shrink-0", settled ? "text-muted-foreground" : "text-amber-500")
4715
+ }),
4716
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", {
4717
+ className: "min-w-0 flex-1",
4718
+ children: [
4719
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", {
4720
+ className: "text-sm font-medium text-foreground",
4721
+ children: settled ? "Approval request" : "The agent needs your approval"
4722
+ }),
4723
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("p", {
4724
+ className: "text-sm text-muted-foreground",
4725
+ children: [
4726
+ "Run ",
4727
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("code", {
4728
+ className: "rounded bg-muted px-1 py-0.5 font-mono text-xs text-foreground",
4729
+ children: toolLabel
4730
+ })
4731
+ ]
4732
+ })
4733
+ ]
4734
+ }),
4735
+ settled && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", {
4736
+ className: cn("flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium", approval.status === "approved" ? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400" : "bg-destructive/10 text-destructive"),
4737
+ children: [
4738
+ approval.status === "approved" ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react19.Check, {
4739
+ className: "h-3 w-3"
4740
+ }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react19.X, {
4741
+ className: "h-3 w-3"
4742
+ }),
4743
+ approval.status === "approved" ? "Approved" : "Rejected",
4744
+ approval.decidedHere ? " by you" : " elsewhere"
4745
+ ]
4746
+ })
4747
+ ]
4748
+ }),
4749
+ args !== null && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("pre", {
4750
+ "aria-label": "Arguments",
4751
+ className: "mt-3 max-h-48 overflow-auto rounded-lg bg-muted/60 p-3 font-mono text-xs text-foreground",
4752
+ children: args
4753
+ }),
4754
+ settled && approval.status === "rejected" && approval.reason && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("p", {
4755
+ className: "mt-3 text-sm text-muted-foreground",
4756
+ children: [
4757
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", {
4758
+ className: "font-medium text-foreground",
4759
+ children: "Reason:"
4760
+ }),
4761
+ " ",
4762
+ approval.reason
4763
+ ]
4764
+ }),
4765
+ blocked && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", {
4766
+ role: "status",
4767
+ className: "mt-3 text-sm text-muted-foreground",
4768
+ children: blocked
4769
+ }),
4770
+ failed && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("p", {
4771
+ role: "alert",
4772
+ className: "mt-3 text-sm text-destructive",
4773
+ children: [
4774
+ "Couldn't send your decision",
4775
+ failed.detail ? ": ".concat(failed.detail) : ".",
4776
+ " Try again."
4777
+ ]
4778
+ }),
4779
+ !settled && (submitting || approval.canAnswer) && /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", {
4780
+ className: "mt-3 flex flex-col gap-2",
4781
+ children: [
4782
+ rejecting && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Textarea, {
4783
+ "aria-label": "Reason for rejecting (optional)",
4784
+ placeholder: "Reason for rejecting (optional)",
4785
+ value: reason,
4786
+ disabled: submitting,
4787
+ onChange: function(e) {
4788
+ return setReason(e.target.value);
4789
+ },
4790
+ className: "min-h-[64px] text-sm"
4791
+ }),
4792
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", {
4793
+ className: "flex flex-wrap items-center justify-end gap-2",
4794
+ children: [
4795
+ submitting && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_lucide_react19.Loader2, {
4796
+ "aria-label": "Sending decision",
4797
+ className: "h-4 w-4 animate-spin text-muted-foreground"
4798
+ }),
4799
+ rejecting ? /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, {
4800
+ children: [
4801
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Button, {
4802
+ size: "sm",
4803
+ variant: "ghost",
4804
+ disabled: submitting,
4805
+ onClick: function() {
4806
+ return setRejecting(false);
4807
+ },
4808
+ children: "Cancel"
4809
+ }),
4810
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Button, {
4811
+ size: "sm",
4812
+ variant: "destructive",
4813
+ disabled: submitting,
4814
+ onClick: function() {
4815
+ return decide(false);
4816
+ },
4817
+ children: "Reject"
4818
+ })
4819
+ ]
4820
+ }) : /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_jsx_runtime55.Fragment, {
4821
+ children: [
4822
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Button, {
4823
+ size: "sm",
4824
+ variant: "outline",
4825
+ disabled: submitting,
4826
+ onClick: function() {
4827
+ return setRejecting(true);
4828
+ },
4829
+ children: "Reject\u2026"
4830
+ }),
4831
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Button, {
4832
+ size: "sm",
4833
+ disabled: submitting,
4834
+ onClick: function() {
4835
+ return decide(true);
4836
+ },
4837
+ children: "Approve"
4838
+ })
4839
+ ]
4840
+ })
4841
+ ]
4842
+ })
4843
+ ]
4844
+ })
4845
+ ]
4846
+ });
4847
+ }
4654
4848
  // src/types/type.ts
4655
4849
  var EditingStatus = /* @__PURE__ */ function(EditingStatus2) {
4656
4850
  EditingStatus2["EDITING"] = "EDITING";
@@ -4658,24 +4852,24 @@ var EditingStatus = /* @__PURE__ */ function(EditingStatus2) {
4658
4852
  return EditingStatus2;
4659
4853
  }(EditingStatus || {});
4660
4854
  // src/providers/alquimia-ui-provider.tsx
4661
- var React38 = __toESM(require("react"));
4662
- var import_jsx_runtime55 = require("react/jsx-runtime");
4855
+ var React39 = __toESM(require("react"));
4856
+ var import_jsx_runtime56 = require("react/jsx-runtime");
4663
4857
  function AlquimiaUIProvider(param) {
4664
4858
  var _param_defaultMode = param.defaultMode, defaultMode = _param_defaultMode === void 0 ? "system" : _param_defaultMode, children = param.children;
4665
- var _React38_useState = _sliced_to_array(React38.useState(function() {
4859
+ var _React39_useState = _sliced_to_array(React39.useState(function() {
4666
4860
  if (defaultMode !== "system") return defaultMode;
4667
4861
  if (typeof window !== "undefined") {
4668
4862
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
4669
4863
  }
4670
4864
  return "light";
4671
- }), 2), resolvedTheme = _React38_useState[0], setResolvedTheme = _React38_useState[1];
4865
+ }), 2), resolvedTheme = _React39_useState[0], setResolvedTheme = _React39_useState[1];
4672
4866
  function applyTheme(theme) {
4673
4867
  if (typeof document !== "undefined") {
4674
4868
  document.documentElement.classList.toggle("dark", theme === "dark");
4675
4869
  }
4676
4870
  setResolvedTheme(theme);
4677
4871
  }
4678
- React38.useEffect(function() {
4872
+ React39.useEffect(function() {
4679
4873
  if (defaultMode !== "system") {
4680
4874
  applyTheme(defaultMode);
4681
4875
  return;
@@ -4692,7 +4886,7 @@ function AlquimiaUIProvider(param) {
4692
4886
  }, [
4693
4887
  defaultMode
4694
4888
  ]);
4695
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(ThemeContext.Provider, {
4889
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ThemeContext.Provider, {
4696
4890
  value: {
4697
4891
  theme: resolvedTheme,
4698
4892
  setTheme: applyTheme