@dbx-tools/ui-mastra 0.3.1 → 0.3.3
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/package.json +7 -7
- package/src/react/chat-view.tsx +25 -8
- package/src/react/index.ts +1 -0
- package/src/react/mastra-chat.tsx +6 -0
- package/src/react/types.ts +7 -0
- package/src/support/mastra-client.ts +50 -0
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-
|
|
31
|
-
"@dbx-tools/shared-
|
|
32
|
-
"@dbx-tools/shared-
|
|
33
|
-
"@dbx-tools/ui-appkit": "0.3.
|
|
34
|
-
"@dbx-tools/ui-branding": "0.3.
|
|
29
|
+
"@dbx-tools/shared-genie": "0.3.3",
|
|
30
|
+
"@dbx-tools/shared-core": "0.3.3",
|
|
31
|
+
"@dbx-tools/shared-mastra": "0.3.3",
|
|
32
|
+
"@dbx-tools/shared-model": "0.3.3",
|
|
33
|
+
"@dbx-tools/ui-appkit": "0.3.3",
|
|
34
|
+
"@dbx-tools/ui-branding": "0.3.3"
|
|
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.3",
|
|
42
42
|
"types": "index.ts",
|
|
43
43
|
"type": "module",
|
|
44
44
|
"exports": {
|
package/src/react/chat-view.tsx
CHANGED
|
@@ -100,6 +100,7 @@ export const ChatView = ({
|
|
|
100
100
|
models,
|
|
101
101
|
model,
|
|
102
102
|
onModelChange,
|
|
103
|
+
defaultModelName,
|
|
103
104
|
onLoadMore,
|
|
104
105
|
isLoadingMore = false,
|
|
105
106
|
hasMore = false,
|
|
@@ -285,11 +286,25 @@ export const ChatView = ({
|
|
|
285
286
|
// otherwise as static text.
|
|
286
287
|
const showModelDisplay = Boolean(onModelChange);
|
|
287
288
|
const modelChangeable = Boolean(models && models.length > 0);
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
models?.find((m) => m.name ===
|
|
289
|
+
// Human-readable name for an endpoint id, using the catalogue's
|
|
290
|
+
// `displayName` when present, else the raw id.
|
|
291
|
+
const modelLabel = (name?: string): string | undefined => {
|
|
292
|
+
if (!name) return undefined;
|
|
293
|
+
return models?.find((m) => m.name === name)?.displayName || name;
|
|
294
|
+
};
|
|
295
|
+
// The default option shows the server's fallback model by name when known
|
|
296
|
+
// (from `defaultModelName`), else a neutral "Default" - no "server default"
|
|
297
|
+
// phrasing either way.
|
|
298
|
+
const defaultOptionLabel = modelLabel(defaultModelName) ?? "Default";
|
|
299
|
+
// Label the current model by its human-readable name when a model is
|
|
300
|
+
// pinned, else the default-option label.
|
|
301
|
+
const currentModelLabel = modelLabel(model) || defaultOptionLabel;
|
|
302
|
+
// Picker entries sorted by their human-readable label (case-insensitive).
|
|
303
|
+
const sortedModels = [...(models ?? [])].sort((a, b) =>
|
|
304
|
+
(a.displayName || a.name).localeCompare(b.displayName || b.name, undefined, {
|
|
305
|
+
sensitivity: "base",
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
293
308
|
const showClear = Boolean(onClear);
|
|
294
309
|
const showExport = Boolean(onExportConversation);
|
|
295
310
|
// The conversation sidebar turns on once the host wires both the
|
|
@@ -680,11 +695,13 @@ export const ChatView = ({
|
|
|
680
695
|
size="sm"
|
|
681
696
|
className="h-7 w-auto max-w-[200px] gap-1 rounded-full px-2.5 text-xs [&_svg]:size-3"
|
|
682
697
|
>
|
|
683
|
-
<SelectValue placeholder=
|
|
698
|
+
<SelectValue placeholder={defaultOptionLabel} />
|
|
684
699
|
</SelectTrigger>
|
|
685
700
|
<SelectContent>
|
|
686
|
-
<SelectItem value={DEFAULT_MODEL_VALUE}>
|
|
687
|
-
|
|
701
|
+
<SelectItem value={DEFAULT_MODEL_VALUE}>
|
|
702
|
+
{defaultOptionLabel}
|
|
703
|
+
</SelectItem>
|
|
704
|
+
{sortedModels.map((m) => (
|
|
688
705
|
<SelectItem key={m.name} value={m.name}>
|
|
689
706
|
{m.displayName || m.name}
|
|
690
707
|
</SelectItem>
|
package/src/react/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { exportChat, type EmbedResolver, type ExportFormat } from "../support/ex
|
|
|
10
10
|
import { useBrand } from "@dbx-tools/ui-branding/react";
|
|
11
11
|
import {
|
|
12
12
|
useMastraClient,
|
|
13
|
+
useMastraDefaultModel,
|
|
13
14
|
useMastraModels,
|
|
14
15
|
useMastraSuggestions,
|
|
15
16
|
useMastraThreads,
|
|
@@ -347,6 +348,10 @@ export const useMastraChat = (
|
|
|
347
348
|
// hidden and skips the catalogue fetch entirely.
|
|
348
349
|
const showModelPicker = Boolean(options.showModelPicker);
|
|
349
350
|
const { models } = useMastraModels(showModelPicker);
|
|
351
|
+
// The endpoint the active agent falls back to when no model is pinned, so
|
|
352
|
+
// the picker can name its "Server default" option. Fetched only when the
|
|
353
|
+
// picker is shown; `null` when the agent's model is dynamic.
|
|
354
|
+
const defaultModelName = useMastraDefaultModel(agentId, showModelPicker);
|
|
350
355
|
// Starter suggestions: an explicit `options.suggestions` always
|
|
351
356
|
// wins (including `[]` to force none) and is rendered verbatim;
|
|
352
357
|
// otherwise auto-source the agent's Genie space sample questions.
|
|
@@ -1333,6 +1338,7 @@ export const useMastraChat = (
|
|
|
1333
1338
|
models: showModelPicker ? models : undefined,
|
|
1334
1339
|
model,
|
|
1335
1340
|
onModelChange: showModelPicker ? setModel : undefined,
|
|
1341
|
+
defaultModelName: showModelPicker ? (defaultModelName ?? undefined) : undefined,
|
|
1336
1342
|
onLoadMore: loadOlderHistory,
|
|
1337
1343
|
isLoadingMore,
|
|
1338
1344
|
hasMore: activeSession.hasMoreHistory,
|
package/src/react/types.ts
CHANGED
|
@@ -116,6 +116,13 @@ export type ChatViewProps = {
|
|
|
116
116
|
/** Currently selected model name; empty string means "use server default". */
|
|
117
117
|
model?: string;
|
|
118
118
|
onModelChange?: (model: string) => void;
|
|
119
|
+
/**
|
|
120
|
+
* The serving-endpoint id the server falls back to when no model is pinned.
|
|
121
|
+
* When set, the picker's "Server default" option names it (e.g. "Server
|
|
122
|
+
* default (Claude Sonnet 4.6)"), using the matching `models` entry's
|
|
123
|
+
* `displayName` when available.
|
|
124
|
+
*/
|
|
125
|
+
defaultModelName?: string;
|
|
119
126
|
/**
|
|
120
127
|
* Optional infinite-scroll-up handler. Fired when the user scrolls
|
|
121
128
|
* within `TOP_LOAD_MORE_THRESHOLD_PX` of the top of the
|
|
@@ -174,6 +174,24 @@ export class MastraPluginClient extends MastraClient {
|
|
|
174
174
|
return payload.endpoints;
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Fetch the static default serving-endpoint id `agentId` falls back to
|
|
179
|
+
* when no model is pinned, from `GET ${basePath}/default-model`. Returns
|
|
180
|
+
* `null` when the agent resolves its model dynamically at call time (or the
|
|
181
|
+
* agent id is unknown) - there's nothing static to advertise. The picker
|
|
182
|
+
* uses this to name its "Server default" option. Defaults to the server's
|
|
183
|
+
* default agent when `agentId` is omitted.
|
|
184
|
+
*/
|
|
185
|
+
async defaultModel(agentId?: string, signal?: AbortSignal): Promise<string | null> {
|
|
186
|
+
const query = agentId ? `?agentId=${encodeURIComponent(agentId)}` : "";
|
|
187
|
+
const payload = await this.#getJson(
|
|
188
|
+
`${this.basePath}${routes.MASTRA_ROUTES.defaultModel}${query}`,
|
|
189
|
+
wire.DefaultModelResponseSchema,
|
|
190
|
+
signal,
|
|
191
|
+
);
|
|
192
|
+
return payload.model;
|
|
193
|
+
}
|
|
194
|
+
|
|
177
195
|
/**
|
|
178
196
|
* Fetch the curated starter questions for `agentId`'s Genie space
|
|
179
197
|
* from `GET ${basePath}/suggestions`. Empty when the agent has no
|
|
@@ -533,6 +551,38 @@ export const useMastraModels = (
|
|
|
533
551
|
return { models, loading, error };
|
|
534
552
|
};
|
|
535
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Fetch the static default serving-endpoint id the given agent (or the
|
|
556
|
+
* server's default agent) falls back to when no model is pinned, via
|
|
557
|
+
* `client.defaultModel(agentId)`. `null` while loading, when the agent's
|
|
558
|
+
* model is dynamic, or on error - the picker then shows a plain "Server
|
|
559
|
+
* default". Pass `enabled: false` to skip the fetch (e.g. picker hidden).
|
|
560
|
+
*/
|
|
561
|
+
export const useMastraDefaultModel = (
|
|
562
|
+
agentId?: string,
|
|
563
|
+
enabled = true,
|
|
564
|
+
): string | null => {
|
|
565
|
+
const client = useMastraClient();
|
|
566
|
+
const [model, setModel] = useState<string | null>(null);
|
|
567
|
+
|
|
568
|
+
useEffect(() => {
|
|
569
|
+
if (!enabled) return;
|
|
570
|
+
const controller = new AbortController();
|
|
571
|
+
client
|
|
572
|
+
.defaultModel(agentId, controller.signal)
|
|
573
|
+
.then((m) => {
|
|
574
|
+
if (!controller.signal.aborted) setModel(m);
|
|
575
|
+
})
|
|
576
|
+
.catch(() => {
|
|
577
|
+
// Non-critical: a missing default just yields a plain "Server default".
|
|
578
|
+
if (!controller.signal.aborted) setModel(null);
|
|
579
|
+
});
|
|
580
|
+
return () => controller.abort();
|
|
581
|
+
}, [client, agentId, enabled]);
|
|
582
|
+
|
|
583
|
+
return model;
|
|
584
|
+
};
|
|
585
|
+
|
|
536
586
|
/**
|
|
537
587
|
* Fetch the curated starter questions for an agent's Genie space via
|
|
538
588
|
* `client.suggestions(agentId)`. These are the `sample_questions` an
|