@dbx-tools/ui-mastra 0.3.16 → 0.3.18
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 +3 -1
- package/package.json +7 -7
- package/src/react/bubbles.tsx +76 -3
package/README.md
CHANGED
|
@@ -20,7 +20,9 @@ Key features:
|
|
|
20
20
|
routes for history, threads, model lists, suggestions, feedback, charts, and
|
|
21
21
|
statement data.
|
|
22
22
|
- Tool-approval support for suspended Mastra `requireApproval` calls, including
|
|
23
|
-
direct resumed-stream handling.
|
|
23
|
+
direct resumed-stream handling. An email-shaped input (the `send_email` tool)
|
|
24
|
+
renders as a formatted To / Cc / Subject / Markdown-body preview rather than
|
|
25
|
+
raw JSON.
|
|
24
26
|
- Inline embed rendering for `[chart:<id>]` and `[data:<id>]` markers produced by
|
|
25
27
|
the server plugin.
|
|
26
28
|
- Conversation sidebar with new, select, rename, delete, active-thread, and
|
package/package.json
CHANGED
|
@@ -26,19 +26,19 @@
|
|
|
26
26
|
"shiki": "^3.0.0",
|
|
27
27
|
"sql-formatter": "^15.6.9",
|
|
28
28
|
"streamdown": "^2.5.0",
|
|
29
|
-
"@dbx-tools/shared-
|
|
30
|
-
"@dbx-tools/shared-core": "0.3.
|
|
31
|
-
"@dbx-tools/
|
|
32
|
-
"@dbx-tools/shared-
|
|
33
|
-
"@dbx-tools/
|
|
34
|
-
"@dbx-tools/ui-branding": "0.3.
|
|
29
|
+
"@dbx-tools/shared-model": "0.3.18",
|
|
30
|
+
"@dbx-tools/shared-core": "0.3.18",
|
|
31
|
+
"@dbx-tools/ui-appkit": "0.3.18",
|
|
32
|
+
"@dbx-tools/shared-mastra": "0.3.18",
|
|
33
|
+
"@dbx-tools/shared-genie": "0.3.18",
|
|
34
|
+
"@dbx-tools/ui-branding": "0.3.18"
|
|
35
35
|
},
|
|
36
36
|
"main": "index.ts",
|
|
37
37
|
"license": "UNLICENSED",
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
|
-
"version": "0.3.
|
|
41
|
+
"version": "0.3.18",
|
|
42
42
|
"types": "index.ts",
|
|
43
43
|
"type": "module",
|
|
44
44
|
"exports": {
|
package/src/react/bubbles.tsx
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from "lucide-react";
|
|
26
26
|
import { useState } from "react";
|
|
27
27
|
import { MarkdownWithEmbeds } from "./embed-slots";
|
|
28
|
+
import { ToolMarkdown } from "./markdown";
|
|
28
29
|
import { ExportMenu } from "./export-menu";
|
|
29
30
|
import { FeedbackControls } from "./feedback-controls";
|
|
30
31
|
import { SuggestionPills } from "./suggestion-pills";
|
|
@@ -95,6 +96,74 @@ const RoleAvatar = ({ role }: { role: UIMessage["role"] }) => (
|
|
|
95
96
|
</Avatar>
|
|
96
97
|
);
|
|
97
98
|
|
|
99
|
+
/** A tool-call input shaped like an outbound email (the `send_email` tool). */
|
|
100
|
+
type EmailApprovalInput = {
|
|
101
|
+
to?: string | string[];
|
|
102
|
+
cc?: string | string[];
|
|
103
|
+
subject?: string;
|
|
104
|
+
body?: string;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/** Comma-join one-or-many addresses; empty string when none. */
|
|
108
|
+
const joinAddresses = (value: string | string[] | undefined): string =>
|
|
109
|
+
(Array.isArray(value) ? value : value ? [value] : []).filter(Boolean).join(", ");
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Recognize an approval input that is an email draft (the `send_email` tool),
|
|
113
|
+
* so its card can render a formatted preview instead of raw JSON. Structural,
|
|
114
|
+
* not name-based, so a renamed email tool still previews.
|
|
115
|
+
*/
|
|
116
|
+
const asEmailInput = (input: unknown): EmailApprovalInput | null => {
|
|
117
|
+
if (!input || typeof input !== "object") return null;
|
|
118
|
+
const e = input as EmailApprovalInput;
|
|
119
|
+
const hasBody = typeof e.body === "string";
|
|
120
|
+
const hasSubject = typeof e.subject === "string";
|
|
121
|
+
const hasTo = typeof e.to === "string" || Array.isArray(e.to);
|
|
122
|
+
return hasBody && (hasSubject || hasTo) ? e : null;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Labeled To / Cc / Subject / Body preview of an email awaiting approval, with
|
|
127
|
+
* the body rendered as Markdown (headings, tables, lists) rather than the raw
|
|
128
|
+
* source. Mirrors `ui-email`'s `EmailPreview` without a dependency on that
|
|
129
|
+
* optional package, so the `send_email` approval card reads like an email
|
|
130
|
+
* instead of a JSON blob.
|
|
131
|
+
*/
|
|
132
|
+
const EmailApprovalPreview = ({ email }: { email: EmailApprovalInput }) => {
|
|
133
|
+
const to = joinAddresses(email.to);
|
|
134
|
+
const cc = joinAddresses(email.cc);
|
|
135
|
+
return (
|
|
136
|
+
<dl className="space-y-1 rounded bg-background/40 p-2 text-[11px]">
|
|
137
|
+
{to && (
|
|
138
|
+
<div className="flex gap-2">
|
|
139
|
+
<dt className="w-14 shrink-0 text-muted-foreground">To</dt>
|
|
140
|
+
<dd className="min-w-0 flex-1 truncate">{to}</dd>
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
{cc && (
|
|
144
|
+
<div className="flex gap-2">
|
|
145
|
+
<dt className="w-14 shrink-0 text-muted-foreground">Cc</dt>
|
|
146
|
+
<dd className="min-w-0 flex-1 truncate">{cc}</dd>
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
{email.subject && (
|
|
150
|
+
<div className="flex gap-2">
|
|
151
|
+
<dt className="w-14 shrink-0 text-muted-foreground">Subject</dt>
|
|
152
|
+
<dd className="min-w-0 flex-1 truncate font-medium">{email.subject}</dd>
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
{email.body && (
|
|
156
|
+
<div className="flex gap-2">
|
|
157
|
+
<dt className="w-14 shrink-0 text-muted-foreground">Body</dt>
|
|
158
|
+
<dd className="min-w-0 flex-1 break-words">
|
|
159
|
+
<ToolMarkdown>{email.body}</ToolMarkdown>
|
|
160
|
+
</dd>
|
|
161
|
+
</div>
|
|
162
|
+
)}
|
|
163
|
+
</dl>
|
|
164
|
+
);
|
|
165
|
+
};
|
|
166
|
+
|
|
98
167
|
/**
|
|
99
168
|
* Inline approval prompt rendered when a `requireApproval: true` tool is
|
|
100
169
|
* paused in the agent loop. Approve / deny flows through
|
|
@@ -144,9 +213,13 @@ const ToolApprovalCard = ({
|
|
|
144
213
|
<MessageSquareIcon className="size-3.5" />
|
|
145
214
|
<span>Approval needed: {humanizeToolName(toolName)}</span>
|
|
146
215
|
</div>
|
|
147
|
-
|
|
148
|
-
{
|
|
149
|
-
|
|
216
|
+
{asEmailInput(input) ? (
|
|
217
|
+
<EmailApprovalPreview email={asEmailInput(input)!} />
|
|
218
|
+
) : (
|
|
219
|
+
<pre className="overflow-x-auto rounded bg-background/40 p-2 text-[11px]">
|
|
220
|
+
{JSON.stringify(input, null, 2)}
|
|
221
|
+
</pre>
|
|
222
|
+
)}
|
|
150
223
|
{expired ? (
|
|
151
224
|
<div className="mt-3 flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
|
|
152
225
|
<MessageSquareIcon className="size-3.5" />
|