@dbx-tools/ui-mastra 0.6.218 → 0.6.220
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 +116 -21
- package/index.ts +10 -9
- package/package.json +8 -8
- package/src/react/bubbles.tsx +9 -2
- package/src/react/chat-approvals.ts +40 -9
- package/src/react/chat-composer.tsx +80 -73
- package/src/react/chat-feedback.ts +2 -2
- package/src/react/chat-history.ts +79 -10
- package/src/react/chat-stream.ts +29 -59
- package/src/react/chat-thread-layout.tsx +17 -1
- package/src/react/chat-view.tsx +10 -0
- package/src/react/export-menu.tsx +8 -1
- package/src/react/index.ts +18 -2
- package/src/react/mastra-assistant.tsx +611 -0
- package/src/react/mastra-chat.tsx +127 -72
- package/src/react/thread-sidebar.tsx +33 -43
- package/src/react/thread-tabs.tsx +141 -117
- package/src/react/tool-pill.tsx +24 -1
- package/src/react/types.ts +36 -22
- package/src/support/mastra-client.ts +203 -171
- package/src/support/request-context.ts +30 -0
- package/src/support/thread-sessions.ts +25 -38
- package/src/support/tool-events.ts +41 -0
- package/src/react/chat-stream-reducer.ts +0 -243
- package/src/support/mastra-stream.ts +0 -59
package/README.md
CHANGED
|
@@ -14,15 +14,22 @@ Key features:
|
|
|
14
14
|
wires itself to the default agent.
|
|
15
15
|
- Headless `useMastraChat()` driver for apps that want the same transport logic
|
|
16
16
|
with custom layout.
|
|
17
|
+
- Persistent `MastraAssistant` application shell with a floating launcher,
|
|
18
|
+
dock/overlay modes, every edge, optional resizing, external controls, and
|
|
19
|
+
route-stable chat state.
|
|
17
20
|
- Controlled `ChatView` for hosts that own messages, streaming, model state, and
|
|
18
21
|
route calls themselves.
|
|
19
|
-
- `MastraPluginClient`
|
|
20
|
-
|
|
21
|
-
statement
|
|
22
|
+
- `MastraPluginClient` combines Mastra's official AI SDK chat route, native
|
|
23
|
+
memory APIs, and AppKit-Mastra model, suggestion, feedback, chart, and
|
|
24
|
+
statement routes.
|
|
22
25
|
- Tool-approval support for suspended Mastra `requireApproval` calls, including
|
|
23
|
-
|
|
26
|
+
resumed-stream handling. An email-shaped input (the `send_email` tool)
|
|
24
27
|
renders as a formatted To / Cc / Subject / Markdown-body preview rather than
|
|
25
28
|
raw JSON.
|
|
29
|
+
- Complete native tool input/results retained behind expandable Request and
|
|
30
|
+
Response rows in each tool pill.
|
|
31
|
+
- Typed per-turn application context through Mastra's native `RequestContext`
|
|
32
|
+
and server-side `requestContextSchema`.
|
|
26
33
|
- Inline embed rendering for `[chart:<id>]` and `[data:<id>]` markers produced by
|
|
27
34
|
the server plugin.
|
|
28
35
|
- Conversation sidebar with new, select, rename, delete, active-thread, and
|
|
@@ -49,9 +56,9 @@ Use this package when the server is
|
|
|
49
56
|
[`@dbx-tools/appkit-mastra`](../../node/appkit-mastra) and the UI needs to
|
|
50
57
|
understand Mastra-specific behavior:
|
|
51
58
|
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
- Suspended `requireApproval` tool calls
|
|
59
|
+
- Mastra's official AI SDK chat stream, native resource-scoped memory APIs, and
|
|
60
|
+
the plugin's model, suggestion, feedback, chart, and statement routes.
|
|
61
|
+
- Suspended `requireApproval` tool calls resumed through native `resumeData`.
|
|
55
62
|
- Genie writer events rendered as inline tool progress, not just a terminal
|
|
56
63
|
answer.
|
|
57
64
|
- `[chart:<id>]` and `[data:<id>]` assistant markers rendered as ECharts charts
|
|
@@ -73,6 +80,51 @@ The stylesheet imports the shared `@dbx-tools/ui-appkit` foundation and register
|
|
|
73
80
|
this package's React files with Tailwind. It does not define design tokens; the
|
|
74
81
|
chat UI uses AppKit semantic tokens from the host app.
|
|
75
82
|
|
|
83
|
+
## Add A Persistent Assistant
|
|
84
|
+
|
|
85
|
+
Mount `MastraAssistant` inside the app's existing authentication gate and above
|
|
86
|
+
the route outlet. Closing the panel hides its presentation without unmounting
|
|
87
|
+
the chat driver, so drafts, threads, and active streams survive page navigation.
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
import { MastraAssistant, useMastraAssistant } from "@dbx-tools/ui-mastra/react";
|
|
91
|
+
|
|
92
|
+
const AskAboutStore = ({ storeId }: { storeId: string }) => {
|
|
93
|
+
const assistant = useMastraAssistant<{ storeId: string; route: string }>();
|
|
94
|
+
return (
|
|
95
|
+
<button onClick={() => assistant.open({ storeId, route: window.location.pathname })}>
|
|
96
|
+
Ask assistant
|
|
97
|
+
</button>
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export function App() {
|
|
102
|
+
return (
|
|
103
|
+
<MastraAssistant
|
|
104
|
+
mode="overlay"
|
|
105
|
+
side="right"
|
|
106
|
+
resizable={{ defaultSize: 480, minSize: 360, storageKey: "assistant-size" }}
|
|
107
|
+
title="Workflow assistant"
|
|
108
|
+
launcher={{ position: "bottom-right", label: "Open assistant" }}
|
|
109
|
+
chat={{ showModelPicker: true, enableExport: true, threadPlacement: "top" }}
|
|
110
|
+
>
|
|
111
|
+
<RouterAndAuthenticatedApplication />
|
|
112
|
+
</MastraAssistant>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
`mode="dock"` reflows the child application; `mode="overlay"` overlaps it.
|
|
118
|
+
`side` accepts `top`, `right`, `bottom`, or `left`. Set `resizable={false}` to
|
|
119
|
+
lock size, `launcher={false}` when every launch comes from
|
|
120
|
+
`useMastraAssistant()`, `header={false}` to place New, History, and Close beside
|
|
121
|
+
the conversation pills. With the header enabled those controls move into it and
|
|
122
|
+
the conversation pills remain on their own second row. Replace `icon`, `closeIcon`,
|
|
123
|
+
`newConversationIcon`, `historyIcon`, and `launcher.icon`. Below
|
|
124
|
+
`mobileBreakpoint` the panel becomes a focus-contained modal overlay with Escape
|
|
125
|
+
dismissal while the covered application is inert. A `storageKey` retains
|
|
126
|
+
horizontal and vertical sizes independently.
|
|
127
|
+
|
|
76
128
|
## Render A Drop-In Chat
|
|
77
129
|
|
|
78
130
|
```tsx
|
|
@@ -94,8 +146,8 @@ export function App() {
|
|
|
94
146
|
|
|
95
147
|
`MastraChat` is the quickest client for the AppKit-Mastra plugin. It reads the
|
|
96
148
|
plugin's published client config, creates a `MastraPluginClient`, streams turns
|
|
97
|
-
through
|
|
98
|
-
controlled `ChatView`.
|
|
149
|
+
through Mastra's official AI SDK chat route, hydrates native memory, and renders
|
|
150
|
+
the controlled `ChatView`.
|
|
99
151
|
|
|
100
152
|
Useful options:
|
|
101
153
|
|
|
@@ -103,6 +155,9 @@ Useful options:
|
|
|
103
155
|
- `showModelPicker` fetches `/models` and sends `X-Mastra-Model` overrides.
|
|
104
156
|
- `composerActions` places host-owned per-turn controls beside the model
|
|
105
157
|
selector without replacing the built-in composer.
|
|
158
|
+
- `composerLeadingActions` places attachment or app actions on the left side of
|
|
159
|
+
the fixed composer footer. The textarea grows above it to a cap, then scrolls;
|
|
160
|
+
model and Send/Stop stay pinned bottom-right.
|
|
106
161
|
- `suggestions` overrides Genie starter questions; omit it to auto-fetch
|
|
107
162
|
`/suggestions`, or pass `[]` to hide suggestions.
|
|
108
163
|
- `threadPlacement` chooses where conversation management renders, or turns it
|
|
@@ -167,6 +222,28 @@ Use `useMastraChat()` when the stock behavior is right but the surrounding layou
|
|
|
167
222
|
belongs to your app. The hook owns streaming, aborts, history paging, thread
|
|
168
223
|
selection, model overrides, suggestions, exports, approvals, and feedback state.
|
|
169
224
|
|
|
225
|
+
## Pass Typed Application Context
|
|
226
|
+
|
|
227
|
+
`requestContext` accepts a typed plain record, Mastra `RequestContext<T>`, or a
|
|
228
|
+
per-turn resolver. The driver snapshots it when a message is submitted and
|
|
229
|
+
keeps that snapshot with queued steers, regeneration, and approval continuation.
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
type StoreContext = { storeId: string; route: string };
|
|
233
|
+
|
|
234
|
+
const chat = useMastraChat<StoreContext>({
|
|
235
|
+
requestContext: () => ({
|
|
236
|
+
storeId: selectedStore.id,
|
|
237
|
+
route: location.pathname,
|
|
238
|
+
}),
|
|
239
|
+
});
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
On the server, declare the same contract with Mastra's native
|
|
243
|
+
`requestContextSchema` on `createAgent<StoreContext>()`. Application context
|
|
244
|
+
cannot override the authenticated memory resource, thread, user, scopes, model,
|
|
245
|
+
or trace fields stamped by AppKit-Mastra.
|
|
246
|
+
|
|
170
247
|
## Build A Controlled Chat Surface
|
|
171
248
|
|
|
172
249
|
```tsx
|
|
@@ -200,7 +277,13 @@ const client = new MastraPluginClient(clientConfig);
|
|
|
200
277
|
// different threads never share state.
|
|
201
278
|
const stream = await client.streamAgent({
|
|
202
279
|
agentId: client.defaultAgent,
|
|
203
|
-
messages: [
|
|
280
|
+
messages: [
|
|
281
|
+
{
|
|
282
|
+
id: "user-1",
|
|
283
|
+
role: "user",
|
|
284
|
+
parts: [{ type: "text", text: "Hello" }],
|
|
285
|
+
},
|
|
286
|
+
],
|
|
204
287
|
runId,
|
|
205
288
|
threadId: activeThreadId,
|
|
206
289
|
model: "claude sonnet",
|
|
@@ -215,18 +298,22 @@ Each conversation thread runs independently: start a turn on one thread, switch
|
|
|
215
298
|
to another and start a second, and both stream concurrently. Cancel one via its
|
|
216
299
|
`AbortSignal` (or the driver's `onCancelThread`) without touching the others.
|
|
217
300
|
|
|
218
|
-
`MastraPluginClient` extends `@mastra/client-js` with the
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
301
|
+
`MastraPluginClient` extends `@mastra/client-js` with the official AI SDK
|
|
302
|
+
`chatRoute` transport and AppKit-Mastra additions. It uses
|
|
303
|
+
`credentials: "include"` so session cookies travel with streaming and REST
|
|
304
|
+
calls. The React hooks wrap native memory plus model catalogues, suggestions,
|
|
305
|
+
chart fetches, and statement-data fetches.
|
|
222
306
|
|
|
223
307
|
## Approvals, Embeds, And Feedback
|
|
224
308
|
|
|
225
309
|
The UI understands the extra events produced by
|
|
226
310
|
[`@dbx-tools/appkit-mastra`](../../node/appkit-mastra):
|
|
227
311
|
|
|
228
|
-
-
|
|
229
|
-
|
|
312
|
+
- Approval chunks become inline approval cards and continue the official chat
|
|
313
|
+
route with Mastra's native `{ approved, reason? }` resume data.
|
|
314
|
+
- Native tool-call and tool-result payloads remain complete. Expanding a tool
|
|
315
|
+
row reveals default-closed Request and Response viewers; large values scroll
|
|
316
|
+
without string or collection truncation.
|
|
230
317
|
- Genie writer events render as tool progress, including thinking text, SQL, row
|
|
231
318
|
counts, result summaries, and chart/data markers.
|
|
232
319
|
- `[chart:<id>]` markers long-poll the chart cache and render ECharts inline.
|
|
@@ -303,16 +390,19 @@ touching `navigator.clipboard` or `URL.createObjectURL` again.
|
|
|
303
390
|
## Modules
|
|
304
391
|
|
|
305
392
|
- `MastraChat` - self-contained drop-in chat component.
|
|
393
|
+
- `MastraAssistant` / `useMastraAssistant` - persistent application shell and
|
|
394
|
+
external open/close/context controller.
|
|
306
395
|
- `useMastraChat` - headless driver that returns `ChatView` props.
|
|
307
396
|
- `ChatView` - controlled presentational chat shell.
|
|
308
|
-
- `MastraPluginClient` - `@mastra/client-js`
|
|
397
|
+
- `MastraPluginClient` - native `@mastra/client-js` memory/agent APIs plus
|
|
398
|
+
AppKit-Mastra model, suggestion, feedback, and embed routes.
|
|
309
399
|
- `useMastraClient`, `useMastraConfig`, `useMastraModels`,
|
|
310
400
|
`useMastraDefaultModel`, `useMastraSuggestions`, `useMastraThreads`,
|
|
311
401
|
`useChartFetch`, `useStatementFetch` - route/config hooks for controlled
|
|
312
402
|
clients.
|
|
313
403
|
- `ThreadSidebar` - controlled conversation list, dockable to either edge.
|
|
314
|
-
- `ThreadTabs` - conversation
|
|
315
|
-
|
|
404
|
+
- `ThreadTabs` / `ThreadActions` - conversation pills plus reusable New/History
|
|
405
|
+
controls for the top strip or persistent assistant header.
|
|
316
406
|
- `ExportMenu` - shared export format menu.
|
|
317
407
|
- `src/support/thread-tabs.ts` - pure open-tab bookkeeping (`syncThreadTabs`,
|
|
318
408
|
`closeThreadTab`, `nextActiveThreadTab`) so the strip's state is testable
|
|
@@ -320,6 +410,10 @@ touching `navigator.clipboard` or `URL.createObjectURL` again.
|
|
|
320
410
|
- `src/support/thread-labels.ts` - `threadTitle` / `relativeTime`, shared by
|
|
321
411
|
the sidebar and the tab strip so a row and a tab never disagree about how an
|
|
322
412
|
untitled or freshly-updated conversation reads.
|
|
413
|
+
- `src/support/request-context.ts` - immutable per-run snapshots around Mastra's
|
|
414
|
+
native typed `RequestContext`.
|
|
415
|
+
- `src/support/tool-events.ts` - projection of native AI SDK persisted tool
|
|
416
|
+
parts onto the live pill view model.
|
|
323
417
|
- `src/support/chart-theme.ts` - `ChartChrome`, `LIGHT_CHART_CHROME`,
|
|
324
418
|
`resolveChartChrome`, and the `useChartChrome` hook that keeps an inline
|
|
325
419
|
chart's colors in step with the active theme.
|
|
@@ -328,8 +422,9 @@ touching `navigator.clipboard` or `URL.createObjectURL` again.
|
|
|
328
422
|
an optional `ChartChrome` into a planner spec, shared by the inline chart and
|
|
329
423
|
the PDF export so both read the same.
|
|
330
424
|
- Types - `ChatViewProps`, `MastraChatProps`, `UseMastraChatOptions`,
|
|
331
|
-
`
|
|
332
|
-
`
|
|
425
|
+
`MastraAssistantProps`, `MastraRequestContextInput`, `ThreadPlacement`,
|
|
426
|
+
`ThreadSummary`, `ToolEvent`, `ToolProgress`, `PendingApproval`,
|
|
427
|
+
`FeedbackSubmission`, and related UI contract types.
|
|
333
428
|
|
|
334
429
|
Server-side routes and event production live in
|
|
335
430
|
[`@dbx-tools/appkit-mastra`](../../node/appkit-mastra). Browser-safe route,
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/ui-mastra";
|
|
6
|
-
export const PACKAGE_VERSION = "0.6.
|
|
6
|
+
export const PACKAGE_VERSION = "0.6.220";
|
|
7
7
|
export * as reactBubbles from "./src/react/bubbles.tsx";
|
|
8
8
|
export * as reactChatApprovals from "./src/react/chat-approvals.ts";
|
|
9
9
|
export * as reactChatComposer from "./src/react/chat-composer.tsx";
|
|
@@ -11,7 +11,6 @@ export * as reactChatFeedback from "./src/react/chat-feedback.ts";
|
|
|
11
11
|
export * as reactChatHistory from "./src/react/chat-history.ts";
|
|
12
12
|
export * as reactChatSessions from "./src/react/chat-sessions.ts";
|
|
13
13
|
export * as reactChatStream from "./src/react/chat-stream.ts";
|
|
14
|
-
export * as reactChatStreamReducer from "./src/react/chat-stream-reducer.ts";
|
|
15
14
|
export * as reactChatThreadLayout from "./src/react/chat-thread-layout.tsx";
|
|
16
15
|
export * as reactChatTranscript from "./src/react/chat-transcript.tsx";
|
|
17
16
|
export * as reactChatView from "./src/react/chat-view.tsx";
|
|
@@ -20,6 +19,7 @@ export * as reactEmbedSlots from "./src/react/embed-slots.tsx";
|
|
|
20
19
|
export * as reactExportMenu from "./src/react/export-menu.tsx";
|
|
21
20
|
export * as reactFeedbackControls from "./src/react/feedback-controls.tsx";
|
|
22
21
|
export * as reactMarkdown from "./src/react/markdown.tsx";
|
|
22
|
+
export * as reactMastraAssistant from "./src/react/mastra-assistant.tsx";
|
|
23
23
|
export * as reactMastraChat from "./src/react/mastra-chat.tsx";
|
|
24
24
|
export * as reactSuggestionPills from "./src/react/suggestion-pills.tsx";
|
|
25
25
|
export * as reactSuggestions from "./src/react/suggestions.ts";
|
|
@@ -33,16 +33,16 @@ export * as supportClipboard from "./src/support/clipboard.ts";
|
|
|
33
33
|
export * as supportDownload from "./src/support/download.ts";
|
|
34
34
|
export * as supportExport from "./src/support/export.ts";
|
|
35
35
|
export * as supportMastraClient from "./src/support/mastra-client.ts";
|
|
36
|
-
export * as supportMastraStream from "./src/support/mastra-stream.ts";
|
|
37
36
|
export * as supportModelSelection from "./src/support/model-selection.ts";
|
|
37
|
+
export * as supportRequestContext from "./src/support/request-context.ts";
|
|
38
38
|
export * as supportShikiPlugin from "./src/support/shiki-plugin.ts";
|
|
39
39
|
export * as supportThreadLabels from "./src/support/thread-labels.ts";
|
|
40
40
|
export * as supportThreadSessions from "./src/support/thread-sessions.ts";
|
|
41
41
|
export * as supportThreadTabs from "./src/support/thread-tabs.ts";
|
|
42
|
+
export * as supportToolEvents from "./src/support/tool-events.ts";
|
|
42
43
|
export { AssistantBubble, UserBubble } from "./src/react/bubbles.tsx";
|
|
43
44
|
export { ChatComposer } from "./src/react/chat-composer.tsx";
|
|
44
45
|
export type { ThreadSessionReader, ThreadSessionUpdater, ThreadMessageWriter } from "./src/react/chat-sessions.ts";
|
|
45
|
-
export type { ChatStreamState, ChatStreamChanges, ChatStreamReduction } from "./src/react/chat-stream-reducer.ts";
|
|
46
46
|
export { ChatThreadLayout } from "./src/react/chat-thread-layout.tsx";
|
|
47
47
|
export { useChatTranscriptController, ChatTranscript } from "./src/react/chat-transcript.tsx";
|
|
48
48
|
export type { ChatTranscriptController } from "./src/react/chat-transcript.tsx";
|
|
@@ -53,6 +53,7 @@ export { MarkdownWithEmbeds } from "./src/react/embed-slots.tsx";
|
|
|
53
53
|
export { ExportMenu } from "./src/react/export-menu.tsx";
|
|
54
54
|
export { FeedbackControls } from "./src/react/feedback-controls.tsx";
|
|
55
55
|
export { AssistantMarkdown, ToolMarkdown, SqlBlock } from "./src/react/markdown.tsx";
|
|
56
|
+
export type { MastraAssistantMode, MastraAssistantSide, MastraAssistantLauncherPosition, MastraAssistantResizeOptions, MastraAssistantLauncherOptions, MastraAssistantController, MastraAssistantProps } from "./src/react/mastra-assistant.tsx";
|
|
56
57
|
export { useMastraChat, MastraChat } from "./src/react/mastra-chat.tsx";
|
|
57
58
|
export type { UseMastraChatOptions, MastraChatProps } from "./src/react/mastra-chat.tsx";
|
|
58
59
|
export { SuggestionPills } from "./src/react/suggestion-pills.tsx";
|
|
@@ -60,17 +61,17 @@ export type { SuggestionPillsProps } from "./src/react/suggestion-pills.tsx";
|
|
|
60
61
|
export { dedupeSuggestions, collectSuggestions } from "./src/react/suggestions.ts";
|
|
61
62
|
export { ThreadSidebar } from "./src/react/thread-sidebar.tsx";
|
|
62
63
|
export type { ThreadSidebarProps } from "./src/react/thread-sidebar.tsx";
|
|
63
|
-
export { ThreadTabs } from "./src/react/thread-tabs.tsx";
|
|
64
|
-
export type { ThreadTabsProps } from "./src/react/thread-tabs.tsx";
|
|
64
|
+
export { ThreadActions, ThreadTabs } from "./src/react/thread-tabs.tsx";
|
|
65
|
+
export type { ThreadTabsProps, ThreadActionsProps } from "./src/react/thread-tabs.tsx";
|
|
65
66
|
export { humanizeToolName, ToolSessionPill } from "./src/react/tool-pill.tsx";
|
|
66
67
|
export type { ChatStatus, ToolEvent, ToolProgress, ChatModelOption, QueuedSteer, FeedbackValue, FeedbackSubmission, MessageFeedback, ThreadSummary, ThreadPlacement, ChatViewProps, ApprovalDecision, PendingApproval } from "./src/react/types.ts";
|
|
67
68
|
export { LIGHT_CHART_CHROME } from "./src/support/chart-theme.ts";
|
|
68
69
|
export type { ChartChrome } from "./src/support/chart-theme.ts";
|
|
69
70
|
export type { ExportFormat, ExportBrand, EmbedResolver, ExportChatOptions } from "./src/support/export.ts";
|
|
70
71
|
export { MastraPluginClient, useMastraConfig, useMastraClient, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch } from "./src/support/mastra-client.ts";
|
|
71
|
-
export type { ByIdFetchState } from "./src/support/mastra-client.ts";
|
|
72
|
-
export type { MastraStreamResponse } from "./src/support/mastra-stream.ts";
|
|
72
|
+
export type { MastraStreamResponse, MastraMemoryThread, ByIdFetchState } from "./src/support/mastra-client.ts";
|
|
73
73
|
export { modelStorageKey, readStoredModel, storeSelectedModel } from "./src/support/model-selection.ts";
|
|
74
|
+
export type { MastraRequestContextInput, MastraRequestContextSource, MastraRequestContextSnapshot } from "./src/support/request-context.ts";
|
|
74
75
|
export { DEFAULT_THREAD_SESSION_KEY } from "./src/support/thread-sessions.ts";
|
|
75
|
-
export type { ThreadSession } from "./src/support/thread-sessions.ts";
|
|
76
|
+
export type { SessionQueuedSteer, SessionRun, ThreadSession } from "./src/support/thread-sessions.ts";
|
|
76
77
|
export { THREAD_TAB_SEED_MAX } from "./src/support/thread-tabs.ts";
|
package/package.json
CHANGED
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"react-dom": "~19.2.4"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@dbx-tools/shared-core": "0.6.
|
|
35
|
-
"@dbx-tools/shared-genie": "0.6.
|
|
36
|
-
"@dbx-tools/shared-mastra": "0.6.
|
|
37
|
-
"@dbx-tools/shared-model": "0.6.
|
|
38
|
-
"@dbx-tools/ui-appkit": "0.6.
|
|
39
|
-
"@dbx-tools/ui-branding": "0.6.
|
|
40
|
-
"@mastra/client-js": "1.
|
|
34
|
+
"@dbx-tools/shared-core": "0.6.220",
|
|
35
|
+
"@dbx-tools/shared-genie": "0.6.220",
|
|
36
|
+
"@dbx-tools/shared-mastra": "0.6.220",
|
|
37
|
+
"@dbx-tools/shared-model": "0.6.220",
|
|
38
|
+
"@dbx-tools/ui-appkit": "0.6.220",
|
|
39
|
+
"@dbx-tools/ui-branding": "0.6.220",
|
|
40
|
+
"@mastra/client-js": "1.50.0",
|
|
41
41
|
"@tanstack/react-table": "^8.21.3",
|
|
42
42
|
"ai": "^5.0.0",
|
|
43
43
|
"echarts": "^6.0.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
|
-
"version": "0.6.
|
|
55
|
+
"version": "0.6.220",
|
|
56
56
|
"type": "module",
|
|
57
57
|
"exports": {
|
|
58
58
|
"./react": "./src/react/index.ts",
|
package/src/react/bubbles.tsx
CHANGED
|
@@ -41,6 +41,7 @@ import type {
|
|
|
41
41
|
ToolEvent,
|
|
42
42
|
} from "./types.ts";
|
|
43
43
|
import { copyText } from "../support/clipboard.ts";
|
|
44
|
+
import { mergeToolEvents, toolEventsFromParts } from "../support/tool-events.ts";
|
|
44
45
|
|
|
45
46
|
// User / assistant message bubbles plus the inline approval card and
|
|
46
47
|
// the helpers that surface approval-gated tool calls out of a message's
|
|
@@ -134,6 +135,7 @@ const EmailApprovalPreview = ({ email }: { email: EmailApprovalInput }) => {
|
|
|
134
135
|
* {@link ApprovalDecision} to the parent resume handler.
|
|
135
136
|
*/
|
|
136
137
|
const ToolApprovalCard = ({
|
|
138
|
+
messageId,
|
|
137
139
|
toolName,
|
|
138
140
|
toolCallId,
|
|
139
141
|
runId,
|
|
@@ -141,6 +143,7 @@ const ToolApprovalCard = ({
|
|
|
141
143
|
onResolve,
|
|
142
144
|
disabled,
|
|
143
145
|
}: {
|
|
146
|
+
messageId: string;
|
|
144
147
|
toolName: string;
|
|
145
148
|
toolCallId: string;
|
|
146
149
|
runId?: string;
|
|
@@ -157,9 +160,10 @@ const ToolApprovalCard = ({
|
|
|
157
160
|
setDecision(approved ? "approved" : "denied");
|
|
158
161
|
Promise.resolve(
|
|
159
162
|
approved
|
|
160
|
-
? onResolve({ approved: true, toolName, toolCallId, runId, input })
|
|
163
|
+
? onResolve({ approved: true, messageId, toolName, toolCallId, runId, input })
|
|
161
164
|
: onResolve({
|
|
162
165
|
approved: false,
|
|
166
|
+
messageId,
|
|
163
167
|
toolName,
|
|
164
168
|
toolCallId,
|
|
165
169
|
runId,
|
|
@@ -374,6 +378,7 @@ export const AssistantBubble = ({
|
|
|
374
378
|
collectPendingApprovals(message.parts),
|
|
375
379
|
externalApprovals,
|
|
376
380
|
);
|
|
381
|
+
const toolEvents = mergeToolEvents(toolEventsFromParts(message.parts), events);
|
|
377
382
|
|
|
378
383
|
return (
|
|
379
384
|
<Item className="items-start gap-3 border-none bg-transparent p-0">
|
|
@@ -394,7 +399,7 @@ export const AssistantBubble = ({
|
|
|
394
399
|
* pill above the text parts guarantees the "what the agent did"
|
|
395
400
|
* summary always sits before its resulting charts and answer.
|
|
396
401
|
*/}
|
|
397
|
-
{
|
|
402
|
+
{toolEvents.length > 0 && <ToolSessionPill events={toolEvents} />}
|
|
398
403
|
{reasoning && (
|
|
399
404
|
<Collapsible defaultOpen={isReasoningStreaming}>
|
|
400
405
|
<CollapsibleTrigger className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground">
|
|
@@ -426,6 +431,7 @@ export const AssistantBubble = ({
|
|
|
426
431
|
{pendingApprovals.map((p) => (
|
|
427
432
|
<ToolApprovalCard
|
|
428
433
|
key={p.toolCallId}
|
|
434
|
+
messageId={message.id}
|
|
429
435
|
toolName={p.toolName}
|
|
430
436
|
toolCallId={p.toolCallId}
|
|
431
437
|
runId={p.runId}
|
|
@@ -444,6 +450,7 @@ export const AssistantBubble = ({
|
|
|
444
450
|
variant="ghost"
|
|
445
451
|
className="size-7"
|
|
446
452
|
onClick={() => regenerate()}
|
|
453
|
+
aria-label="Retry response"
|
|
447
454
|
>
|
|
448
455
|
<RefreshCcwIcon className="size-3" />
|
|
449
456
|
</Button>
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { log } from "@dbx-tools/shared-core";
|
|
2
2
|
import { useCallback } from "react";
|
|
3
|
-
import type { MastraPluginClient } from "../support/mastra-client.ts";
|
|
4
|
-
import type { MastraStreamResponse } from "../support/mastra-stream.ts";
|
|
5
|
-
import { DEFAULT_THREAD_SESSION_KEY } from "../support/thread-sessions.ts";
|
|
6
3
|
import type { ThreadSessionReader, ThreadSessionUpdater } from "./chat-sessions.ts";
|
|
7
4
|
import type { ApprovalDecision } from "./types.ts";
|
|
5
|
+
import type { MastraPluginClient, MastraStreamResponse } from "../support/mastra-client.ts";
|
|
6
|
+
import { DEFAULT_THREAD_SESSION_KEY, type ThreadSession } from "../support/thread-sessions.ts";
|
|
8
7
|
|
|
9
8
|
const logger = log.logger("ui-mastra/chat");
|
|
10
9
|
|
|
@@ -23,6 +22,35 @@ interface UseChatApprovalsOptions {
|
|
|
23
22
|
updateSession: ThreadSessionUpdater;
|
|
24
23
|
}
|
|
25
24
|
|
|
25
|
+
/** Resolve one approval against the exact run and assistant message that created it. */
|
|
26
|
+
export function resolveApprovalContinuation(
|
|
27
|
+
session: ThreadSession,
|
|
28
|
+
decision: ApprovalDecision,
|
|
29
|
+
):
|
|
30
|
+
| {
|
|
31
|
+
assistantId: string;
|
|
32
|
+
runId: string;
|
|
33
|
+
requestContext: ThreadSession["runRequestContext"];
|
|
34
|
+
}
|
|
35
|
+
| undefined {
|
|
36
|
+
const runId = decision.runId ?? session.runId;
|
|
37
|
+
if (!runId) return undefined;
|
|
38
|
+
const run = session.runs[runId];
|
|
39
|
+
const assistantId =
|
|
40
|
+
decision.messageId ??
|
|
41
|
+
run?.assistantId ??
|
|
42
|
+
Object.entries(session.pendingApprovalsByMessage).find(([, approvals]) =>
|
|
43
|
+
approvals.some((approval) => approval.toolCallId === decision.toolCallId),
|
|
44
|
+
)?.[0] ??
|
|
45
|
+
session.assistantId;
|
|
46
|
+
if (!assistantId) return undefined;
|
|
47
|
+
return {
|
|
48
|
+
assistantId,
|
|
49
|
+
runId,
|
|
50
|
+
requestContext: run?.requestContext,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
26
54
|
/** Resume an approval-gated tool call and remove its pending UI state. */
|
|
27
55
|
export function useChatApprovals({
|
|
28
56
|
activeKey,
|
|
@@ -34,19 +62,19 @@ export function useChatApprovals({
|
|
|
34
62
|
}: UseChatApprovalsOptions) {
|
|
35
63
|
return useCallback(
|
|
36
64
|
async (decision: ApprovalDecision) => {
|
|
37
|
-
const {
|
|
65
|
+
const { toolCallId, toolName } = decision;
|
|
38
66
|
const session = getSession(activeKey);
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
if (!runId || !assistantId) {
|
|
67
|
+
const continuation = resolveApprovalContinuation(session, decision);
|
|
68
|
+
if (!continuation) {
|
|
42
69
|
logger.warn("approval missing runId or assistantId, cannot resume", {
|
|
43
70
|
tool: toolName,
|
|
44
71
|
toolCallId,
|
|
45
|
-
hasRunId: Boolean(runId),
|
|
46
|
-
hasAssistantId: Boolean(assistantId),
|
|
72
|
+
hasRunId: Boolean(decision.runId ?? session.runId),
|
|
73
|
+
hasAssistantId: Boolean(decision.messageId ?? session.assistantId),
|
|
47
74
|
});
|
|
48
75
|
return;
|
|
49
76
|
}
|
|
77
|
+
const { assistantId, runId, requestContext } = continuation;
|
|
50
78
|
|
|
51
79
|
updateSession(activeKey, (current) => {
|
|
52
80
|
const existing = current.pendingApprovalsByMessage[assistantId];
|
|
@@ -77,12 +105,15 @@ export function useChatApprovals({
|
|
|
77
105
|
runId,
|
|
78
106
|
toolCallId,
|
|
79
107
|
threadId: streamThreadId,
|
|
108
|
+
requestContext,
|
|
80
109
|
signal,
|
|
81
110
|
})
|
|
82
111
|
: mastraClient.declineToolCallStream(agentId, {
|
|
83
112
|
runId,
|
|
84
113
|
toolCallId,
|
|
85
114
|
threadId: streamThreadId,
|
|
115
|
+
reason: decision.reason,
|
|
116
|
+
requestContext,
|
|
86
117
|
signal,
|
|
87
118
|
}),
|
|
88
119
|
);
|