@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/README.md +27 -3
- package/dist/components/genui/index.d.mts +10 -1
- package/dist/components/genui/index.d.ts +10 -1
- package/dist/components/genui/index.js +261 -30
- package/dist/components/genui/index.js.map +1 -1
- package/dist/components/genui/index.mjs +261 -30
- package/dist/components/genui/index.mjs.map +1 -1
- package/dist/components/organisms/index.d.mts +2 -0
- package/dist/components/organisms/index.d.ts +2 -0
- package/dist/components/organisms/index.js +194 -0
- package/dist/components/organisms/index.js.map +1 -1
- package/dist/components/organisms/index.mjs +192 -1
- package/dist/components/organisms/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +200 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +198 -7
- package/dist/index.mjs.map +1 -1
- package/dist/tool-approval-K8aLzb1_.d.mts +26 -0
- package/dist/tool-approval-K8aLzb1_.d.ts +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@ It holds no runtime logic. State comes from [`@alquimia-ai/tools`](../tools) —
|
|
|
15
15
|
- [Theming](#theming)
|
|
16
16
|
- [Building a chat](#building-a-chat)
|
|
17
17
|
- [Chat organisms](#chat-organisms)
|
|
18
|
+
- [Tool approval](#tool-approval)
|
|
18
19
|
- [GenUI](#genui)
|
|
19
20
|
- [Speech](#speech)
|
|
20
21
|
- [Ratings](#ratings)
|
|
@@ -190,6 +191,29 @@ A form with autosizing textarea, drag-and-drop and slots.
|
|
|
190
191
|
|
|
191
192
|
---
|
|
192
193
|
|
|
194
|
+
## Tool approval
|
|
195
|
+
|
|
196
|
+
When the runtime parks a tool call for human approval, `useAlquimia` exposes the gate in `toolApprovals` and answers it with `approveTool`. `ToolApprovalCard` renders one: the tool name, its arguments, and Approve / Reject — rejecting takes an optional reason, which the runtime keeps in its audit trail.
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { ToolApprovalCard } from '@alquimia-ai/ui/components/organisms';
|
|
200
|
+
|
|
201
|
+
{alquimia.toolApprovals.map((approval) => (
|
|
202
|
+
<ToolApprovalCard
|
|
203
|
+
key={approval.controlId}
|
|
204
|
+
approval={approval}
|
|
205
|
+
onDecide={alquimia.approveTool}
|
|
206
|
+
channelName="WhatsApp"
|
|
207
|
+
/>
|
|
208
|
+
))}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The card follows `approval.status` rather than deciding anything itself, so a decision made by another operator or on the originating channel shows up as settled here too — "Approved by you" or "Approved elsewhere", with the reason for a rejection. When the gate can only be answered on its original channel, or the runtime already refused this client (already decided, no longer pending, not allowed), the buttons are replaced by an explanation; `channelName` names the channel in it, since the runtime's refusal does not.
|
|
212
|
+
|
|
213
|
+
`AssistantChat` does all of this for you when given the whole hook return: approvals render after the message they followed, the typing indicator is suppressed while one waits, and `approvalChannelName` is passed through to the card.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
193
217
|
## GenUI
|
|
194
218
|
|
|
195
219
|
The agent answers with a **component tree**, not markup. `@alquimia-ai/tools` validates it against a catalog; this package renders it.
|
|
@@ -204,7 +228,7 @@ const alquimia = useAlquimia({ assistantId, adapter, genui: { allow: 'all' } });
|
|
|
204
228
|
<AssistantChat alquimia={alquimia} conversationId={conversationId} />
|
|
205
229
|
```
|
|
206
230
|
|
|
207
|
-
`AssistantChat` is a thin composition of `AssistantMessageArea` + `AssistantInput` — it inherits markdown, streaming and error rendering rather than reimplementing them. Props: `alquimia` (required), `registry`, `conversationId`, `placeholder`, `suggestions`, `className`, `thinkIndicator`.
|
|
231
|
+
`AssistantChat` is a thin composition of `AssistantMessageArea` + `AssistantInput` — it inherits markdown, streaming and error rendering rather than reimplementing them. Props: `alquimia` (required), `registry`, `conversationId`, `placeholder`, `suggestions`, `className`, `thinkIndicator`, `approvalChannelName`. Pending tool approvals render in place — see [Tool approval](#tool-approval).
|
|
208
232
|
|
|
209
233
|
Lower level, when you own the shell:
|
|
210
234
|
|
|
@@ -293,7 +317,7 @@ import { Whisper, SpeechToText } from '@alquimia-ai/ui/components/organisms';
|
|
|
293
317
|
|
|
294
318
|
**Molecules** — `PageContainer`, `AlertDialog`, `AssistantButton`, `Carousel`, `NavigationMenu`, `Sidebar`, `Sonner`, `CallOut`, rating and document components.
|
|
295
319
|
|
|
296
|
-
**Organisms** — `Assistant`, `AssistantMessageArea`, `AssistantInput`, `Whisper`, `SpeechToText`, `RatingDialog`.
|
|
320
|
+
**Organisms** — `Assistant`, `AssistantMessageArea`, `AssistantInput`, `ToolApprovalCard`, `Whisper`, `SpeechToText`, `RatingDialog`.
|
|
297
321
|
|
|
298
322
|
**Templates** — `MessagesWindow`, `QueryBox`, `Hero`, `Cards`.
|
|
299
323
|
|
|
@@ -324,7 +348,7 @@ import { Whisper, SpeechToText } from '@alquimia-ai/ui/components/organisms';
|
|
|
324
348
|
| `./components/molecules` | composed components |
|
|
325
349
|
| `./components/molecules/viewers` | PDF / plain-text viewers |
|
|
326
350
|
| `./components/molecules/documents` | document selector + viewer |
|
|
327
|
-
| `./components/organisms` | chat, speech, ratings |
|
|
351
|
+
| `./components/organisms` | chat, tool approval, speech, ratings |
|
|
328
352
|
| `./components/templates` | page-level layouts |
|
|
329
353
|
| `./components/genui` | `A2uiRenderer`, `coreUiRegistry`, `AssistantChat` |
|
|
330
354
|
| `./components/hooks` | UI hooks |
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { A2uiComponent, SurfaceAction, A2uiSurface, UIAction } from '@alquimia-ai/tools/genui';
|
|
4
|
+
import { b as ToolApprovalView } from '../../tool-approval-K8aLzb1_.mjs';
|
|
5
|
+
import '@alquimia-ai/tools/hooks';
|
|
4
6
|
|
|
5
7
|
/** Props every A2UI component receives from the renderer. */
|
|
6
8
|
interface A2uiNodeProps {
|
|
@@ -48,6 +50,11 @@ interface GenuiChatController {
|
|
|
48
50
|
awaitingUser: boolean;
|
|
49
51
|
dismiss?: (userMessage?: string) => void;
|
|
50
52
|
};
|
|
53
|
+
/** Human-approval gates (`useAlquimia().toolApprovals`), rendered in place with Approve / Reject. */
|
|
54
|
+
toolApprovals?: Array<ToolApprovalView & {
|
|
55
|
+
afterCount: number;
|
|
56
|
+
}>;
|
|
57
|
+
approveTool?: (controlId: string, approved: boolean, message?: string) => unknown;
|
|
51
58
|
}
|
|
52
59
|
interface AssistantChatProps {
|
|
53
60
|
/** The value returned by `useAlquimia({ genui: {...} })`. */
|
|
@@ -61,6 +68,8 @@ interface AssistantChatProps {
|
|
|
61
68
|
className?: string;
|
|
62
69
|
/** Override the typing indicator shown while the agent is working. Defaults to animated dots. */
|
|
63
70
|
thinkIndicator?: React.ReactNode;
|
|
71
|
+
/** Channel name shown when an approval can only be answered on its originating channel. */
|
|
72
|
+
approvalChannelName?: string;
|
|
64
73
|
}
|
|
65
74
|
/**
|
|
66
75
|
* Batteries-included GenUI chat. A thin composition of the SDK's existing organisms
|
|
@@ -74,6 +83,6 @@ interface AssistantChatProps {
|
|
|
74
83
|
* the hook). To customize the shell, compose the organisms directly instead of using
|
|
75
84
|
* this wrapper.
|
|
76
85
|
*/
|
|
77
|
-
declare function AssistantChat({ alquimia, registry, conversationId, placeholder, suggestions, className, thinkIndicator, }: AssistantChatProps): react_jsx_runtime.JSX.Element;
|
|
86
|
+
declare function AssistantChat({ alquimia, registry, conversationId, placeholder, suggestions, className, thinkIndicator, approvalChannelName, }: AssistantChatProps): react_jsx_runtime.JSX.Element;
|
|
78
87
|
|
|
79
88
|
export { type A2uiNodeProps, A2uiRenderer, type A2uiRendererProps, AssistantChat, type AssistantChatProps, type GenuiChatController, coreUiRegistry };
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { A2uiComponent, SurfaceAction, A2uiSurface, UIAction } from '@alquimia-ai/tools/genui';
|
|
4
|
+
import { b as ToolApprovalView } from '../../tool-approval-K8aLzb1_.js';
|
|
5
|
+
import '@alquimia-ai/tools/hooks';
|
|
4
6
|
|
|
5
7
|
/** Props every A2UI component receives from the renderer. */
|
|
6
8
|
interface A2uiNodeProps {
|
|
@@ -48,6 +50,11 @@ interface GenuiChatController {
|
|
|
48
50
|
awaitingUser: boolean;
|
|
49
51
|
dismiss?: (userMessage?: string) => void;
|
|
50
52
|
};
|
|
53
|
+
/** Human-approval gates (`useAlquimia().toolApprovals`), rendered in place with Approve / Reject. */
|
|
54
|
+
toolApprovals?: Array<ToolApprovalView & {
|
|
55
|
+
afterCount: number;
|
|
56
|
+
}>;
|
|
57
|
+
approveTool?: (controlId: string, approved: boolean, message?: string) => unknown;
|
|
51
58
|
}
|
|
52
59
|
interface AssistantChatProps {
|
|
53
60
|
/** The value returned by `useAlquimia({ genui: {...} })`. */
|
|
@@ -61,6 +68,8 @@ interface AssistantChatProps {
|
|
|
61
68
|
className?: string;
|
|
62
69
|
/** Override the typing indicator shown while the agent is working. Defaults to animated dots. */
|
|
63
70
|
thinkIndicator?: React.ReactNode;
|
|
71
|
+
/** Channel name shown when an approval can only be answered on its originating channel. */
|
|
72
|
+
approvalChannelName?: string;
|
|
64
73
|
}
|
|
65
74
|
/**
|
|
66
75
|
* Batteries-included GenUI chat. A thin composition of the SDK's existing organisms
|
|
@@ -74,6 +83,6 @@ interface AssistantChatProps {
|
|
|
74
83
|
* the hook). To customize the shell, compose the organisms directly instead of using
|
|
75
84
|
* this wrapper.
|
|
76
85
|
*/
|
|
77
|
-
declare function AssistantChat({ alquimia, registry, conversationId, placeholder, suggestions, className, thinkIndicator, }: AssistantChatProps): react_jsx_runtime.JSX.Element;
|
|
86
|
+
declare function AssistantChat({ alquimia, registry, conversationId, placeholder, suggestions, className, thinkIndicator, approvalChannelName, }: AssistantChatProps): react_jsx_runtime.JSX.Element;
|
|
78
87
|
|
|
79
88
|
export { type A2uiNodeProps, A2uiRenderer, type A2uiRendererProps, AssistantChat, type AssistantChatProps, type GenuiChatController, coreUiRegistry };
|
|
@@ -2705,8 +2705,8 @@ var coreUiRegistry = {
|
|
|
2705
2705
|
Link: LinkNode
|
|
2706
2706
|
};
|
|
2707
2707
|
// src/components/genui/assistant-chat.tsx
|
|
2708
|
-
var
|
|
2709
|
-
var
|
|
2708
|
+
var React44 = __toESM(require("react"));
|
|
2709
|
+
var import_lucide_react21 = require("lucide-react");
|
|
2710
2710
|
// src/components/organisms/assistant.tsx
|
|
2711
2711
|
var React42 = __toESM(require("react"));
|
|
2712
2712
|
var import_react8 = require("react");
|
|
@@ -4466,17 +4466,208 @@ var AssistantInput = React42.forwardRef(function(_param, ref) {
|
|
|
4466
4466
|
}));
|
|
4467
4467
|
});
|
|
4468
4468
|
AssistantInput.displayName = "AssistantInput";
|
|
4469
|
-
// src/components/
|
|
4469
|
+
// src/components/organisms/tool-approval.tsx
|
|
4470
|
+
var React43 = __toESM(require("react"));
|
|
4471
|
+
var import_lucide_react20 = require("lucide-react");
|
|
4470
4472
|
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
4473
|
+
function formatArguments(args) {
|
|
4474
|
+
if (args === null || args === void 0) return null;
|
|
4475
|
+
if (typeof args === "string") return args;
|
|
4476
|
+
try {
|
|
4477
|
+
return JSON.stringify(args, null, 2);
|
|
4478
|
+
} catch (e) {
|
|
4479
|
+
return String(args);
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
function blockedMessage(approval, channelName) {
|
|
4483
|
+
var _approval_lastResult;
|
|
4484
|
+
var outcome = (_approval_lastResult = approval.lastResult) === null || _approval_lastResult === void 0 ? void 0 : _approval_lastResult.outcome;
|
|
4485
|
+
if (approval.channelOwned || outcome === "wrong-channel") {
|
|
4486
|
+
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.");
|
|
4487
|
+
}
|
|
4488
|
+
switch(outcome){
|
|
4489
|
+
case "already-decided":
|
|
4490
|
+
return "Someone else already answered this request. Waiting for the agent to continue.";
|
|
4491
|
+
case "not-pending":
|
|
4492
|
+
return "This request is no longer waiting for a decision.";
|
|
4493
|
+
case "not-found":
|
|
4494
|
+
return "This conversation has ended, so the request can no longer be answered.";
|
|
4495
|
+
case "forbidden":
|
|
4496
|
+
return "You don't have permission to answer this request.";
|
|
4497
|
+
default:
|
|
4498
|
+
return null;
|
|
4499
|
+
}
|
|
4500
|
+
}
|
|
4501
|
+
function ToolApprovalCard(param) {
|
|
4502
|
+
var approval = param.approval, onDecide = param.onDecide, channelName = param.channelName, className = param.className;
|
|
4503
|
+
var _React43_useState = _sliced_to_array(React43.useState(false), 2), rejecting = _React43_useState[0], setRejecting = _React43_useState[1];
|
|
4504
|
+
var _React43_useState1 = _sliced_to_array(React43.useState(""), 2), reason = _React43_useState1[0], setReason = _React43_useState1[1];
|
|
4505
|
+
var args = formatArguments(approval.arguments);
|
|
4506
|
+
var _approval_toolName;
|
|
4507
|
+
var toolLabel = (_approval_toolName = approval.toolName) !== null && _approval_toolName !== void 0 ? _approval_toolName : "a tool";
|
|
4508
|
+
var submitting = approval.status === "submitting";
|
|
4509
|
+
var settled = approval.status === "approved" || approval.status === "rejected";
|
|
4510
|
+
var blocked = !settled && !submitting && !approval.canAnswer ? blockedMessage(approval, channelName) : null;
|
|
4511
|
+
var failed = !settled && !submitting && approval.canAnswer && approval.lastResult && approval.lastResult.outcome !== "accepted" ? approval.lastResult : null;
|
|
4512
|
+
var decide = function(approved) {
|
|
4513
|
+
var said = reason.trim();
|
|
4514
|
+
void onDecide(approval.controlId, approved, approved || !said ? void 0 : said);
|
|
4515
|
+
};
|
|
4516
|
+
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("section", {
|
|
4517
|
+
"aria-label": "Approval request for ".concat(toolLabel),
|
|
4518
|
+
"data-status": approval.status,
|
|
4519
|
+
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),
|
|
4520
|
+
children: [
|
|
4521
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("header", {
|
|
4522
|
+
className: "flex items-start gap-2",
|
|
4523
|
+
children: [
|
|
4524
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.ShieldAlert, {
|
|
4525
|
+
"aria-hidden": true,
|
|
4526
|
+
className: cn("mt-0.5 h-4 w-4 shrink-0", settled ? "text-muted-foreground" : "text-amber-500")
|
|
4527
|
+
}),
|
|
4528
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", {
|
|
4529
|
+
className: "min-w-0 flex-1",
|
|
4530
|
+
children: [
|
|
4531
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", {
|
|
4532
|
+
className: "text-sm font-medium text-foreground",
|
|
4533
|
+
children: settled ? "Approval request" : "The agent needs your approval"
|
|
4534
|
+
}),
|
|
4535
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("p", {
|
|
4536
|
+
className: "text-sm text-muted-foreground",
|
|
4537
|
+
children: [
|
|
4538
|
+
"Run ",
|
|
4539
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("code", {
|
|
4540
|
+
className: "rounded bg-muted px-1 py-0.5 font-mono text-xs text-foreground",
|
|
4541
|
+
children: toolLabel
|
|
4542
|
+
})
|
|
4543
|
+
]
|
|
4544
|
+
})
|
|
4545
|
+
]
|
|
4546
|
+
}),
|
|
4547
|
+
settled && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("span", {
|
|
4548
|
+
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"),
|
|
4549
|
+
children: [
|
|
4550
|
+
approval.status === "approved" ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.Check, {
|
|
4551
|
+
className: "h-3 w-3"
|
|
4552
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.X, {
|
|
4553
|
+
className: "h-3 w-3"
|
|
4554
|
+
}),
|
|
4555
|
+
approval.status === "approved" ? "Approved" : "Rejected",
|
|
4556
|
+
approval.decidedHere ? " by you" : " elsewhere"
|
|
4557
|
+
]
|
|
4558
|
+
})
|
|
4559
|
+
]
|
|
4560
|
+
}),
|
|
4561
|
+
args !== null && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("pre", {
|
|
4562
|
+
"aria-label": "Arguments",
|
|
4563
|
+
className: "mt-3 max-h-48 overflow-auto rounded-lg bg-muted/60 p-3 font-mono text-xs text-foreground",
|
|
4564
|
+
children: args
|
|
4565
|
+
}),
|
|
4566
|
+
settled && approval.status === "rejected" && approval.reason && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("p", {
|
|
4567
|
+
className: "mt-3 text-sm text-muted-foreground",
|
|
4568
|
+
children: [
|
|
4569
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", {
|
|
4570
|
+
className: "font-medium text-foreground",
|
|
4571
|
+
children: "Reason:"
|
|
4572
|
+
}),
|
|
4573
|
+
" ",
|
|
4574
|
+
approval.reason
|
|
4575
|
+
]
|
|
4576
|
+
}),
|
|
4577
|
+
blocked && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", {
|
|
4578
|
+
role: "status",
|
|
4579
|
+
className: "mt-3 text-sm text-muted-foreground",
|
|
4580
|
+
children: blocked
|
|
4581
|
+
}),
|
|
4582
|
+
failed && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("p", {
|
|
4583
|
+
role: "alert",
|
|
4584
|
+
className: "mt-3 text-sm text-destructive",
|
|
4585
|
+
children: [
|
|
4586
|
+
"Couldn't send your decision",
|
|
4587
|
+
failed.detail ? ": ".concat(failed.detail) : ".",
|
|
4588
|
+
" Try again."
|
|
4589
|
+
]
|
|
4590
|
+
}),
|
|
4591
|
+
!settled && (submitting || approval.canAnswer) && /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", {
|
|
4592
|
+
className: "mt-3 flex flex-col gap-2",
|
|
4593
|
+
children: [
|
|
4594
|
+
rejecting && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Textarea, {
|
|
4595
|
+
"aria-label": "Reason for rejecting (optional)",
|
|
4596
|
+
placeholder: "Reason for rejecting (optional)",
|
|
4597
|
+
value: reason,
|
|
4598
|
+
disabled: submitting,
|
|
4599
|
+
onChange: function(e) {
|
|
4600
|
+
return setReason(e.target.value);
|
|
4601
|
+
},
|
|
4602
|
+
className: "min-h-[64px] text-sm"
|
|
4603
|
+
}),
|
|
4604
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", {
|
|
4605
|
+
className: "flex flex-wrap items-center justify-end gap-2",
|
|
4606
|
+
children: [
|
|
4607
|
+
submitting && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(import_lucide_react20.Loader2, {
|
|
4608
|
+
"aria-label": "Sending decision",
|
|
4609
|
+
className: "h-4 w-4 animate-spin text-muted-foreground"
|
|
4610
|
+
}),
|
|
4611
|
+
rejecting ? /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, {
|
|
4612
|
+
children: [
|
|
4613
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, {
|
|
4614
|
+
size: "sm",
|
|
4615
|
+
variant: "ghost",
|
|
4616
|
+
disabled: submitting,
|
|
4617
|
+
onClick: function() {
|
|
4618
|
+
return setRejecting(false);
|
|
4619
|
+
},
|
|
4620
|
+
children: "Cancel"
|
|
4621
|
+
}),
|
|
4622
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, {
|
|
4623
|
+
size: "sm",
|
|
4624
|
+
variant: "destructive",
|
|
4625
|
+
disabled: submitting,
|
|
4626
|
+
onClick: function() {
|
|
4627
|
+
return decide(false);
|
|
4628
|
+
},
|
|
4629
|
+
children: "Reject"
|
|
4630
|
+
})
|
|
4631
|
+
]
|
|
4632
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, {
|
|
4633
|
+
children: [
|
|
4634
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, {
|
|
4635
|
+
size: "sm",
|
|
4636
|
+
variant: "outline",
|
|
4637
|
+
disabled: submitting,
|
|
4638
|
+
onClick: function() {
|
|
4639
|
+
return setRejecting(true);
|
|
4640
|
+
},
|
|
4641
|
+
children: "Reject\u2026"
|
|
4642
|
+
}),
|
|
4643
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, {
|
|
4644
|
+
size: "sm",
|
|
4645
|
+
disabled: submitting,
|
|
4646
|
+
onClick: function() {
|
|
4647
|
+
return decide(true);
|
|
4648
|
+
},
|
|
4649
|
+
children: "Approve"
|
|
4650
|
+
})
|
|
4651
|
+
]
|
|
4652
|
+
})
|
|
4653
|
+
]
|
|
4654
|
+
})
|
|
4655
|
+
]
|
|
4656
|
+
})
|
|
4657
|
+
]
|
|
4658
|
+
});
|
|
4659
|
+
}
|
|
4660
|
+
// src/components/genui/assistant-chat.tsx
|
|
4661
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
4471
4662
|
function TypingDots() {
|
|
4472
|
-
return /* @__PURE__ */ (0,
|
|
4663
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", {
|
|
4473
4664
|
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",
|
|
4474
4665
|
children: [
|
|
4475
4666
|
0,
|
|
4476
4667
|
1,
|
|
4477
4668
|
2
|
|
4478
4669
|
].map(function(i) {
|
|
4479
|
-
return /* @__PURE__ */ (0,
|
|
4670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", {
|
|
4480
4671
|
className: "h-2 w-2 animate-bounce rounded-full bg-primary",
|
|
4481
4672
|
style: {
|
|
4482
4673
|
animationDelay: "".concat(i * 0.15, "s"),
|
|
@@ -4487,11 +4678,15 @@ function TypingDots() {
|
|
|
4487
4678
|
});
|
|
4488
4679
|
}
|
|
4489
4680
|
function AssistantChat(param) {
|
|
4490
|
-
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;
|
|
4491
|
-
var endRef =
|
|
4492
|
-
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;
|
|
4681
|
+
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;
|
|
4682
|
+
var endRef = React44.useRef(null);
|
|
4683
|
+
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;
|
|
4493
4684
|
var _genui_surfaces;
|
|
4494
4685
|
var surfaces = (_genui_surfaces = genui === null || genui === void 0 ? void 0 : genui.surfaces) !== null && _genui_surfaces !== void 0 ? _genui_surfaces : [];
|
|
4686
|
+
var approvals = toolApprovals !== null && toolApprovals !== void 0 ? toolApprovals : [];
|
|
4687
|
+
var awaitingApproval = approvals.some(function(a) {
|
|
4688
|
+
return a.status === "pending" || a.status === "submitting";
|
|
4689
|
+
});
|
|
4495
4690
|
var _genui_awaitingUser;
|
|
4496
4691
|
var awaitingUser = (_genui_awaitingUser = genui === null || genui === void 0 ? void 0 : genui.awaitingUser) !== null && _genui_awaitingUser !== void 0 ? _genui_awaitingUser : false;
|
|
4497
4692
|
var isBusy = !!(isLoading || isMessageStreaming);
|
|
@@ -4499,36 +4694,37 @@ function AssistantChat(param) {
|
|
|
4499
4694
|
var _m_content;
|
|
4500
4695
|
return m.role === "user" || m.role !== "system" && ((_m_content = m.content) !== null && _m_content !== void 0 ? _m_content : "").trim().length > 0;
|
|
4501
4696
|
});
|
|
4502
|
-
var isEmpty = !hasContent && surfaces.length === 0;
|
|
4503
|
-
|
|
4697
|
+
var isEmpty = !hasContent && surfaces.length === 0 && approvals.length === 0;
|
|
4698
|
+
React44.useEffect(function() {
|
|
4504
4699
|
var _endRef_current;
|
|
4505
4700
|
(_endRef_current = endRef.current) === null || _endRef_current === void 0 ? void 0 : _endRef_current.scrollIntoView({
|
|
4506
4701
|
behavior: "smooth"
|
|
4507
4702
|
});
|
|
4508
4703
|
}, [
|
|
4509
4704
|
messages,
|
|
4510
|
-
surfaces
|
|
4705
|
+
surfaces,
|
|
4706
|
+
approvals.length
|
|
4511
4707
|
]);
|
|
4512
4708
|
var renderSurface = function(item) {
|
|
4513
|
-
return /* @__PURE__ */ (0,
|
|
4709
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", {
|
|
4514
4710
|
className: "my-3 flex flex-col items-start gap-1.5",
|
|
4515
4711
|
children: [
|
|
4516
|
-
/* @__PURE__ */ (0,
|
|
4712
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", {
|
|
4517
4713
|
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"),
|
|
4518
4714
|
children: [
|
|
4519
|
-
item.submitted && /* @__PURE__ */ (0,
|
|
4715
|
+
item.submitted && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", {
|
|
4520
4716
|
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",
|
|
4521
4717
|
children: [
|
|
4522
|
-
/* @__PURE__ */ (0,
|
|
4718
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_lucide_react21.Check, {
|
|
4523
4719
|
className: "h-3 w-3"
|
|
4524
4720
|
}),
|
|
4525
4721
|
item.dismissedWith ? "Skipped" : "Submitted"
|
|
4526
4722
|
]
|
|
4527
4723
|
}),
|
|
4528
|
-
/* @__PURE__ */ (0,
|
|
4724
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", {
|
|
4529
4725
|
className: cn(item.submitted && "pointer-events-none select-none"),
|
|
4530
4726
|
"aria-disabled": item.submitted,
|
|
4531
|
-
children: /* @__PURE__ */ (0,
|
|
4727
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(A2uiRenderer, {
|
|
4532
4728
|
surface: item.surface,
|
|
4533
4729
|
registry: registry,
|
|
4534
4730
|
onAgentAction: genui ? genui.onAgentAction(item.controlId) : function() {}
|
|
@@ -4536,10 +4732,10 @@ function AssistantChat(param) {
|
|
|
4536
4732
|
})
|
|
4537
4733
|
]
|
|
4538
4734
|
}),
|
|
4539
|
-
item.dismissedWith && /* @__PURE__ */ (0,
|
|
4735
|
+
item.dismissedWith && /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("p", {
|
|
4540
4736
|
className: "alq--surface-dismissed max-w-[95%] pl-1 text-sm text-muted-foreground",
|
|
4541
4737
|
children: [
|
|
4542
|
-
/* @__PURE__ */ (0,
|
|
4738
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", {
|
|
4543
4739
|
className: "font-medium text-foreground",
|
|
4544
4740
|
children: "You replied:"
|
|
4545
4741
|
}),
|
|
@@ -4574,21 +4770,56 @@ function AssistantChat(param) {
|
|
|
4574
4770
|
}
|
|
4575
4771
|
}
|
|
4576
4772
|
}
|
|
4773
|
+
var approvalsByCount = /* @__PURE__ */ new Map();
|
|
4774
|
+
var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
|
|
4775
|
+
try {
|
|
4776
|
+
for(var _iterator1 = approvals[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
4777
|
+
var a = _step1.value;
|
|
4778
|
+
var _approvalsByCount_get;
|
|
4779
|
+
var arr1 = (_approvalsByCount_get = approvalsByCount.get(a.afterCount)) !== null && _approvalsByCount_get !== void 0 ? _approvalsByCount_get : [];
|
|
4780
|
+
arr1.push(a);
|
|
4781
|
+
approvalsByCount.set(a.afterCount, arr1);
|
|
4782
|
+
}
|
|
4783
|
+
} catch (err) {
|
|
4784
|
+
_didIteratorError1 = true;
|
|
4785
|
+
_iteratorError1 = err;
|
|
4786
|
+
} finally{
|
|
4787
|
+
try {
|
|
4788
|
+
if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
|
|
4789
|
+
_iterator1.return();
|
|
4790
|
+
}
|
|
4791
|
+
} finally{
|
|
4792
|
+
if (_didIteratorError1) {
|
|
4793
|
+
throw _iteratorError1;
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
var renderApproval = function(approval) {
|
|
4798
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", {
|
|
4799
|
+
className: "my-3 flex flex-col items-start",
|
|
4800
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(ToolApprovalCard, {
|
|
4801
|
+
approval: approval,
|
|
4802
|
+
onDecide: approveTool !== null && approveTool !== void 0 ? approveTool : function() {},
|
|
4803
|
+
channelName: approvalChannelName,
|
|
4804
|
+
className: "duration-500 animate-in fade-in slide-in-from-bottom-2"
|
|
4805
|
+
})
|
|
4806
|
+
}, "a-".concat(approval.controlId));
|
|
4807
|
+
};
|
|
4577
4808
|
var interleave = function(afterIndex) {
|
|
4578
|
-
var _byCount_get;
|
|
4579
|
-
var nodes = ((_byCount_get = byCount.get(afterIndex)) !== null && _byCount_get !== void 0 ? _byCount_get : []).map(renderSurface);
|
|
4809
|
+
var _byCount_get, _approvalsByCount_get;
|
|
4810
|
+
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)));
|
|
4580
4811
|
if (afterIndex === 0 && isEmpty) {
|
|
4581
|
-
nodes.unshift(/* @__PURE__ */ (0,
|
|
4812
|
+
nodes.unshift(/* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", {
|
|
4582
4813
|
className: "flex min-h-full flex-col items-center justify-center gap-4 py-16 text-center",
|
|
4583
4814
|
children: [
|
|
4584
|
-
/* @__PURE__ */ (0,
|
|
4815
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", {
|
|
4585
4816
|
className: "max-w-sm text-muted-foreground",
|
|
4586
4817
|
children: "Ask the agent to build an interface."
|
|
4587
4818
|
}),
|
|
4588
|
-
/* @__PURE__ */ (0,
|
|
4819
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", {
|
|
4589
4820
|
className: "flex flex-col items-center gap-2",
|
|
4590
4821
|
children: suggestions.map(function(s) {
|
|
4591
|
-
return /* @__PURE__ */ (0,
|
|
4822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("button", {
|
|
4592
4823
|
type: "button",
|
|
4593
4824
|
onClick: function() {
|
|
4594
4825
|
return handleInputChange({
|
|
@@ -4662,20 +4893,20 @@ function AssistantChat(param) {
|
|
|
4662
4893
|
return _ref.apply(this, arguments);
|
|
4663
4894
|
};
|
|
4664
4895
|
}();
|
|
4665
|
-
return /* @__PURE__ */ (0,
|
|
4896
|
+
return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(Assistant, {
|
|
4666
4897
|
className: cn("mx-auto flex h-full w-full max-w-2xl flex-col bg-transparent px-4", className),
|
|
4667
4898
|
children: [
|
|
4668
|
-
/* @__PURE__ */ (0,
|
|
4899
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(AssistantMessageArea, {
|
|
4669
4900
|
className: "bg-transparent",
|
|
4670
4901
|
messages: messages,
|
|
4671
4902
|
messagesEndRef: endRef,
|
|
4672
4903
|
isLoading: !!isLoading,
|
|
4673
4904
|
streamingMessageId: streamingMessageId !== null && streamingMessageId !== void 0 ? streamingMessageId : null,
|
|
4674
4905
|
interleave: interleave,
|
|
4675
|
-
awaitingUser: awaitingUser,
|
|
4676
|
-
thinkIndicator: thinkIndicator !== null && thinkIndicator !== void 0 ? thinkIndicator : /* @__PURE__ */ (0,
|
|
4906
|
+
awaitingUser: awaitingUser || awaitingApproval,
|
|
4907
|
+
thinkIndicator: thinkIndicator !== null && thinkIndicator !== void 0 ? thinkIndicator : /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(TypingDots, {})
|
|
4677
4908
|
}),
|
|
4678
|
-
/* @__PURE__ */ (0,
|
|
4909
|
+
/* @__PURE__ */ (0, import_jsx_runtime54.jsx)(AssistantInput, {
|
|
4679
4910
|
className: "mb-5 mt-2 rounded-2xl border-border/60 bg-card/90 shadow-lg backdrop-blur",
|
|
4680
4911
|
sendMessageFunc: onSubmit,
|
|
4681
4912
|
isButtonDisabled: isBusy && !awaitingUser,
|