@dbx-tools/ui-mastra 0.9.153 → 0.9.157
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/index.react.ts +61 -0
- package/index.support.ts +40 -0
- package/index.ts +1 -79
- package/package.json +21 -10
- package/src/react/_assistant-response-status.tsx +1 -1
- package/src/react/_external-link-dialog.tsx +1 -1
- package/src/react/_model-selector.tsx +5 -5
- package/src/react/bubbles.tsx +3 -3
- package/src/react/chat-composer.tsx +1 -1
- package/src/react/chat-feedback.ts +5 -5
- package/src/react/chat-history.ts +4 -4
- package/src/react/chat-stream.ts +4 -5
- package/src/react/chat-thread-layout.tsx +9 -2
- package/src/react/chat-transcript.tsx +3 -3
- package/src/react/data-grid.tsx +4 -4
- package/src/react/embed-slots.tsx +10 -6
- package/src/react/export-menu.tsx +1 -1
- package/src/react/feedback-controls.tsx +1 -1
- package/src/react/markdown.tsx +2 -4
- package/src/react/mastra-assistant.tsx +1 -1
- package/src/react/mastra-chat.tsx +17 -17
- package/src/react/suggestion-pills.tsx +1 -1
- package/src/react/suggestions.ts +1 -1
- package/src/react/thread-sidebar.tsx +1 -1
- package/src/react/thread-tabs.tsx +1 -1
- package/src/react/tool-pill.tsx +7 -9
- package/src/react/types.ts +1 -3
- package/src/react/use-chat-thread-query.ts +27 -0
- package/src/support/chart-option.ts +2 -2
- package/src/support/chart-theme.ts +2 -2
- package/src/support/export.ts +10 -13
- package/src/support/genie-client.ts +22 -13
- package/src/support/mastra-client.ts +39 -32
- package/src/support/thread-sessions.ts +0 -2
- package/src/support/thread-tabs.ts +12 -2
- package/src/support/tool-events.ts +1 -1
- package/src/react/index.ts +0 -72
- package/src/support/index.ts +0 -32
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { getAuthStatus } from "@dbx-tools/shared-auth";
|
|
2
|
+
import { hash, log, toError } from "@dbx-tools/shared-core";
|
|
3
|
+
import { isStaleMastraResumeError } from "@dbx-tools/shared-mastra";
|
|
3
4
|
import type { ReasoningEffort } from "@dbx-tools/shared-model";
|
|
4
|
-
import { getAuthStatus } from "@dbx-tools/ui/auth/react";
|
|
5
5
|
import { useBrand } from "@dbx-tools/ui/branding/react";
|
|
6
6
|
import type { RequestContext } from "@mastra/client-js";
|
|
7
7
|
import type { FileUIPart, UIMessage } from "ai";
|
|
@@ -660,7 +660,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
660
660
|
}
|
|
661
661
|
logger.warn("chat stream disconnected; reconnecting to background run", {
|
|
662
662
|
runId,
|
|
663
|
-
error:
|
|
663
|
+
error: toError(initialError),
|
|
664
664
|
});
|
|
665
665
|
const messagesBeforeReplay = getSession(threadId).messages;
|
|
666
666
|
writeMessages(
|
|
@@ -705,7 +705,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
705
705
|
if (getSession(threadId).runToken !== token) return;
|
|
706
706
|
if (isStaleMastraResumeError(caught)) {
|
|
707
707
|
logger.warn("ignored stale mastra resume", {
|
|
708
|
-
error:
|
|
708
|
+
error: toError(caught),
|
|
709
709
|
});
|
|
710
710
|
updateSession(threadId, (session) => {
|
|
711
711
|
if (session.runToken !== token) return session;
|
|
@@ -725,11 +725,11 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
725
725
|
return;
|
|
726
726
|
}
|
|
727
727
|
logger.error("stream error", {
|
|
728
|
-
error:
|
|
728
|
+
error: toError(caught),
|
|
729
729
|
});
|
|
730
730
|
updateSession(threadId, (session) => ({
|
|
731
731
|
...session,
|
|
732
|
-
error:
|
|
732
|
+
error: toError(caught),
|
|
733
733
|
status: "error",
|
|
734
734
|
abortController: session.abortController === controller ? null : session.abortController,
|
|
735
735
|
runId: runIdRef.current,
|
|
@@ -905,7 +905,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
905
905
|
.catch((error: unknown) => {
|
|
906
906
|
logger.warn("failed to abort background run", {
|
|
907
907
|
runId: current.runId,
|
|
908
|
-
error:
|
|
908
|
+
error: toError(error),
|
|
909
909
|
});
|
|
910
910
|
});
|
|
911
911
|
}
|
|
@@ -948,7 +948,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
948
948
|
.catch((error: unknown) => {
|
|
949
949
|
logger.warn("failed to observe interrupted background run", {
|
|
950
950
|
runId,
|
|
951
|
-
error:
|
|
951
|
+
error: toError(error),
|
|
952
952
|
});
|
|
953
953
|
})
|
|
954
954
|
: undefined;
|
|
@@ -962,7 +962,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
962
962
|
.catch((error: unknown) => {
|
|
963
963
|
logger.warn("failed to abort interrupted background run", {
|
|
964
964
|
runId,
|
|
965
|
-
error:
|
|
965
|
+
error: toError(error),
|
|
966
966
|
});
|
|
967
967
|
})
|
|
968
968
|
: undefined;
|
|
@@ -1105,7 +1105,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1105
1105
|
logger.info("history cleared", { threadId });
|
|
1106
1106
|
} catch (error) {
|
|
1107
1107
|
logger.error("history clear error", {
|
|
1108
|
-
error:
|
|
1108
|
+
error: toError(error),
|
|
1109
1109
|
});
|
|
1110
1110
|
}
|
|
1111
1111
|
resetSession(threadId, true);
|
|
@@ -1164,7 +1164,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1164
1164
|
} catch (error) {
|
|
1165
1165
|
logger.error("thread delete error", {
|
|
1166
1166
|
threadId,
|
|
1167
|
-
error:
|
|
1167
|
+
error: toError(error),
|
|
1168
1168
|
});
|
|
1169
1169
|
setRemovedThreadIds((prev) => {
|
|
1170
1170
|
if (!prev.has(threadId)) return prev;
|
|
@@ -1207,7 +1207,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1207
1207
|
} catch (error) {
|
|
1208
1208
|
logger.error("thread rename error", {
|
|
1209
1209
|
threadId,
|
|
1210
|
-
error:
|
|
1210
|
+
error: toError(error),
|
|
1211
1211
|
});
|
|
1212
1212
|
setRenamedThreads((prev) => {
|
|
1213
1213
|
if (!(threadId in prev)) return prev;
|
|
@@ -1250,11 +1250,11 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1250
1250
|
.catch((error: unknown) => {
|
|
1251
1251
|
logger.error("regenerate cleanup error", {
|
|
1252
1252
|
threadId,
|
|
1253
|
-
error:
|
|
1253
|
+
error: toError(error),
|
|
1254
1254
|
});
|
|
1255
1255
|
updateSession(threadId, (session) => ({
|
|
1256
1256
|
...session,
|
|
1257
|
-
error:
|
|
1257
|
+
error: toError(error),
|
|
1258
1258
|
status: "error",
|
|
1259
1259
|
}));
|
|
1260
1260
|
});
|
|
@@ -1321,7 +1321,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1321
1321
|
} catch (error) {
|
|
1322
1322
|
logger.error("conversation export error", {
|
|
1323
1323
|
format,
|
|
1324
|
-
error:
|
|
1324
|
+
error: toError(error),
|
|
1325
1325
|
});
|
|
1326
1326
|
}
|
|
1327
1327
|
},
|
|
@@ -1343,7 +1343,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1343
1343
|
} catch (error) {
|
|
1344
1344
|
logger.error("message export error", {
|
|
1345
1345
|
format,
|
|
1346
|
-
error:
|
|
1346
|
+
error: toError(error),
|
|
1347
1347
|
});
|
|
1348
1348
|
}
|
|
1349
1349
|
},
|
package/src/react/suggestions.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
FOLLOW_UP_SUGGESTIONS_PART_TYPE,
|
|
3
3
|
FollowUpSuggestionsPartDataSchema,
|
|
4
4
|
type FollowUpSuggestionMode,
|
|
5
|
-
} from "@dbx-tools/shared-mastra
|
|
5
|
+
} from "@dbx-tools/shared-mastra";
|
|
6
6
|
import type { UIMessage } from "ai";
|
|
7
7
|
import type { ToolEvent, ToolProgress } from "./types.ts";
|
|
8
8
|
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
TooltipContent,
|
|
8
8
|
TooltipTrigger,
|
|
9
9
|
cn,
|
|
10
|
-
} from "@
|
|
10
|
+
} from "@databricks/appkit-ui/react";
|
|
11
11
|
import { HistoryIcon, Loader2Icon, PlusIcon, XIcon } from "lucide-react";
|
|
12
12
|
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
13
13
|
import { ThreadSidebar, type ThreadSidebarProps } from "./thread-sidebar.tsx";
|
package/src/react/tool-pill.tsx
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { json, stringUtils } from "@dbx-tools/shared-core";
|
|
2
|
-
import { genieModel } from "@dbx-tools/shared-genie";
|
|
3
1
|
import {
|
|
4
2
|
Collapsible,
|
|
5
3
|
CollapsibleContent,
|
|
6
4
|
CollapsibleTrigger,
|
|
7
|
-
detectCodeLanguage,
|
|
8
|
-
JsonBlock,
|
|
9
|
-
RecordPreview,
|
|
10
5
|
Spinner,
|
|
11
6
|
cn,
|
|
12
|
-
} from "@
|
|
7
|
+
} from "@databricks/appkit-ui/react";
|
|
8
|
+
import { parse, toLabel, capitalize } from "@dbx-tools/shared-core";
|
|
9
|
+
import { humanizeStatus } from "@dbx-tools/shared-genie";
|
|
10
|
+
import { detectCodeLanguage, JsonBlock, RecordPreview } from "@dbx-tools/ui/react";
|
|
13
11
|
import { CheckIcon, ChevronDownIcon, XIcon } from "lucide-react";
|
|
14
12
|
import { SourceBlock, ToolMarkdown } from "./markdown.tsx";
|
|
15
13
|
import type { ToolEvent, ToolProgress } from "./types.ts";
|
|
@@ -49,7 +47,7 @@ export const humanizeToolName = (toolName: string): string => {
|
|
|
49
47
|
const label = toolName.startsWith(MASTRA_WORKSPACE_TOOL_PREFIX)
|
|
50
48
|
? toolName.slice(MASTRA_WORKSPACE_TOOL_PREFIX.length)
|
|
51
49
|
: toolName;
|
|
52
|
-
return
|
|
50
|
+
return toLabel(label);
|
|
53
51
|
};
|
|
54
52
|
|
|
55
53
|
/**
|
|
@@ -69,7 +67,7 @@ const runningLabelFor = (event: ToolEvent): string => {
|
|
|
69
67
|
.reverse()
|
|
70
68
|
.find((p): p is Extract<ToolProgress, { type: "status" }> => p.type === "status");
|
|
71
69
|
return latest
|
|
72
|
-
?
|
|
70
|
+
? capitalize(humanizeStatus(latest.status))
|
|
73
71
|
: `Calling ${humanizeToolName(event.toolName)}`;
|
|
74
72
|
};
|
|
75
73
|
|
|
@@ -393,7 +391,7 @@ export function structuredToolPayload(value: unknown): unknown | undefined {
|
|
|
393
391
|
if (typeof value !== "string") return undefined;
|
|
394
392
|
const trimmed = value.trim();
|
|
395
393
|
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return undefined;
|
|
396
|
-
const parsed =
|
|
394
|
+
const parsed = parse(trimmed);
|
|
397
395
|
return typeof parsed === "object" && parsed !== null ? parsed : undefined;
|
|
398
396
|
}
|
|
399
397
|
|
package/src/react/types.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import type { FollowUpSuggestionMode, ToolProgressEvent } from "@dbx-tools/shared-mastra
|
|
1
|
+
import type { FollowUpSuggestionMode, ToolProgressEvent } from "@dbx-tools/shared-mastra";
|
|
2
2
|
import type { ReasoningEffort, ServingEndpointSummary } from "@dbx-tools/shared-model";
|
|
3
3
|
import type { FileUIPart, UIMessage } from "ai";
|
|
4
4
|
import type { ReactNode } from "react";
|
|
5
5
|
import type { ExportFormat } from "../support/export.ts";
|
|
6
6
|
|
|
7
|
-
export type { ExportFormat } from "../support/export.ts";
|
|
8
|
-
|
|
9
7
|
// Public types for the chat UI: the controlled `ChatView` props plus
|
|
10
8
|
// the supporting tool-event / approval shapes a host transport feeds
|
|
11
9
|
// it. Kept dependency-free of the components so both the presentational
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { useSearchParams } from "react-router-dom";
|
|
3
|
+
import type { ThreadIdChangeReason } from "./mastra-chat.tsx";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_THREAD_PARAMETER = "thread";
|
|
6
|
+
|
|
7
|
+
/** Bind Mastra's active thread to one URL search parameter. */
|
|
8
|
+
export function useChatThreadQuery(parameter = DEFAULT_THREAD_PARAMETER) {
|
|
9
|
+
const [searchParams, setSearchParams] = useSearchParams();
|
|
10
|
+
const threadId = searchParams.get(parameter)?.trim() || undefined;
|
|
11
|
+
const onThreadIdChange = useCallback(
|
|
12
|
+
(nextThreadId: string, reason: ThreadIdChangeReason) => {
|
|
13
|
+
setSearchParams(
|
|
14
|
+
(current) => {
|
|
15
|
+
if (current.get(parameter) === nextThreadId) return current;
|
|
16
|
+
const next = new URLSearchParams(current);
|
|
17
|
+
next.set(parameter, nextThreadId);
|
|
18
|
+
return next;
|
|
19
|
+
},
|
|
20
|
+
{ replace: reason === "hydrate" || reason === "missing" || reason === "delete" },
|
|
21
|
+
);
|
|
22
|
+
},
|
|
23
|
+
[parameter, setSearchParams],
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return { threadId, onThreadIdChange };
|
|
27
|
+
}
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @module
|
|
29
29
|
*/
|
|
30
|
-
import {
|
|
30
|
+
import { isRecord } from "@dbx-tools/shared-core";
|
|
31
31
|
import type { ChartChrome } from "./chart-theme.ts";
|
|
32
32
|
|
|
33
33
|
/** Compact SI formatter shared across every value-axis tick. */
|
|
@@ -52,7 +52,7 @@ function compactAxisLabel(value: number): string {
|
|
|
52
52
|
/** A permissive record view of an option node we patch field-by-field. */
|
|
53
53
|
type Obj = Record<string, unknown>;
|
|
54
54
|
|
|
55
|
-
const isObj =
|
|
55
|
+
const isObj = isRecord;
|
|
56
56
|
|
|
57
57
|
/** True when `title` (object or array) carries any non-empty `text`. */
|
|
58
58
|
function hasTitleText(title: unknown): boolean {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
* @module
|
|
22
22
|
*/
|
|
23
|
-
import {
|
|
23
|
+
import { deepEqual } from "@dbx-tools/shared-core";
|
|
24
24
|
import { type RefObject, useEffect, useState } from "react";
|
|
25
25
|
|
|
26
26
|
/**
|
|
@@ -122,7 +122,7 @@ export function useChartChrome(ref: RefObject<Element | null>): ChartChrome | un
|
|
|
122
122
|
useEffect(() => {
|
|
123
123
|
const read = () => {
|
|
124
124
|
const next = resolveChartChrome(ref.current);
|
|
125
|
-
setChrome((prev) => (
|
|
125
|
+
setChrome((prev) => (deepEqual(prev, next) ? prev : next));
|
|
126
126
|
};
|
|
127
127
|
read();
|
|
128
128
|
const observer = new MutationObserver(read);
|
package/src/support/export.ts
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
26
|
+
import { capitalize, toLabel, toSlugWithOptions, escapeHtml } from "@dbx-tools/shared-core";
|
|
27
|
+
import { type Chart, type StatementData, parseMarkers, isUuid } from "@dbx-tools/shared-mastra";
|
|
28
28
|
import type { UIMessage } from "ai";
|
|
29
29
|
import type { EChartsCoreOption } from "echarts";
|
|
30
30
|
import { normalizeChartOption } from "./chart-option.ts";
|
|
@@ -199,15 +199,15 @@ type Segment =
|
|
|
199
199
|
function splitSegments(text: string): Segment[] {
|
|
200
200
|
const segments: Segment[] = [];
|
|
201
201
|
let last = 0;
|
|
202
|
-
for (const marker of
|
|
202
|
+
for (const marker of parseMarkers(text)) {
|
|
203
203
|
if (marker.start > last) {
|
|
204
204
|
segments.push({ kind: "text", text: text.slice(last, marker.start) });
|
|
205
205
|
}
|
|
206
|
-
if (
|
|
206
|
+
if (isUuid(marker.id) && marker.type === "chart") {
|
|
207
207
|
segments.push({ kind: "chart", id: marker.id });
|
|
208
|
-
} else if (
|
|
208
|
+
} else if (isUuid(marker.id) && marker.type === "data") {
|
|
209
209
|
segments.push({ kind: "data", id: marker.id });
|
|
210
|
-
} else if (
|
|
210
|
+
} else if (isUuid(marker.id) && marker.type === "visualization") {
|
|
211
211
|
segments.push({ kind: "visualization", id: marker.id });
|
|
212
212
|
}
|
|
213
213
|
last = marker.end;
|
|
@@ -232,7 +232,7 @@ export function messageText(message: UIMessage): string {
|
|
|
232
232
|
function roleLabel(role: UIMessage["role"], userLabel: string): string {
|
|
233
233
|
if (role === "user") return userLabel;
|
|
234
234
|
if (role === "assistant") return "Assistant";
|
|
235
|
-
return
|
|
235
|
+
return capitalize(role);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
/* --------------------------------- HTML ---------------------------------- */
|
|
@@ -345,7 +345,7 @@ async function dataTableHtml(
|
|
|
345
345
|
): Promise<string | null> {
|
|
346
346
|
const data = await safeStatement(resolver, id, visualization);
|
|
347
347
|
if (!data || data.rows.length === 0) return null;
|
|
348
|
-
const head = data.columns.map((c) => `<th>${escapeHtml(
|
|
348
|
+
const head = data.columns.map((c) => `<th>${escapeHtml(toLabel(c))}</th>`).join("");
|
|
349
349
|
const body = data.rows
|
|
350
350
|
.map(
|
|
351
351
|
(row) =>
|
|
@@ -417,7 +417,7 @@ async function dataTableMarkdown(
|
|
|
417
417
|
): Promise<string | null> {
|
|
418
418
|
const data = await safeStatement(resolver, id, visualization);
|
|
419
419
|
if (!data || data.rows.length === 0) return null;
|
|
420
|
-
const header = `| ${data.columns.map((c) => mdCell(
|
|
420
|
+
const header = `| ${data.columns.map((c) => mdCell(toLabel(c))).join(" | ")} |`;
|
|
421
421
|
const sep = `| ${data.columns.map(() => "---").join(" | ")} |`;
|
|
422
422
|
const rows = data.rows.map(
|
|
423
423
|
(row) => `| ${data.columns.map((c) => mdCell(cellText(row[c]))).join(" | ")} |`,
|
|
@@ -462,12 +462,9 @@ function mdCell(value: string): string {
|
|
|
462
462
|
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
-
/** Escape HTML-significant characters (from the shared string utils). */
|
|
466
|
-
const escapeHtml = stringUtils.escapeHtml;
|
|
467
|
-
|
|
468
465
|
/** Turn a title into a safe, lowercase filename stem. */
|
|
469
466
|
function slugify(value: string): string {
|
|
470
|
-
return
|
|
467
|
+
return toSlugWithOptions({ maxLength: 60 }, value) || "conversation";
|
|
471
468
|
}
|
|
472
469
|
|
|
473
470
|
/**
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type MastraClientConfig,
|
|
3
|
+
genieRoutePath,
|
|
4
|
+
MASTRA_ROUTES,
|
|
5
|
+
GENIE_CONVERSATION_PART_TYPE,
|
|
6
|
+
GenieConversationPartDataSchema,
|
|
7
|
+
MastraSuggestionsResponseSchema,
|
|
8
|
+
GenieThreadsResponseSchema,
|
|
9
|
+
GenieThreadMessagesResponseSchema,
|
|
10
|
+
} from "@dbx-tools/shared-mastra";
|
|
2
11
|
import type {
|
|
3
12
|
ListAgentSuspendedRunsResponse,
|
|
4
13
|
ListMemoryThreadMessagesResponse,
|
|
@@ -44,7 +53,7 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
#url(...parts: string[]): string {
|
|
47
|
-
return `${this.basePath}${
|
|
56
|
+
return `${this.basePath}${genieRoutePath(this.alias, ...parts)}`;
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
async #delete(url: string, signal?: AbortSignal): Promise<void> {
|
|
@@ -72,7 +81,7 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
72
81
|
const conversationId =
|
|
73
82
|
params.threadId && this.#conversations.has(params.threadId) ? params.threadId : undefined;
|
|
74
83
|
const response = await this.uiStream({
|
|
75
|
-
path: this.#url(
|
|
84
|
+
path: this.#url(MASTRA_ROUTES.chat),
|
|
76
85
|
chatId: params.threadId ?? params.runId,
|
|
77
86
|
messages: userMessage ? [userMessage] : [],
|
|
78
87
|
body: {
|
|
@@ -87,8 +96,8 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
87
96
|
const stream = response.stream.pipeThrough(
|
|
88
97
|
new TransformStream<UIMessageChunk, UIMessageChunk>({
|
|
89
98
|
transform: (chunk, controller) => {
|
|
90
|
-
if (chunk.type ===
|
|
91
|
-
const data =
|
|
99
|
+
if (chunk.type === GENIE_CONVERSATION_PART_TYPE) {
|
|
100
|
+
const data = GenieConversationPartDataSchema.safeParse(chunk.data);
|
|
92
101
|
if (data.success) {
|
|
93
102
|
resolved = data.data.conversationId;
|
|
94
103
|
this.#conversations.add(resolved);
|
|
@@ -122,8 +131,8 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
122
131
|
/** Starter questions for this client's Genie space. */
|
|
123
132
|
override async suggestions(_agentId?: string, signal?: AbortSignal): Promise<string[]> {
|
|
124
133
|
const payload = await this.getJson(
|
|
125
|
-
this.#url(
|
|
126
|
-
|
|
134
|
+
this.#url(MASTRA_ROUTES.suggestions),
|
|
135
|
+
MastraSuggestionsResponseSchema,
|
|
127
136
|
signal,
|
|
128
137
|
);
|
|
129
138
|
return payload.questions;
|
|
@@ -134,8 +143,8 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
134
143
|
options: { signal?: AbortSignal } = {},
|
|
135
144
|
): Promise<ListMemoryThreadsResponse> {
|
|
136
145
|
const payload = await this.getJson(
|
|
137
|
-
this.#url(
|
|
138
|
-
|
|
146
|
+
this.#url(MASTRA_ROUTES.threads),
|
|
147
|
+
GenieThreadsResponseSchema,
|
|
139
148
|
options.signal,
|
|
140
149
|
);
|
|
141
150
|
for (const thread of payload.threads) this.#conversations.add(thread.id);
|
|
@@ -169,8 +178,8 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
169
178
|
let messages: UIMessage[] = [];
|
|
170
179
|
if (page === 0) {
|
|
171
180
|
const payload = await this.getJson(
|
|
172
|
-
this.#url(
|
|
173
|
-
|
|
181
|
+
this.#url(MASTRA_ROUTES.threads, options.threadId, MASTRA_ROUTES.messages),
|
|
182
|
+
GenieThreadMessagesResponseSchema,
|
|
174
183
|
options.signal,
|
|
175
184
|
);
|
|
176
185
|
messages = await validateUIMessages({ messages: payload.messages });
|
|
@@ -195,7 +204,7 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
195
204
|
options: { signal?: AbortSignal } = {},
|
|
196
205
|
): Promise<void> {
|
|
197
206
|
if (!this.#conversations.has(threadId)) return;
|
|
198
|
-
await this.#delete(this.#url(
|
|
207
|
+
await this.#delete(this.#url(MASTRA_ROUTES.threads, threadId), options.signal);
|
|
199
208
|
this.#conversations.delete(threadId);
|
|
200
209
|
}
|
|
201
210
|
|
|
@@ -224,7 +233,7 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
224
233
|
);
|
|
225
234
|
for (const genieId of genieIds) {
|
|
226
235
|
await this.#delete(
|
|
227
|
-
this.#url(
|
|
236
|
+
this.#url(MASTRA_ROUTES.threads, threadId, MASTRA_ROUTES.messages, genieId),
|
|
228
237
|
options.signal,
|
|
229
238
|
);
|
|
230
239
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { usePluginClientConfig } from "@databricks/appkit-ui/react";
|
|
2
|
+
import { toError } from "@dbx-tools/shared-core";
|
|
2
3
|
import {
|
|
3
|
-
feedback,
|
|
4
|
-
override,
|
|
5
|
-
routes,
|
|
6
|
-
thread,
|
|
7
|
-
wire,
|
|
8
4
|
type Chart,
|
|
9
5
|
type DefaultModelResponse,
|
|
10
6
|
type MastraClientConfig,
|
|
@@ -12,9 +8,20 @@ import {
|
|
|
12
8
|
type MastraFeedbackResponse,
|
|
13
9
|
type MastraMlflowExperimentResponse,
|
|
14
10
|
type StatementData,
|
|
11
|
+
type FeedbackMode,
|
|
12
|
+
MastraFeedbackResponseSchema,
|
|
13
|
+
MastraMlflowExperimentResponseSchema,
|
|
14
|
+
MODEL_OVERRIDE_HEADER,
|
|
15
|
+
MASTRA_ROUTES,
|
|
16
|
+
THREAD_ID_HEADER,
|
|
17
|
+
MastraRunAbortResponseSchema,
|
|
18
|
+
ServingEndpointsResponseSchema,
|
|
19
|
+
DefaultModelResponseSchema,
|
|
20
|
+
MastraSuggestionsResponseSchema,
|
|
21
|
+
ChartSchema,
|
|
22
|
+
StatementDataSchema,
|
|
15
23
|
} from "@dbx-tools/shared-mastra";
|
|
16
24
|
import type { ReasoningEffort, ServingEndpointSummary } from "@dbx-tools/shared-model";
|
|
17
|
-
import { usePluginClientConfig } from "@dbx-tools/ui/react";
|
|
18
25
|
import {
|
|
19
26
|
MastraClient,
|
|
20
27
|
type ListAgentSuspendedRunsResponse,
|
|
@@ -80,7 +87,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
80
87
|
/** Registered agent ids, surfaced for pickers. */
|
|
81
88
|
readonly agents: readonly string[];
|
|
82
89
|
/** Resolved feedback destination published by the server. */
|
|
83
|
-
readonly feedbackMode:
|
|
90
|
+
readonly feedbackMode: FeedbackMode;
|
|
84
91
|
/**
|
|
85
92
|
* Whether the agents run their Databricks calls as the app service principal
|
|
86
93
|
* rather than on-behalf-of the signed-in user. When `true` the chat works for
|
|
@@ -131,8 +138,8 @@ export class MastraPluginClient extends MastraClient {
|
|
|
131
138
|
*/
|
|
132
139
|
#routingHeaders(routing: { threadId?: string; model?: string }): Record<string, string> {
|
|
133
140
|
const headers: Record<string, string> = {};
|
|
134
|
-
if (routing.threadId) headers[
|
|
135
|
-
if (routing.model) headers[
|
|
141
|
+
if (routing.threadId) headers[THREAD_ID_HEADER] = routing.threadId;
|
|
142
|
+
if (routing.model) headers[MODEL_OVERRIDE_HEADER] = routing.model;
|
|
136
143
|
return headers;
|
|
137
144
|
}
|
|
138
145
|
|
|
@@ -232,7 +239,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
232
239
|
signal?: AbortSignal;
|
|
233
240
|
}): Promise<MastraStreamResponse> {
|
|
234
241
|
return this.uiStream({
|
|
235
|
-
path: `${this.basePath}${
|
|
242
|
+
path: `${this.basePath}${MASTRA_ROUTES.chat}/${encodeURIComponent(params.agentId)}`,
|
|
236
243
|
chatId: params.threadId ?? params.runId,
|
|
237
244
|
messages: params.messages,
|
|
238
245
|
body: {
|
|
@@ -256,7 +263,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
256
263
|
signal?: AbortSignal;
|
|
257
264
|
}): Promise<MastraStreamResponse> {
|
|
258
265
|
return this.#uiReconnect({
|
|
259
|
-
path: `${this.basePath}${
|
|
266
|
+
path: `${this.basePath}${MASTRA_ROUTES.chat}/${encodeURIComponent(params.agentId)}${MASTRA_ROUTES.runs}/${encodeURIComponent(params.runId)}`,
|
|
260
267
|
chatId: params.runId,
|
|
261
268
|
routing: params,
|
|
262
269
|
signal: params.signal,
|
|
@@ -273,11 +280,11 @@ export class MastraPluginClient extends MastraClient {
|
|
|
273
280
|
const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
|
|
274
281
|
const response = await this.#mutateJson(
|
|
275
282
|
new URL(
|
|
276
|
-
`${this.basePath}${
|
|
283
|
+
`${this.basePath}${MASTRA_ROUTES.chat}/${encodeURIComponent(params.agentId)}${MASTRA_ROUTES.runs}/${encodeURIComponent(params.runId)}${MASTRA_ROUTES.abort}`,
|
|
277
284
|
origin,
|
|
278
285
|
).toString(),
|
|
279
286
|
"POST",
|
|
280
|
-
|
|
287
|
+
MastraRunAbortResponseSchema,
|
|
281
288
|
{
|
|
282
289
|
headers: this.#routingHeaders({ threadId: params.threadId }),
|
|
283
290
|
signal: params.signal,
|
|
@@ -333,7 +340,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
333
340
|
},
|
|
334
341
|
): Promise<MastraStreamResponse> {
|
|
335
342
|
return this.uiStream({
|
|
336
|
-
path: `${this.basePath}${
|
|
343
|
+
path: `${this.basePath}${MASTRA_ROUTES.chat}/${encodeURIComponent(agentId)}`,
|
|
337
344
|
chatId: params.threadId ?? params.runId,
|
|
338
345
|
messages: [],
|
|
339
346
|
body: {
|
|
@@ -358,8 +365,8 @@ export class MastraPluginClient extends MastraClient {
|
|
|
358
365
|
*/
|
|
359
366
|
async models(signal?: AbortSignal): Promise<ServingEndpointSummary[]> {
|
|
360
367
|
const payload = await this.getJson(
|
|
361
|
-
`${this.basePath}${
|
|
362
|
-
|
|
368
|
+
`${this.basePath}${MASTRA_ROUTES.models}`,
|
|
369
|
+
ServingEndpointsResponseSchema,
|
|
363
370
|
signal,
|
|
364
371
|
);
|
|
365
372
|
return payload.endpoints;
|
|
@@ -382,8 +389,8 @@ export class MastraPluginClient extends MastraClient {
|
|
|
382
389
|
/** Fetch the complete resolved default-model descriptor for an agent. */
|
|
383
390
|
async defaultModelDetails(agentId?: string, signal?: AbortSignal): Promise<DefaultModelResponse> {
|
|
384
391
|
const payload = await this.getJson(
|
|
385
|
-
this.#agentScoped(
|
|
386
|
-
|
|
392
|
+
this.#agentScoped(MASTRA_ROUTES.defaultModel, agentId),
|
|
393
|
+
DefaultModelResponseSchema,
|
|
387
394
|
signal,
|
|
388
395
|
);
|
|
389
396
|
return payload;
|
|
@@ -396,8 +403,8 @@ export class MastraPluginClient extends MastraClient {
|
|
|
396
403
|
*/
|
|
397
404
|
async suggestions(agentId?: string, signal?: AbortSignal): Promise<string[]> {
|
|
398
405
|
const payload = await this.getJson(
|
|
399
|
-
this.#agentScoped(
|
|
400
|
-
|
|
406
|
+
this.#agentScoped(MASTRA_ROUTES.suggestions, agentId),
|
|
407
|
+
MastraSuggestionsResponseSchema,
|
|
401
408
|
signal,
|
|
402
409
|
);
|
|
403
410
|
return payload.questions;
|
|
@@ -512,9 +519,9 @@ export class MastraPluginClient extends MastraClient {
|
|
|
512
519
|
*/
|
|
513
520
|
async feedback(input: MastraFeedbackRequest): Promise<MastraFeedbackResponse> {
|
|
514
521
|
return this.#mutateJson(
|
|
515
|
-
`${this.basePath}${
|
|
522
|
+
`${this.basePath}${MASTRA_ROUTES.feedback}`,
|
|
516
523
|
"POST",
|
|
517
|
-
|
|
524
|
+
MastraFeedbackResponseSchema,
|
|
518
525
|
{ body: input },
|
|
519
526
|
);
|
|
520
527
|
}
|
|
@@ -526,8 +533,8 @@ export class MastraPluginClient extends MastraClient {
|
|
|
526
533
|
*/
|
|
527
534
|
async mlflowExperiment(signal?: AbortSignal): Promise<MastraMlflowExperimentResponse> {
|
|
528
535
|
return this.getJson(
|
|
529
|
-
`${this.basePath}${
|
|
530
|
-
|
|
536
|
+
`${this.basePath}${MASTRA_ROUTES.mlflowExperiment}`,
|
|
537
|
+
MastraMlflowExperimentResponseSchema,
|
|
531
538
|
signal,
|
|
532
539
|
);
|
|
533
540
|
}
|
|
@@ -540,7 +547,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
540
547
|
* resolves to `undefined` so the slot renders nothing.
|
|
541
548
|
*/
|
|
542
549
|
chart(id: string, signal?: AbortSignal): Promise<Chart | undefined> {
|
|
543
|
-
return this.#embed("chart", id,
|
|
550
|
+
return this.#embed("chart", id, ChartSchema.parse, signal);
|
|
544
551
|
}
|
|
545
552
|
|
|
546
553
|
/**
|
|
@@ -550,12 +557,12 @@ export class MastraPluginClient extends MastraClient {
|
|
|
550
557
|
* `undefined`.
|
|
551
558
|
*/
|
|
552
559
|
statement(id: string, signal?: AbortSignal): Promise<StatementData | undefined> {
|
|
553
|
-
return this.#embed("data", id,
|
|
560
|
+
return this.#embed("data", id, StatementDataSchema.parse, signal);
|
|
554
561
|
}
|
|
555
562
|
|
|
556
563
|
/** Resolve AppKit UI visualization data for a direct Genie statement. */
|
|
557
564
|
visualization(id: string, signal?: AbortSignal): Promise<StatementData | undefined> {
|
|
558
|
-
return this.#embed("visualization", id,
|
|
565
|
+
return this.#embed("visualization", id, StatementDataSchema.parse, signal);
|
|
559
566
|
}
|
|
560
567
|
|
|
561
568
|
/**
|
|
@@ -638,7 +645,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
638
645
|
parse: (raw: unknown) => T,
|
|
639
646
|
signal?: AbortSignal,
|
|
640
647
|
): Promise<T | undefined> {
|
|
641
|
-
const url = `${this.basePath}${
|
|
648
|
+
const url = `${this.basePath}${MASTRA_ROUTES.embed}/${encodeURIComponent(
|
|
642
649
|
type,
|
|
643
650
|
)}/${encodeURIComponent(id)}`;
|
|
644
651
|
const init: RequestInit = { credentials: "include" };
|
|
@@ -792,7 +799,7 @@ export const useMastraModels = (
|
|
|
792
799
|
})
|
|
793
800
|
.catch((e: unknown) => {
|
|
794
801
|
if (controller.signal.aborted) return;
|
|
795
|
-
setError(
|
|
802
|
+
setError(toError(e));
|
|
796
803
|
})
|
|
797
804
|
.finally(() => {
|
|
798
805
|
if (!controller.signal.aborted) setLoading(false);
|
|
@@ -960,7 +967,7 @@ export const useMastraThreads = (
|
|
|
960
967
|
})
|
|
961
968
|
.catch((e: unknown) => {
|
|
962
969
|
if (controller.signal.aborted || (e as { name?: string }).name === "AbortError") return;
|
|
963
|
-
setError(
|
|
970
|
+
setError(toError(e));
|
|
964
971
|
setThreads([]);
|
|
965
972
|
})
|
|
966
973
|
.finally(() => {
|
|
@@ -1125,7 +1132,7 @@ function useByIdFetch<T>(
|
|
|
1125
1132
|
})
|
|
1126
1133
|
.catch((e: unknown) => {
|
|
1127
1134
|
if (cancelled) return;
|
|
1128
|
-
setError(
|
|
1135
|
+
setError(toError(e));
|
|
1129
1136
|
setLoading(false);
|
|
1130
1137
|
});
|
|
1131
1138
|
|
|
@@ -2,8 +2,6 @@ import type { RequestContext } from "@mastra/client-js";
|
|
|
2
2
|
import type { UIMessage } from "ai";
|
|
3
3
|
import type { ChatStatus, MessageFeedback, PendingApproval, QueuedSteer } from "../react/types.ts";
|
|
4
4
|
|
|
5
|
-
export type { QueuedSteer } from "../react/types.ts";
|
|
6
|
-
|
|
7
5
|
/** A queued steer plus the application context captured when it was submitted. */
|
|
8
6
|
export type SessionQueuedSteer = QueuedSteer & {
|
|
9
7
|
requestContext?: RequestContext;
|