@dbx-tools/ui-mastra 0.9.119 → 0.9.121

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 CHANGED
@@ -288,6 +288,7 @@ export function ReviewChat(props: ChatViewProps) {
288
288
  sidebar, transcript, tool progress, approval cards, suggestions, export controls,
289
289
  feedback controls, and composer from props. Use it when your app already has a
290
290
  transport or needs to combine Mastra messages with another state model.
291
+
291
292
  `MastraChat` shows a spinner in the model control while its live default model
292
293
  is being resolved. The picker groups endpoints into
293
294
  model-family submenus. Its compact first popup shows only the current
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.9.119";
6
+ export const PACKAGE_VERSION = "0.9.121";
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";
@@ -71,7 +71,7 @@ export type { StoredActiveRun } from "./src/support/active-runs.ts";
71
71
  export { LIGHT_CHART_CHROME } from "./src/support/chart-theme.ts";
72
72
  export type { ChartChrome } from "./src/support/chart-theme.ts";
73
73
  export type { ExportFormat, ExportBrand, EmbedResolver, ExportChatOptions } from "./src/support/export.ts";
74
- export { MastraPluginClient, useMastraConfig, useMastraClient, useMastraMlflowExperiment, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch } from "./src/support/mastra-client.ts";
74
+ export { MastraChatRequestError, MastraPluginClient, useMastraConfig, useMastraClient, useMastraMlflowExperiment, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch } from "./src/support/mastra-client.ts";
75
75
  export type { MastraStreamResponse, MastraMemoryThread, ByIdFetchState } from "./src/support/mastra-client.ts";
76
76
  export { defaultReasoningEffort, modelStorageKey, readStoredModel, storeSelectedModel } from "./src/support/model-selection.ts";
77
77
  export type { MastraRequestContextInput, MastraRequestContextSource, MastraRequestContextSnapshot } from "./src/support/request-context.ts";
package/package.json CHANGED
@@ -29,11 +29,11 @@
29
29
  "react-dom": "~19.2.4"
30
30
  },
31
31
  "dependencies": {
32
- "@dbx-tools/shared-core": "^0.9.119",
33
- "@dbx-tools/shared-genie": "^0.9.119",
34
- "@dbx-tools/shared-mastra": "^0.9.119",
35
- "@dbx-tools/shared-model": "^0.9.119",
36
- "@dbx-tools/ui": "^0.9.119",
32
+ "@dbx-tools/shared-core": "^0.9.121",
33
+ "@dbx-tools/shared-genie": "^0.9.121",
34
+ "@dbx-tools/shared-mastra": "^0.9.121",
35
+ "@dbx-tools/shared-model": "^0.9.121",
36
+ "@dbx-tools/ui": "^0.9.121",
37
37
  "@mastra/client-js": "1.50.0",
38
38
  "@mastra/core": "1.71.0",
39
39
  "@tanstack/react-table": "^8.21.3",
@@ -50,7 +50,7 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "version": "0.9.119",
53
+ "version": "0.9.121",
54
54
  "dbxToolsConfig": {
55
55
  "tags": [
56
56
  "ui"
@@ -340,6 +340,7 @@ type AssistantBubbleProps = {
340
340
  mlflowExperimentUrl?: string;
341
341
  };
342
342
 
343
+ /** Render one assistant message with tool progress, actions, and optional feedback. */
343
344
  export const AssistantBubble = ({
344
345
  message,
345
346
  isLast,
@@ -523,6 +524,7 @@ export const AssistantBubble = ({
523
524
  );
524
525
  };
525
526
 
527
+ /** Render one user message, including text and image attachments. */
526
528
  export const UserBubble = ({ message }: { message: UIMessage }) => {
527
529
  const text = message.parts
528
530
  .filter((p): p is { type: "text"; text: string } => p.type === "text")
@@ -423,7 +423,7 @@ export const ChatComposer = ({
423
423
  }}
424
424
  placeholder="Send a message..."
425
425
  rows={1}
426
- className="field-sizing-fixed min-h-10 max-h-64 w-full flex-none overflow-y-auto px-4 pb-2 pt-4 text-base md:text-xs"
426
+ className="field-sizing-fixed min-h-10 max-h-64 w-full flex-none overflow-y-auto px-4 pb-2 pt-4 text-sm"
427
427
  />
428
428
  {fileError && (
429
429
  <div className="px-4 text-xs text-destructive" role="alert">
@@ -51,7 +51,7 @@ export function useChatFeedback({
51
51
  } catch (error) {
52
52
  logger.error("feedback error", {
53
53
  traceId,
54
- error: errorUtils.errorMessage(error),
54
+ error: errorUtils.toError(error),
55
55
  });
56
56
  }
57
57
  },
@@ -116,7 +116,7 @@ export function useChatHistory({
116
116
  .catch((error: unknown) => {
117
117
  if ((error as { name?: string }).name === "AbortError") throw error;
118
118
  logger.warn("suspended-run discovery error", {
119
- error: errorUtils.errorMessage(error),
119
+ error: errorUtils.toError(error),
120
120
  });
121
121
  return { runs: [], total: 0 };
122
122
  });
@@ -140,7 +140,7 @@ export function useChatHistory({
140
140
  .catch((error: unknown) => {
141
141
  if (cancelled || (error as { name?: string }).name === "AbortError") return;
142
142
  logger.error("history load error", {
143
- error: errorUtils.errorMessage(error),
143
+ error: errorUtils.toError(error),
144
144
  });
145
145
  updateSession(threadId, (current) => ({
146
146
  ...current,
@@ -181,7 +181,7 @@ export function useChatHistory({
181
181
  .catch((error: unknown) => {
182
182
  logger.error("history load-more error", {
183
183
  page,
184
- error: errorUtils.errorMessage(error),
184
+ error: errorUtils.toError(error),
185
185
  });
186
186
  updateSession(threadId, (current) => ({
187
187
  ...current,
@@ -8,13 +8,16 @@ import {
8
8
  type ThreadSession,
9
9
  } from "../support/thread-sessions.ts";
10
10
 
11
+ /** Read or lazily create the mutable session state for one thread. */
11
12
  export type ThreadSessionReader = (threadId: string) => ThreadSession;
12
13
 
14
+ /** Replace one thread session through a state-producing callback. */
13
15
  export type ThreadSessionUpdater = (
14
16
  threadId: string,
15
17
  updater: (session: ThreadSession) => ThreadSession,
16
18
  ) => void;
17
19
 
20
+ /** Replace the transcript stored for one thread. */
18
21
  export type ThreadMessageWriter = (threadId: string, messages: UIMessage[]) => void;
19
22
 
20
23
  /** Own the mutable per-thread session registry behind the public chat hook. */
@@ -127,7 +127,7 @@ export function useChatStream({ getSession, updateSession, writeMessages }: UseC
127
127
  if (error instanceof StreamAborted || signal.aborted) return;
128
128
  if (isStaleMastraResumeError(error)) {
129
129
  logger.warn("ignored stale mastra resume", {
130
- error: errorUtils.errorMessage(error),
130
+ error: errorUtils.toError(error),
131
131
  });
132
132
  return;
133
133
  }
@@ -113,7 +113,7 @@ export const ChatThreadLayout = ({
113
113
  const rootRef = useRef<HTMLDivElement>(null);
114
114
  const isNarrow = useIsNarrow(rootRef);
115
115
  const showThreads = Boolean(threads && onSelectThread) && threadPlacement !== "disabled";
116
- const placement = threadPlacement === "auto" ? (isNarrow ? "top" : "right") : threadPlacement;
116
+ const placement = threadPlacement === "auto" ? (isNarrow ? "top" : "left") : threadPlacement;
117
117
  const tabbedThreads = showThreads && placement === "top";
118
118
  const dockedSide = placement === "right" ? "right" : "left";
119
119
  const dockedThreads = showThreads && (placement === "left" || placement === "right");
@@ -50,6 +50,7 @@ export type DataRow = Record<string, unknown>;
50
50
  */
51
51
  const DELTA_PATTERN = /^([+\u2212-])\s*\d[\d,.\s]*(?:%|\s*pts?)?$/i;
52
52
 
53
+ /** Apply success or destructive text color to a signed numeric delta string. */
53
54
  export function colorizeDelta(content: React.ReactNode): React.ReactNode {
54
55
  if (typeof content !== "string") return content;
55
56
  const text = content.trim();
@@ -23,6 +23,7 @@ import type { FeedbackSubmission, FeedbackValue } from "./types.ts";
23
23
  // wires feedback (which only happens when MLflow logging is enabled and
24
24
  // the turn has a captured trace id).
25
25
 
26
+ /** Render per-message rating and comment controls for an MLflow-backed trace. */
26
27
  export const FeedbackControls = ({
27
28
  value,
28
29
  onSubmit,
@@ -27,6 +27,7 @@ import {
27
27
  useMastraModels,
28
28
  useMastraSuggestions,
29
29
  useMastraThreads,
30
+ MastraChatRequestError,
30
31
  type MastraMemoryThread,
31
32
  type MastraStreamResponse,
32
33
  } from "../support/mastra-client.ts";
@@ -479,6 +480,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
479
480
  if (
480
481
  controller.signal.aborted ||
481
482
  getSession(threadId).runToken !== token ||
483
+ initialError instanceof MastraChatRequestError ||
482
484
  !mastraClient.backgroundTurns ||
483
485
  !runId
484
486
  ) {
@@ -486,7 +488,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
486
488
  }
487
489
  logger.warn("chat stream disconnected; reconnecting to background run", {
488
490
  runId,
489
- error: errorUtils.errorMessage(initialError),
491
+ error: errorUtils.toError(initialError),
490
492
  });
491
493
  const messagesBeforeReplay = getSession(threadId).messages;
492
494
  writeMessages(
@@ -528,7 +530,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
528
530
  if (getSession(threadId).runToken !== token) return;
529
531
  if (isStaleMastraResumeError(caught)) {
530
532
  logger.warn("ignored stale mastra resume", {
531
- error: errorUtils.errorMessage(caught),
533
+ error: errorUtils.toError(caught),
532
534
  });
533
535
  updateSession(threadId, (session) => {
534
536
  if (session.runToken !== token) return session;
@@ -548,7 +550,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
548
550
  return;
549
551
  }
550
552
  logger.error("stream error", {
551
- error: errorUtils.errorMessage(caught),
553
+ error: errorUtils.toError(caught),
552
554
  });
553
555
  updateSession(threadId, (session) => ({
554
556
  ...session,
@@ -557,6 +559,8 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
557
559
  abortController: session.abortController === controller ? null : session.abortController,
558
560
  runId: runIdRef.current,
559
561
  }));
562
+ const failedRunId = runIdRef.current;
563
+ if (failedRunId) removeStoredActiveRun(activeRunsKey, failedRunId);
560
564
  }
561
565
  },
562
566
  [
@@ -699,7 +703,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
699
703
  .catch((error: unknown) => {
700
704
  logger.warn("failed to abort background run", {
701
705
  runId: current.runId,
702
- error: errorUtils.errorMessage(error),
706
+ error: errorUtils.toError(error),
703
707
  });
704
708
  });
705
709
  }
@@ -841,7 +845,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
841
845
  logger.info("history cleared", { threadId });
842
846
  } catch (error) {
843
847
  logger.error("history clear error", {
844
- error: errorUtils.errorMessage(error),
848
+ error: errorUtils.toError(error),
845
849
  });
846
850
  }
847
851
  resetSession(threadId, true);
@@ -882,7 +886,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
882
886
  } catch (error) {
883
887
  logger.error("thread delete error", {
884
888
  threadId,
885
- error: errorUtils.errorMessage(error),
889
+ error: errorUtils.toError(error),
886
890
  });
887
891
  }
888
892
  removeSession(threadId);
@@ -927,7 +931,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
927
931
  } catch (error) {
928
932
  logger.error("thread rename error", {
929
933
  threadId,
930
- error: errorUtils.errorMessage(error),
934
+ error: errorUtils.toError(error),
931
935
  });
932
936
  setRenamedThreads((prev) => {
933
937
  if (!(threadId in prev)) return prev;
@@ -970,7 +974,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
970
974
  .catch((error: unknown) => {
971
975
  logger.error("regenerate cleanup error", {
972
976
  threadId,
973
- error: errorUtils.errorMessage(error),
977
+ error: errorUtils.toError(error),
974
978
  });
975
979
  updateSession(threadId, (session) => ({
976
980
  ...session,
@@ -1040,7 +1044,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
1040
1044
  } catch (error) {
1041
1045
  logger.error("conversation export error", {
1042
1046
  format,
1043
- error: errorUtils.errorMessage(error),
1047
+ error: errorUtils.toError(error),
1044
1048
  });
1045
1049
  }
1046
1050
  },
@@ -1062,7 +1066,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
1062
1066
  } catch (error) {
1063
1067
  logger.error("message export error", {
1064
1068
  format,
1065
- error: errorUtils.errorMessage(error),
1069
+ error: errorUtils.toError(error),
1066
1070
  });
1067
1071
  }
1068
1072
  },
@@ -5,6 +5,7 @@ import { Button, cn } from "@dbx-tools/ui/react";
5
5
  // the per-message follow-up suggestions use this so the two look and
6
6
  // behave identically.
7
7
 
8
+ /** Props for the shared starter and follow-up question pill row. */
8
9
  export interface SuggestionPillsProps {
9
10
  /** Questions to render as clickable pills. Empty renders nothing. */
10
11
  questions: string[];
@@ -424,6 +424,7 @@ const RawToolPayload = ({
424
424
  );
425
425
  };
426
426
 
427
+ /** Compact source-code preview extracted from a tool request payload. */
427
428
  export type ToolInputPresentation = {
428
429
  label: "Code" | "Command" | "Output";
429
430
  language: "typescript" | "javascript" | "python" | "sql" | "json" | "bash" | "text";
@@ -511,6 +512,7 @@ const ToolInputSource = ({ presentation }: { presentation: ToolInputPresentation
511
512
 
512
513
  type ToolStatusProgress = Extract<ToolProgress, { type: "tool_status" }>;
513
514
 
515
+ /** One native web-search request and the result progress events associated with it. */
514
516
  export type WebSearchProgressGroup = {
515
517
  key: string;
516
518
  search?: ToolStatusProgress;
@@ -20,7 +20,7 @@ export type { StoredActiveRun } from "./active-runs.ts";
20
20
  export { LIGHT_CHART_CHROME } from "./chart-theme.ts";
21
21
  export type { ChartChrome } from "./chart-theme.ts";
22
22
  export type { ExportFormat, ExportBrand, EmbedResolver, ExportChatOptions } from "./export.ts";
23
- export { MastraPluginClient, useMastraConfig, useMastraClient, useMastraMlflowExperiment, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch } from "./mastra-client.ts";
23
+ export { MastraChatRequestError, MastraPluginClient, useMastraConfig, useMastraClient, useMastraMlflowExperiment, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch } from "./mastra-client.ts";
24
24
  export type { MastraStreamResponse, MastraMemoryThread, ByIdFetchState } from "./mastra-client.ts";
25
25
  export { defaultReasoningEffort, modelStorageKey, readStoredModel, storeSelectedModel } from "./model-selection.ts";
26
26
  export type { MastraRequestContextInput, MastraRequestContextSource, MastraRequestContextSnapshot } from "./request-context.ts";
@@ -33,6 +33,17 @@ export interface MastraStreamResponse {
33
33
  stream: ReadableStream<UIMessageChunk>;
34
34
  }
35
35
 
36
+ /** Terminal HTTP failure returned before a chat stream was established. */
37
+ export class MastraChatRequestError extends Error {
38
+ constructor(
39
+ message: string,
40
+ readonly status: number,
41
+ ) {
42
+ super(message);
43
+ this.name = "MastraChatRequestError";
44
+ }
45
+ }
46
+
36
47
  /** One memory thread returned by the native Mastra client. */
37
48
  export type MastraMemoryThread = ListMemoryThreadsResponse["threads"][number];
38
49
 
@@ -634,7 +645,10 @@ async function assertChatResponse(response: Response): Promise<void> {
634
645
  .clone()
635
646
  .text()
636
647
  .catch(() => ""));
637
- throw new Error(message.trim() || `Chat request failed (${response.status})`);
648
+ throw new MastraChatRequestError(
649
+ message.trim() || `Chat request failed (${response.status})`,
650
+ response.status,
651
+ );
638
652
  }
639
653
 
640
654
  function responseErrorMessage(body: unknown): string | undefined {
@@ -42,6 +42,7 @@ export type ThreadSession = {
42
42
  /** Map key for the classic single-thread chat (no explicit thread id). */
43
43
  export const DEFAULT_THREAD_SESSION_KEY = "__session__";
44
44
 
45
+ /** Create the empty transcript and run state used for a new conversation thread. */
45
46
  export function createThreadSession(): ThreadSession {
46
47
  return {
47
48
  messages: [],
@@ -61,6 +62,7 @@ export function createThreadSession(): ThreadSession {
61
62
  };
62
63
  }
63
64
 
65
+ /** Return whether a thread has a submitted or actively streaming run. */
64
66
  export function isSessionRunning(session: ThreadSession): boolean {
65
67
  return session.status === "submitted" || session.status === "streaming";
66
68
  }
@@ -98,6 +100,7 @@ export function reorderSteers<T extends QueuedSteer>(queue: T[], orderedIds: str
98
100
  return next;
99
101
  }
100
102
 
103
+ /** Resolve an explicit thread id or the shared key used by single-thread chat. */
101
104
  export function sessionKey(activeThreadId: string | undefined): string {
102
105
  return activeThreadId ?? DEFAULT_THREAD_SESSION_KEY;
103
106
  }