@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.
@@ -2633,8 +2633,8 @@ var coreUiRegistry = {
2633
2633
  Link: LinkNode
2634
2634
  };
2635
2635
  // src/components/genui/assistant-chat.tsx
2636
- import * as React43 from "react";
2637
- import { Check as Check3 } from "lucide-react";
2636
+ import * as React44 from "react";
2637
+ import { Check as Check4 } from "lucide-react";
2638
2638
  // src/components/organisms/assistant.tsx
2639
2639
  import * as React42 from "react";
2640
2640
  import { useCallback as useCallback3, useEffect as useEffect10, useRef as useRef2, useState as useState13 } from "react";
@@ -4394,17 +4394,208 @@ var AssistantInput = React42.forwardRef(function(_param, ref) {
4394
4394
  }));
4395
4395
  });
4396
4396
  AssistantInput.displayName = "AssistantInput";
4397
+ // src/components/organisms/tool-approval.tsx
4398
+ import * as React43 from "react";
4399
+ import { Check as Check3, Loader2 as Loader22, ShieldAlert, X as X3 } from "lucide-react";
4400
+ import { Fragment as Fragment8, jsx as jsx53, jsxs as jsxs27 } from "react/jsx-runtime";
4401
+ function formatArguments(args) {
4402
+ if (args === null || args === void 0) return null;
4403
+ if (typeof args === "string") return args;
4404
+ try {
4405
+ return JSON.stringify(args, null, 2);
4406
+ } catch (e) {
4407
+ return String(args);
4408
+ }
4409
+ }
4410
+ function blockedMessage(approval, channelName) {
4411
+ var _approval_lastResult;
4412
+ var outcome = (_approval_lastResult = approval.lastResult) === null || _approval_lastResult === void 0 ? void 0 : _approval_lastResult.outcome;
4413
+ if (approval.channelOwned || outcome === "wrong-channel") {
4414
+ 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.");
4415
+ }
4416
+ switch(outcome){
4417
+ case "already-decided":
4418
+ return "Someone else already answered this request. Waiting for the agent to continue.";
4419
+ case "not-pending":
4420
+ return "This request is no longer waiting for a decision.";
4421
+ case "not-found":
4422
+ return "This conversation has ended, so the request can no longer be answered.";
4423
+ case "forbidden":
4424
+ return "You don't have permission to answer this request.";
4425
+ default:
4426
+ return null;
4427
+ }
4428
+ }
4429
+ function ToolApprovalCard(param) {
4430
+ var approval = param.approval, onDecide = param.onDecide, channelName = param.channelName, className = param.className;
4431
+ var _React43_useState = _sliced_to_array(React43.useState(false), 2), rejecting = _React43_useState[0], setRejecting = _React43_useState[1];
4432
+ var _React43_useState1 = _sliced_to_array(React43.useState(""), 2), reason = _React43_useState1[0], setReason = _React43_useState1[1];
4433
+ var args = formatArguments(approval.arguments);
4434
+ var _approval_toolName;
4435
+ var toolLabel = (_approval_toolName = approval.toolName) !== null && _approval_toolName !== void 0 ? _approval_toolName : "a tool";
4436
+ var submitting = approval.status === "submitting";
4437
+ var settled = approval.status === "approved" || approval.status === "rejected";
4438
+ var blocked = !settled && !submitting && !approval.canAnswer ? blockedMessage(approval, channelName) : null;
4439
+ var failed = !settled && !submitting && approval.canAnswer && approval.lastResult && approval.lastResult.outcome !== "accepted" ? approval.lastResult : null;
4440
+ var decide = function(approved) {
4441
+ var said = reason.trim();
4442
+ void onDecide(approval.controlId, approved, approved || !said ? void 0 : said);
4443
+ };
4444
+ return /* @__PURE__ */ jsxs27("section", {
4445
+ "aria-label": "Approval request for ".concat(toolLabel),
4446
+ "data-status": approval.status,
4447
+ 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),
4448
+ children: [
4449
+ /* @__PURE__ */ jsxs27("header", {
4450
+ className: "flex items-start gap-2",
4451
+ children: [
4452
+ /* @__PURE__ */ jsx53(ShieldAlert, {
4453
+ "aria-hidden": true,
4454
+ className: cn("mt-0.5 h-4 w-4 shrink-0", settled ? "text-muted-foreground" : "text-amber-500")
4455
+ }),
4456
+ /* @__PURE__ */ jsxs27("div", {
4457
+ className: "min-w-0 flex-1",
4458
+ children: [
4459
+ /* @__PURE__ */ jsx53("p", {
4460
+ className: "text-sm font-medium text-foreground",
4461
+ children: settled ? "Approval request" : "The agent needs your approval"
4462
+ }),
4463
+ /* @__PURE__ */ jsxs27("p", {
4464
+ className: "text-sm text-muted-foreground",
4465
+ children: [
4466
+ "Run ",
4467
+ /* @__PURE__ */ jsx53("code", {
4468
+ className: "rounded bg-muted px-1 py-0.5 font-mono text-xs text-foreground",
4469
+ children: toolLabel
4470
+ })
4471
+ ]
4472
+ })
4473
+ ]
4474
+ }),
4475
+ settled && /* @__PURE__ */ jsxs27("span", {
4476
+ 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"),
4477
+ children: [
4478
+ approval.status === "approved" ? /* @__PURE__ */ jsx53(Check3, {
4479
+ className: "h-3 w-3"
4480
+ }) : /* @__PURE__ */ jsx53(X3, {
4481
+ className: "h-3 w-3"
4482
+ }),
4483
+ approval.status === "approved" ? "Approved" : "Rejected",
4484
+ approval.decidedHere ? " by you" : " elsewhere"
4485
+ ]
4486
+ })
4487
+ ]
4488
+ }),
4489
+ args !== null && /* @__PURE__ */ jsx53("pre", {
4490
+ "aria-label": "Arguments",
4491
+ className: "mt-3 max-h-48 overflow-auto rounded-lg bg-muted/60 p-3 font-mono text-xs text-foreground",
4492
+ children: args
4493
+ }),
4494
+ settled && approval.status === "rejected" && approval.reason && /* @__PURE__ */ jsxs27("p", {
4495
+ className: "mt-3 text-sm text-muted-foreground",
4496
+ children: [
4497
+ /* @__PURE__ */ jsx53("span", {
4498
+ className: "font-medium text-foreground",
4499
+ children: "Reason:"
4500
+ }),
4501
+ " ",
4502
+ approval.reason
4503
+ ]
4504
+ }),
4505
+ blocked && /* @__PURE__ */ jsx53("p", {
4506
+ role: "status",
4507
+ className: "mt-3 text-sm text-muted-foreground",
4508
+ children: blocked
4509
+ }),
4510
+ failed && /* @__PURE__ */ jsxs27("p", {
4511
+ role: "alert",
4512
+ className: "mt-3 text-sm text-destructive",
4513
+ children: [
4514
+ "Couldn't send your decision",
4515
+ failed.detail ? ": ".concat(failed.detail) : ".",
4516
+ " Try again."
4517
+ ]
4518
+ }),
4519
+ !settled && (submitting || approval.canAnswer) && /* @__PURE__ */ jsxs27("div", {
4520
+ className: "mt-3 flex flex-col gap-2",
4521
+ children: [
4522
+ rejecting && /* @__PURE__ */ jsx53(Textarea, {
4523
+ "aria-label": "Reason for rejecting (optional)",
4524
+ placeholder: "Reason for rejecting (optional)",
4525
+ value: reason,
4526
+ disabled: submitting,
4527
+ onChange: function(e) {
4528
+ return setReason(e.target.value);
4529
+ },
4530
+ className: "min-h-[64px] text-sm"
4531
+ }),
4532
+ /* @__PURE__ */ jsxs27("div", {
4533
+ className: "flex flex-wrap items-center justify-end gap-2",
4534
+ children: [
4535
+ submitting && /* @__PURE__ */ jsx53(Loader22, {
4536
+ "aria-label": "Sending decision",
4537
+ className: "h-4 w-4 animate-spin text-muted-foreground"
4538
+ }),
4539
+ rejecting ? /* @__PURE__ */ jsxs27(Fragment8, {
4540
+ children: [
4541
+ /* @__PURE__ */ jsx53(Button, {
4542
+ size: "sm",
4543
+ variant: "ghost",
4544
+ disabled: submitting,
4545
+ onClick: function() {
4546
+ return setRejecting(false);
4547
+ },
4548
+ children: "Cancel"
4549
+ }),
4550
+ /* @__PURE__ */ jsx53(Button, {
4551
+ size: "sm",
4552
+ variant: "destructive",
4553
+ disabled: submitting,
4554
+ onClick: function() {
4555
+ return decide(false);
4556
+ },
4557
+ children: "Reject"
4558
+ })
4559
+ ]
4560
+ }) : /* @__PURE__ */ jsxs27(Fragment8, {
4561
+ children: [
4562
+ /* @__PURE__ */ jsx53(Button, {
4563
+ size: "sm",
4564
+ variant: "outline",
4565
+ disabled: submitting,
4566
+ onClick: function() {
4567
+ return setRejecting(true);
4568
+ },
4569
+ children: "Reject\u2026"
4570
+ }),
4571
+ /* @__PURE__ */ jsx53(Button, {
4572
+ size: "sm",
4573
+ disabled: submitting,
4574
+ onClick: function() {
4575
+ return decide(true);
4576
+ },
4577
+ children: "Approve"
4578
+ })
4579
+ ]
4580
+ })
4581
+ ]
4582
+ })
4583
+ ]
4584
+ })
4585
+ ]
4586
+ });
4587
+ }
4397
4588
  // src/components/genui/assistant-chat.tsx
4398
- import { jsx as jsx53, jsxs as jsxs27 } from "react/jsx-runtime";
4589
+ import { jsx as jsx54, jsxs as jsxs28 } from "react/jsx-runtime";
4399
4590
  function TypingDots() {
4400
- return /* @__PURE__ */ jsx53("div", {
4591
+ return /* @__PURE__ */ jsx54("div", {
4401
4592
  className: "flex w-fit items-center gap-1.5 rounded-2xl rounded-bl-md border border-border/60 bg-card px-4 py-3 shadow-sm",
4402
4593
  children: [
4403
4594
  0,
4404
4595
  1,
4405
4596
  2
4406
4597
  ].map(function(i) {
4407
- return /* @__PURE__ */ jsx53("span", {
4598
+ return /* @__PURE__ */ jsx54("span", {
4408
4599
  className: "h-2 w-2 animate-bounce rounded-full bg-primary",
4409
4600
  style: {
4410
4601
  animationDelay: "".concat(i * 0.15, "s"),
@@ -4415,11 +4606,15 @@ function TypingDots() {
4415
4606
  });
4416
4607
  }
4417
4608
  function AssistantChat(param) {
4418
- var alquimia = param.alquimia, _param_registry = param.registry, registry = _param_registry === void 0 ? coreUiRegistry : _param_registry, conversationId = param.conversationId, _param_placeholder = param.placeholder, placeholder = _param_placeholder === void 0 ? "Ask the agent to build something\u2026" : _param_placeholder, _param_suggestions = param.suggestions, suggestions = _param_suggestions === void 0 ? [] : _param_suggestions, className = param.className, thinkIndicator = param.thinkIndicator;
4419
- var endRef = React43.useRef(null);
4420
- var messages = alquimia.messages, input = alquimia.input, handleInputChange = alquimia.handleInputChange, handleSubmit = alquimia.handleSubmit, handleLoadingCancel = alquimia.handleLoadingCancel, isLoading = alquimia.isLoading, isMessageStreaming = alquimia.isMessageStreaming, streamingMessageId = alquimia.streamingMessageId, genui = alquimia.genui;
4609
+ var alquimia = param.alquimia, _param_registry = param.registry, registry = _param_registry === void 0 ? coreUiRegistry : _param_registry, conversationId = param.conversationId, _param_placeholder = param.placeholder, placeholder = _param_placeholder === void 0 ? "Ask the agent to build something\u2026" : _param_placeholder, _param_suggestions = param.suggestions, suggestions = _param_suggestions === void 0 ? [] : _param_suggestions, className = param.className, thinkIndicator = param.thinkIndicator, approvalChannelName = param.approvalChannelName;
4610
+ var endRef = React44.useRef(null);
4611
+ var messages = alquimia.messages, input = alquimia.input, handleInputChange = alquimia.handleInputChange, handleSubmit = alquimia.handleSubmit, handleLoadingCancel = alquimia.handleLoadingCancel, isLoading = alquimia.isLoading, isMessageStreaming = alquimia.isMessageStreaming, streamingMessageId = alquimia.streamingMessageId, genui = alquimia.genui, toolApprovals = alquimia.toolApprovals, approveTool = alquimia.approveTool;
4421
4612
  var _genui_surfaces;
4422
4613
  var surfaces = (_genui_surfaces = genui === null || genui === void 0 ? void 0 : genui.surfaces) !== null && _genui_surfaces !== void 0 ? _genui_surfaces : [];
4614
+ var approvals = toolApprovals !== null && toolApprovals !== void 0 ? toolApprovals : [];
4615
+ var awaitingApproval = approvals.some(function(a) {
4616
+ return a.status === "pending" || a.status === "submitting";
4617
+ });
4423
4618
  var _genui_awaitingUser;
4424
4619
  var awaitingUser = (_genui_awaitingUser = genui === null || genui === void 0 ? void 0 : genui.awaitingUser) !== null && _genui_awaitingUser !== void 0 ? _genui_awaitingUser : false;
4425
4620
  var isBusy = !!(isLoading || isMessageStreaming);
@@ -4427,36 +4622,37 @@ function AssistantChat(param) {
4427
4622
  var _m_content;
4428
4623
  return m.role === "user" || m.role !== "system" && ((_m_content = m.content) !== null && _m_content !== void 0 ? _m_content : "").trim().length > 0;
4429
4624
  });
4430
- var isEmpty = !hasContent && surfaces.length === 0;
4431
- React43.useEffect(function() {
4625
+ var isEmpty = !hasContent && surfaces.length === 0 && approvals.length === 0;
4626
+ React44.useEffect(function() {
4432
4627
  var _endRef_current;
4433
4628
  (_endRef_current = endRef.current) === null || _endRef_current === void 0 ? void 0 : _endRef_current.scrollIntoView({
4434
4629
  behavior: "smooth"
4435
4630
  });
4436
4631
  }, [
4437
4632
  messages,
4438
- surfaces
4633
+ surfaces,
4634
+ approvals.length
4439
4635
  ]);
4440
4636
  var renderSurface = function(item) {
4441
- return /* @__PURE__ */ jsxs27("div", {
4637
+ return /* @__PURE__ */ jsxs28("div", {
4442
4638
  className: "my-3 flex flex-col items-start gap-1.5",
4443
4639
  children: [
4444
- /* @__PURE__ */ jsxs27("div", {
4640
+ /* @__PURE__ */ jsxs28("div", {
4445
4641
  className: cn("relative w-full max-w-[95%] rounded-2xl border border-border/60 bg-card p-5 shadow-sm duration-500 animate-in fade-in slide-in-from-bottom-2", item.submitted && "opacity-70"),
4446
4642
  children: [
4447
- item.submitted && /* @__PURE__ */ jsxs27("div", {
4643
+ item.submitted && /* @__PURE__ */ jsxs28("div", {
4448
4644
  className: "absolute right-3 top-3 z-10 flex items-center gap-1 rounded-full bg-emerald-500/10 px-2 py-0.5 text-xs font-medium text-emerald-600 dark:text-emerald-400",
4449
4645
  children: [
4450
- /* @__PURE__ */ jsx53(Check3, {
4646
+ /* @__PURE__ */ jsx54(Check4, {
4451
4647
  className: "h-3 w-3"
4452
4648
  }),
4453
4649
  item.dismissedWith ? "Skipped" : "Submitted"
4454
4650
  ]
4455
4651
  }),
4456
- /* @__PURE__ */ jsx53("div", {
4652
+ /* @__PURE__ */ jsx54("div", {
4457
4653
  className: cn(item.submitted && "pointer-events-none select-none"),
4458
4654
  "aria-disabled": item.submitted,
4459
- children: /* @__PURE__ */ jsx53(A2uiRenderer, {
4655
+ children: /* @__PURE__ */ jsx54(A2uiRenderer, {
4460
4656
  surface: item.surface,
4461
4657
  registry: registry,
4462
4658
  onAgentAction: genui ? genui.onAgentAction(item.controlId) : function() {}
@@ -4464,10 +4660,10 @@ function AssistantChat(param) {
4464
4660
  })
4465
4661
  ]
4466
4662
  }),
4467
- item.dismissedWith && /* @__PURE__ */ jsxs27("p", {
4663
+ item.dismissedWith && /* @__PURE__ */ jsxs28("p", {
4468
4664
  className: "alq--surface-dismissed max-w-[95%] pl-1 text-sm text-muted-foreground",
4469
4665
  children: [
4470
- /* @__PURE__ */ jsx53("span", {
4666
+ /* @__PURE__ */ jsx54("span", {
4471
4667
  className: "font-medium text-foreground",
4472
4668
  children: "You replied:"
4473
4669
  }),
@@ -4502,21 +4698,56 @@ function AssistantChat(param) {
4502
4698
  }
4503
4699
  }
4504
4700
  }
4701
+ var approvalsByCount = /* @__PURE__ */ new Map();
4702
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
4703
+ try {
4704
+ for(var _iterator1 = approvals[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
4705
+ var a = _step1.value;
4706
+ var _approvalsByCount_get;
4707
+ var arr1 = (_approvalsByCount_get = approvalsByCount.get(a.afterCount)) !== null && _approvalsByCount_get !== void 0 ? _approvalsByCount_get : [];
4708
+ arr1.push(a);
4709
+ approvalsByCount.set(a.afterCount, arr1);
4710
+ }
4711
+ } catch (err) {
4712
+ _didIteratorError1 = true;
4713
+ _iteratorError1 = err;
4714
+ } finally{
4715
+ try {
4716
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
4717
+ _iterator1.return();
4718
+ }
4719
+ } finally{
4720
+ if (_didIteratorError1) {
4721
+ throw _iteratorError1;
4722
+ }
4723
+ }
4724
+ }
4725
+ var renderApproval = function(approval) {
4726
+ return /* @__PURE__ */ jsx54("div", {
4727
+ className: "my-3 flex flex-col items-start",
4728
+ children: /* @__PURE__ */ jsx54(ToolApprovalCard, {
4729
+ approval: approval,
4730
+ onDecide: approveTool !== null && approveTool !== void 0 ? approveTool : function() {},
4731
+ channelName: approvalChannelName,
4732
+ className: "duration-500 animate-in fade-in slide-in-from-bottom-2"
4733
+ })
4734
+ }, "a-".concat(approval.controlId));
4735
+ };
4505
4736
  var interleave = function(afterIndex) {
4506
- var _byCount_get;
4507
- var nodes = ((_byCount_get = byCount.get(afterIndex)) !== null && _byCount_get !== void 0 ? _byCount_get : []).map(renderSurface);
4737
+ var _byCount_get, _approvalsByCount_get;
4738
+ var nodes = _to_consumable_array(((_byCount_get = byCount.get(afterIndex)) !== null && _byCount_get !== void 0 ? _byCount_get : []).map(renderSurface)).concat(_to_consumable_array(((_approvalsByCount_get = approvalsByCount.get(afterIndex)) !== null && _approvalsByCount_get !== void 0 ? _approvalsByCount_get : []).map(renderApproval)));
4508
4739
  if (afterIndex === 0 && isEmpty) {
4509
- nodes.unshift(/* @__PURE__ */ jsxs27("div", {
4740
+ nodes.unshift(/* @__PURE__ */ jsxs28("div", {
4510
4741
  className: "flex min-h-full flex-col items-center justify-center gap-4 py-16 text-center",
4511
4742
  children: [
4512
- /* @__PURE__ */ jsx53("p", {
4743
+ /* @__PURE__ */ jsx54("p", {
4513
4744
  className: "max-w-sm text-muted-foreground",
4514
4745
  children: "Ask the agent to build an interface."
4515
4746
  }),
4516
- /* @__PURE__ */ jsx53("div", {
4747
+ /* @__PURE__ */ jsx54("div", {
4517
4748
  className: "flex flex-col items-center gap-2",
4518
4749
  children: suggestions.map(function(s) {
4519
- return /* @__PURE__ */ jsx53("button", {
4750
+ return /* @__PURE__ */ jsx54("button", {
4520
4751
  type: "button",
4521
4752
  onClick: function() {
4522
4753
  return handleInputChange({
@@ -4590,20 +4821,20 @@ function AssistantChat(param) {
4590
4821
  return _ref.apply(this, arguments);
4591
4822
  };
4592
4823
  }();
4593
- return /* @__PURE__ */ jsxs27(Assistant, {
4824
+ return /* @__PURE__ */ jsxs28(Assistant, {
4594
4825
  className: cn("mx-auto flex h-full w-full max-w-2xl flex-col bg-transparent px-4", className),
4595
4826
  children: [
4596
- /* @__PURE__ */ jsx53(AssistantMessageArea, {
4827
+ /* @__PURE__ */ jsx54(AssistantMessageArea, {
4597
4828
  className: "bg-transparent",
4598
4829
  messages: messages,
4599
4830
  messagesEndRef: endRef,
4600
4831
  isLoading: !!isLoading,
4601
4832
  streamingMessageId: streamingMessageId !== null && streamingMessageId !== void 0 ? streamingMessageId : null,
4602
4833
  interleave: interleave,
4603
- awaitingUser: awaitingUser,
4604
- thinkIndicator: thinkIndicator !== null && thinkIndicator !== void 0 ? thinkIndicator : /* @__PURE__ */ jsx53(TypingDots, {})
4834
+ awaitingUser: awaitingUser || awaitingApproval,
4835
+ thinkIndicator: thinkIndicator !== null && thinkIndicator !== void 0 ? thinkIndicator : /* @__PURE__ */ jsx54(TypingDots, {})
4605
4836
  }),
4606
- /* @__PURE__ */ jsx53(AssistantInput, {
4837
+ /* @__PURE__ */ jsx54(AssistantInput, {
4607
4838
  className: "mb-5 mt-2 rounded-2xl border-border/60 bg-card/90 shadow-lg backdrop-blur",
4608
4839
  sendMessageFunc: onSubmit,
4609
4840
  isButtonDisabled: isBusy && !awaitingUser,