@dbx-tools/ui-mastra 0.6.218 → 0.6.219
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 +114 -21
- package/index.ts +10 -9
- package/package.json +8 -8
- package/src/react/bubbles.tsx +4 -1
- package/src/react/chat-approvals.ts +9 -4
- 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 +509 -0
- package/src/react/mastra-chat.tsx +120 -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 +32 -22
- package/src/support/mastra-client.ts +203 -171
- package/src/support/request-context.ts +30 -0
- package/src/support/thread-sessions.ts +16 -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,49 @@ 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 full overlay.
|
|
125
|
+
|
|
76
126
|
## Render A Drop-In Chat
|
|
77
127
|
|
|
78
128
|
```tsx
|
|
@@ -94,8 +144,8 @@ export function App() {
|
|
|
94
144
|
|
|
95
145
|
`MastraChat` is the quickest client for the AppKit-Mastra plugin. It reads the
|
|
96
146
|
plugin's published client config, creates a `MastraPluginClient`, streams turns
|
|
97
|
-
through
|
|
98
|
-
controlled `ChatView`.
|
|
147
|
+
through Mastra's official AI SDK chat route, hydrates native memory, and renders
|
|
148
|
+
the controlled `ChatView`.
|
|
99
149
|
|
|
100
150
|
Useful options:
|
|
101
151
|
|
|
@@ -103,6 +153,9 @@ Useful options:
|
|
|
103
153
|
- `showModelPicker` fetches `/models` and sends `X-Mastra-Model` overrides.
|
|
104
154
|
- `composerActions` places host-owned per-turn controls beside the model
|
|
105
155
|
selector without replacing the built-in composer.
|
|
156
|
+
- `composerLeadingActions` places attachment or app actions on the left side of
|
|
157
|
+
the fixed composer footer. The textarea grows above it to a cap, then scrolls;
|
|
158
|
+
model and Send/Stop stay pinned bottom-right.
|
|
106
159
|
- `suggestions` overrides Genie starter questions; omit it to auto-fetch
|
|
107
160
|
`/suggestions`, or pass `[]` to hide suggestions.
|
|
108
161
|
- `threadPlacement` chooses where conversation management renders, or turns it
|
|
@@ -167,6 +220,28 @@ Use `useMastraChat()` when the stock behavior is right but the surrounding layou
|
|
|
167
220
|
belongs to your app. The hook owns streaming, aborts, history paging, thread
|
|
168
221
|
selection, model overrides, suggestions, exports, approvals, and feedback state.
|
|
169
222
|
|
|
223
|
+
## Pass Typed Application Context
|
|
224
|
+
|
|
225
|
+
`requestContext` accepts a typed plain record, Mastra `RequestContext<T>`, or a
|
|
226
|
+
per-turn resolver. The driver snapshots it when a message is submitted and
|
|
227
|
+
keeps that snapshot with queued steers, regeneration, and approval continuation.
|
|
228
|
+
|
|
229
|
+
```tsx
|
|
230
|
+
type StoreContext = { storeId: string; route: string };
|
|
231
|
+
|
|
232
|
+
const chat = useMastraChat<StoreContext>({
|
|
233
|
+
requestContext: () => ({
|
|
234
|
+
storeId: selectedStore.id,
|
|
235
|
+
route: location.pathname,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
On the server, declare the same contract with Mastra's native
|
|
241
|
+
`requestContextSchema` on `createAgent<StoreContext>()`. Application context
|
|
242
|
+
cannot override the authenticated memory resource, thread, user, scopes, model,
|
|
243
|
+
or trace fields stamped by AppKit-Mastra.
|
|
244
|
+
|
|
170
245
|
## Build A Controlled Chat Surface
|
|
171
246
|
|
|
172
247
|
```tsx
|
|
@@ -200,7 +275,13 @@ const client = new MastraPluginClient(clientConfig);
|
|
|
200
275
|
// different threads never share state.
|
|
201
276
|
const stream = await client.streamAgent({
|
|
202
277
|
agentId: client.defaultAgent,
|
|
203
|
-
messages: [
|
|
278
|
+
messages: [
|
|
279
|
+
{
|
|
280
|
+
id: "user-1",
|
|
281
|
+
role: "user",
|
|
282
|
+
parts: [{ type: "text", text: "Hello" }],
|
|
283
|
+
},
|
|
284
|
+
],
|
|
204
285
|
runId,
|
|
205
286
|
threadId: activeThreadId,
|
|
206
287
|
model: "claude sonnet",
|
|
@@ -215,18 +296,22 @@ Each conversation thread runs independently: start a turn on one thread, switch
|
|
|
215
296
|
to another and start a second, and both stream concurrently. Cancel one via its
|
|
216
297
|
`AbortSignal` (or the driver's `onCancelThread`) without touching the others.
|
|
217
298
|
|
|
218
|
-
`MastraPluginClient` extends `@mastra/client-js` with the
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
299
|
+
`MastraPluginClient` extends `@mastra/client-js` with the official AI SDK
|
|
300
|
+
`chatRoute` transport and AppKit-Mastra additions. It uses
|
|
301
|
+
`credentials: "include"` so session cookies travel with streaming and REST
|
|
302
|
+
calls. The React hooks wrap native memory plus model catalogues, suggestions,
|
|
303
|
+
chart fetches, and statement-data fetches.
|
|
222
304
|
|
|
223
305
|
## Approvals, Embeds, And Feedback
|
|
224
306
|
|
|
225
307
|
The UI understands the extra events produced by
|
|
226
308
|
[`@dbx-tools/appkit-mastra`](../../node/appkit-mastra):
|
|
227
309
|
|
|
228
|
-
-
|
|
229
|
-
|
|
310
|
+
- Approval chunks become inline approval cards and continue the official chat
|
|
311
|
+
route with Mastra's native `{ approved, reason? }` resume data.
|
|
312
|
+
- Native tool-call and tool-result payloads remain complete. Expanding a tool
|
|
313
|
+
row reveals default-closed Request and Response viewers; large values scroll
|
|
314
|
+
without string or collection truncation.
|
|
230
315
|
- Genie writer events render as tool progress, including thinking text, SQL, row
|
|
231
316
|
counts, result summaries, and chart/data markers.
|
|
232
317
|
- `[chart:<id>]` markers long-poll the chart cache and render ECharts inline.
|
|
@@ -303,16 +388,19 @@ touching `navigator.clipboard` or `URL.createObjectURL` again.
|
|
|
303
388
|
## Modules
|
|
304
389
|
|
|
305
390
|
- `MastraChat` - self-contained drop-in chat component.
|
|
391
|
+
- `MastraAssistant` / `useMastraAssistant` - persistent application shell and
|
|
392
|
+
external open/close/context controller.
|
|
306
393
|
- `useMastraChat` - headless driver that returns `ChatView` props.
|
|
307
394
|
- `ChatView` - controlled presentational chat shell.
|
|
308
|
-
- `MastraPluginClient` - `@mastra/client-js`
|
|
395
|
+
- `MastraPluginClient` - native `@mastra/client-js` memory/agent APIs plus
|
|
396
|
+
AppKit-Mastra model, suggestion, feedback, and embed routes.
|
|
309
397
|
- `useMastraClient`, `useMastraConfig`, `useMastraModels`,
|
|
310
398
|
`useMastraDefaultModel`, `useMastraSuggestions`, `useMastraThreads`,
|
|
311
399
|
`useChartFetch`, `useStatementFetch` - route/config hooks for controlled
|
|
312
400
|
clients.
|
|
313
401
|
- `ThreadSidebar` - controlled conversation list, dockable to either edge.
|
|
314
|
-
- `ThreadTabs` - conversation
|
|
315
|
-
|
|
402
|
+
- `ThreadTabs` / `ThreadActions` - conversation pills plus reusable New/History
|
|
403
|
+
controls for the top strip or persistent assistant header.
|
|
316
404
|
- `ExportMenu` - shared export format menu.
|
|
317
405
|
- `src/support/thread-tabs.ts` - pure open-tab bookkeeping (`syncThreadTabs`,
|
|
318
406
|
`closeThreadTab`, `nextActiveThreadTab`) so the strip's state is testable
|
|
@@ -320,6 +408,10 @@ touching `navigator.clipboard` or `URL.createObjectURL` again.
|
|
|
320
408
|
- `src/support/thread-labels.ts` - `threadTitle` / `relativeTime`, shared by
|
|
321
409
|
the sidebar and the tab strip so a row and a tab never disagree about how an
|
|
322
410
|
untitled or freshly-updated conversation reads.
|
|
411
|
+
- `src/support/request-context.ts` - immutable per-run snapshots around Mastra's
|
|
412
|
+
native typed `RequestContext`.
|
|
413
|
+
- `src/support/tool-events.ts` - projection of native AI SDK persisted tool
|
|
414
|
+
parts onto the live pill view model.
|
|
323
415
|
- `src/support/chart-theme.ts` - `ChartChrome`, `LIGHT_CHART_CHROME`,
|
|
324
416
|
`resolveChartChrome`, and the `useChartChrome` hook that keeps an inline
|
|
325
417
|
chart's colors in step with the active theme.
|
|
@@ -328,8 +420,9 @@ touching `navigator.clipboard` or `URL.createObjectURL` again.
|
|
|
328
420
|
an optional `ChartChrome` into a planner spec, shared by the inline chart and
|
|
329
421
|
the PDF export so both read the same.
|
|
330
422
|
- Types - `ChatViewProps`, `MastraChatProps`, `UseMastraChatOptions`,
|
|
331
|
-
`
|
|
332
|
-
`
|
|
423
|
+
`MastraAssistantProps`, `MastraRequestContextInput`, `ThreadPlacement`,
|
|
424
|
+
`ThreadSummary`, `ToolEvent`, `ToolProgress`, `PendingApproval`,
|
|
425
|
+
`FeedbackSubmission`, and related UI contract types.
|
|
333
426
|
|
|
334
427
|
Server-side routes and event production live in
|
|
335
428
|
[`@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.219";
|
|
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, 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.219",
|
|
35
|
+
"@dbx-tools/shared-genie": "0.6.219",
|
|
36
|
+
"@dbx-tools/shared-mastra": "0.6.219",
|
|
37
|
+
"@dbx-tools/shared-model": "0.6.219",
|
|
38
|
+
"@dbx-tools/ui-appkit": "0.6.219",
|
|
39
|
+
"@dbx-tools/ui-branding": "0.6.219",
|
|
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.219",
|
|
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
|
|
@@ -374,6 +375,7 @@ export const AssistantBubble = ({
|
|
|
374
375
|
collectPendingApprovals(message.parts),
|
|
375
376
|
externalApprovals,
|
|
376
377
|
);
|
|
378
|
+
const toolEvents = mergeToolEvents(toolEventsFromParts(message.parts), events);
|
|
377
379
|
|
|
378
380
|
return (
|
|
379
381
|
<Item className="items-start gap-3 border-none bg-transparent p-0">
|
|
@@ -394,7 +396,7 @@ export const AssistantBubble = ({
|
|
|
394
396
|
* pill above the text parts guarantees the "what the agent did"
|
|
395
397
|
* summary always sits before its resulting charts and answer.
|
|
396
398
|
*/}
|
|
397
|
-
{
|
|
399
|
+
{toolEvents.length > 0 && <ToolSessionPill events={toolEvents} />}
|
|
398
400
|
{reasoning && (
|
|
399
401
|
<Collapsible defaultOpen={isReasoningStreaming}>
|
|
400
402
|
<CollapsibleTrigger className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground">
|
|
@@ -444,6 +446,7 @@ export const AssistantBubble = ({
|
|
|
444
446
|
variant="ghost"
|
|
445
447
|
className="size-7"
|
|
446
448
|
onClick={() => regenerate()}
|
|
449
|
+
aria-label="Retry response"
|
|
447
450
|
>
|
|
448
451
|
<RefreshCcwIcon className="size-3" />
|
|
449
452
|
</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 } from "../support/thread-sessions.ts";
|
|
8
7
|
|
|
9
8
|
const logger = log.logger("ui-mastra/chat");
|
|
10
9
|
|
|
@@ -36,7 +35,10 @@ export function useChatApprovals({
|
|
|
36
35
|
async (decision: ApprovalDecision) => {
|
|
37
36
|
const { runId: decisionRunId, toolCallId, toolName } = decision;
|
|
38
37
|
const session = getSession(activeKey);
|
|
39
|
-
const assistantId =
|
|
38
|
+
const assistantId =
|
|
39
|
+
Object.entries(session.pendingApprovalsByMessage).find(([, approvals]) =>
|
|
40
|
+
approvals.some((approval) => approval.toolCallId === toolCallId),
|
|
41
|
+
)?.[0] ?? session.assistantId;
|
|
40
42
|
const runId = decisionRunId ?? session.runId;
|
|
41
43
|
if (!runId || !assistantId) {
|
|
42
44
|
logger.warn("approval missing runId or assistantId, cannot resume", {
|
|
@@ -77,12 +79,15 @@ export function useChatApprovals({
|
|
|
77
79
|
runId,
|
|
78
80
|
toolCallId,
|
|
79
81
|
threadId: streamThreadId,
|
|
82
|
+
requestContext: session.runRequestContext,
|
|
80
83
|
signal,
|
|
81
84
|
})
|
|
82
85
|
: mastraClient.declineToolCallStream(agentId, {
|
|
83
86
|
runId,
|
|
84
87
|
toolCallId,
|
|
85
88
|
threadId: streamThreadId,
|
|
89
|
+
reason: decision.reason,
|
|
90
|
+
requestContext: session.runRequestContext,
|
|
86
91
|
signal,
|
|
87
92
|
}),
|
|
88
93
|
);
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
Trash2Icon,
|
|
32
32
|
XIcon,
|
|
33
33
|
} from "lucide-react";
|
|
34
|
-
import { useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
34
|
+
import { useCallback, useId, useLayoutEffect, useRef, useState } from "react";
|
|
35
35
|
import { autosizeComposerTextarea, observeComposerWidth } from "./_composer-autosize.ts";
|
|
36
36
|
import { ExportMenu } from "./export-menu.tsx";
|
|
37
37
|
import { SuggestionPills } from "./suggestion-pills.tsx";
|
|
@@ -251,6 +251,7 @@ type ChatComposerProps = {
|
|
|
251
251
|
onModelChange: ChatViewProps["onModelChange"];
|
|
252
252
|
defaultModelName: ChatViewProps["defaultModelName"];
|
|
253
253
|
composerActions: ChatViewProps["composerActions"];
|
|
254
|
+
composerLeadingActions: ChatViewProps["composerLeadingActions"];
|
|
254
255
|
isLoadingHistory: NonNullable<ChatViewProps["isLoadingHistory"]>;
|
|
255
256
|
onClear: ChatViewProps["onClear"];
|
|
256
257
|
onExportConversation: ChatViewProps["onExportConversation"];
|
|
@@ -273,12 +274,14 @@ export const ChatComposer = ({
|
|
|
273
274
|
onModelChange,
|
|
274
275
|
defaultModelName,
|
|
275
276
|
composerActions,
|
|
277
|
+
composerLeadingActions,
|
|
276
278
|
isLoadingHistory,
|
|
277
279
|
onClear,
|
|
278
280
|
onExportConversation,
|
|
279
281
|
onResumeFollow,
|
|
280
282
|
}: ChatComposerProps) => {
|
|
281
283
|
const [input, setInput] = useState("");
|
|
284
|
+
const inputId = useId();
|
|
282
285
|
const inputGroupRef = useRef<HTMLDivElement>(null);
|
|
283
286
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
284
287
|
|
|
@@ -316,12 +319,6 @@ export const ChatComposer = ({
|
|
|
316
319
|
sensitivity: "base",
|
|
317
320
|
}),
|
|
318
321
|
);
|
|
319
|
-
const showToolbar =
|
|
320
|
-
showModelDisplay ||
|
|
321
|
-
Boolean(composerActions) ||
|
|
322
|
-
Boolean(onExportConversation) ||
|
|
323
|
-
Boolean(onClear);
|
|
324
|
-
|
|
325
322
|
return (
|
|
326
323
|
<>
|
|
327
324
|
{isEmpty && (
|
|
@@ -350,6 +347,8 @@ export const ChatComposer = ({
|
|
|
350
347
|
className="rounded-2xl border-border/80 shadow-sm transition-shadow focus-within:shadow-md"
|
|
351
348
|
>
|
|
352
349
|
<InputGroupTextarea
|
|
350
|
+
id={`${inputId}-message`}
|
|
351
|
+
name="message"
|
|
353
352
|
ref={textareaRef}
|
|
354
353
|
value={input}
|
|
355
354
|
onChange={(event) => setInput(event.target.value)}
|
|
@@ -362,76 +361,84 @@ export const ChatComposer = ({
|
|
|
362
361
|
placeholder={isLoadingHistory ? "Loading history..." : "Send a message..."}
|
|
363
362
|
rows={1}
|
|
364
363
|
disabled={isLoadingHistory}
|
|
365
|
-
className="field-sizing-fixed max-h-
|
|
364
|
+
className="field-sizing-fixed max-h-64 w-full flex-none overflow-y-auto px-4 pb-2 pt-4 text-base md:text-sm"
|
|
366
365
|
/>
|
|
367
|
-
<InputGroupAddon
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
</InputGroupButton>
|
|
378
|
-
) : (
|
|
379
|
-
<InputGroupButton
|
|
380
|
-
type="submit"
|
|
381
|
-
size="icon-sm"
|
|
382
|
-
variant="default"
|
|
383
|
-
disabled={!input.trim() || isLoadingHistory}
|
|
384
|
-
aria-label={isRunning ? "Send now (interrupts)" : "Send message"}
|
|
385
|
-
>
|
|
386
|
-
<SendIcon className="size-3" />
|
|
387
|
-
</InputGroupButton>
|
|
388
|
-
)}
|
|
389
|
-
</InputGroupAddon>
|
|
390
|
-
</InputGroup>
|
|
391
|
-
{showToolbar && (
|
|
392
|
-
<div className="mt-2 flex items-center gap-2 text-xs text-muted-foreground">
|
|
393
|
-
{showModelDisplay &&
|
|
394
|
-
(modelChangeable ? (
|
|
395
|
-
<Select
|
|
396
|
-
value={model ? model : DEFAULT_MODEL_VALUE}
|
|
397
|
-
onValueChange={(value) =>
|
|
398
|
-
onModelChange?.(value === DEFAULT_MODEL_VALUE ? "" : value)
|
|
399
|
-
}
|
|
366
|
+
<InputGroupAddon
|
|
367
|
+
align="block-end"
|
|
368
|
+
className="flex w-full flex-row flex-wrap items-center justify-between gap-2 px-3 pb-3 pt-0"
|
|
369
|
+
>
|
|
370
|
+
<div className="flex min-w-0 max-w-full flex-wrap items-center gap-2">
|
|
371
|
+
{composerLeadingActions}
|
|
372
|
+
{onExportConversation && (
|
|
373
|
+
<ExportMenu
|
|
374
|
+
onExport={(format) => void onExportConversation(format)}
|
|
375
|
+
tooltip="Export conversation"
|
|
400
376
|
disabled={isLoadingHistory}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
377
|
+
/>
|
|
378
|
+
)}
|
|
379
|
+
{onClear && (
|
|
380
|
+
<ClearConversationAction onClear={onClear} isLoadingHistory={isLoadingHistory} />
|
|
381
|
+
)}
|
|
382
|
+
</div>
|
|
383
|
+
<div className="ml-auto flex min-w-0 max-w-full items-center gap-1.5">
|
|
384
|
+
{composerActions}
|
|
385
|
+
{showModelDisplay &&
|
|
386
|
+
(modelChangeable ? (
|
|
387
|
+
<Select
|
|
388
|
+
name="mastra-model"
|
|
389
|
+
value={model ? model : DEFAULT_MODEL_VALUE}
|
|
390
|
+
onValueChange={(value) =>
|
|
391
|
+
onModelChange?.(value === DEFAULT_MODEL_VALUE ? "" : value)
|
|
392
|
+
}
|
|
393
|
+
disabled={isLoadingHistory}
|
|
405
394
|
>
|
|
406
|
-
<
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
<
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
395
|
+
<SelectTrigger
|
|
396
|
+
size="sm"
|
|
397
|
+
aria-label="Model"
|
|
398
|
+
className="h-7 w-auto max-w-[180px] gap-1 truncate border-0 bg-transparent px-2 text-xs shadow-none hover:bg-accent [&_svg]:size-3"
|
|
399
|
+
>
|
|
400
|
+
<SelectValue placeholder={defaultOptionLabel} />
|
|
401
|
+
</SelectTrigger>
|
|
402
|
+
<SelectContent>
|
|
403
|
+
<SelectItem value={DEFAULT_MODEL_VALUE}>{defaultOptionLabel}</SelectItem>
|
|
404
|
+
{sortedModels.map((option) => (
|
|
405
|
+
<SelectItem key={option.name} value={option.name}>
|
|
406
|
+
{option.displayName || option.name}
|
|
407
|
+
</SelectItem>
|
|
408
|
+
))}
|
|
409
|
+
</SelectContent>
|
|
410
|
+
</Select>
|
|
411
|
+
) : (
|
|
412
|
+
<span className="max-w-[180px] truncate px-2 text-xs text-muted-foreground">
|
|
413
|
+
{currentModelLabel}
|
|
414
|
+
</span>
|
|
415
|
+
))}
|
|
416
|
+
{isRunning && onStop && !input.trim() ? (
|
|
417
|
+
<InputGroupButton
|
|
418
|
+
type="button"
|
|
419
|
+
size="icon-sm"
|
|
420
|
+
variant="default"
|
|
421
|
+
onClick={() => onStop()}
|
|
422
|
+
aria-label="Stop response"
|
|
423
|
+
className="shrink-0 rounded-full"
|
|
424
|
+
>
|
|
425
|
+
<SquareIcon className="size-3 fill-current" />
|
|
426
|
+
</InputGroupButton>
|
|
417
427
|
) : (
|
|
418
|
-
<
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
)}
|
|
433
|
-
</div>
|
|
434
|
-
)}
|
|
428
|
+
<InputGroupButton
|
|
429
|
+
type="submit"
|
|
430
|
+
size="icon-sm"
|
|
431
|
+
variant="default"
|
|
432
|
+
disabled={!input.trim() || isLoadingHistory}
|
|
433
|
+
aria-label={isRunning ? "Send now (interrupts)" : "Send message"}
|
|
434
|
+
className="shrink-0 rounded-full"
|
|
435
|
+
>
|
|
436
|
+
<SendIcon className="size-3" />
|
|
437
|
+
</InputGroupButton>
|
|
438
|
+
)}
|
|
439
|
+
</div>
|
|
440
|
+
</InputGroupAddon>
|
|
441
|
+
</InputGroup>
|
|
435
442
|
</form>
|
|
436
443
|
</>
|
|
437
444
|
);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { error as sharedError, log } from "@dbx-tools/shared-core";
|
|
2
2
|
import type { UIMessage } from "ai";
|
|
3
3
|
import { useCallback, useRef } from "react";
|
|
4
|
-
import type { MastraPluginClient } from "../support/mastra-client.ts";
|
|
5
|
-
import type { FeedbackSubmission, MessageFeedback } from "./types.ts";
|
|
6
4
|
import type { ThreadSessionUpdater } from "./chat-sessions.ts";
|
|
5
|
+
import type { FeedbackSubmission, MessageFeedback } from "./types.ts";
|
|
6
|
+
import type { MastraPluginClient } from "../support/mastra-client.ts";
|
|
7
7
|
|
|
8
8
|
const logger = log.logger("ui-mastra/chat");
|
|
9
9
|
|