@dbx-tools/ui-mastra 0.3.21 → 0.3.23

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.
@@ -1,4 +1,4 @@
1
- import { usePluginClientConfig } from "@dbx-tools/ui-appkit/react";
1
+ import { error as errorUtil } from "@dbx-tools/shared-core";
2
2
  import {
3
3
  feedback,
4
4
  override,
@@ -17,8 +17,8 @@ import {
17
17
  type MastraUpdateThreadResponse,
18
18
  type StatementData,
19
19
  } from "@dbx-tools/shared-mastra";
20
- import { error as errorUtil } from "@dbx-tools/shared-core";
21
20
  import type { ServingEndpointSummary } from "@dbx-tools/shared-model";
21
+ import { usePluginClientConfig } from "@dbx-tools/ui-appkit/react";
22
22
  import { MastraClient } from "@mastra/client-js";
23
23
  import { useCallback, useEffect, useMemo, useState } from "react";
24
24
  import { asMastraStreamResponse, type MastraStreamResponse } from "./mastra-stream";
@@ -59,8 +59,7 @@ export class MastraPluginClient extends MastraClient {
59
59
 
60
60
  constructor(config: MastraClientConfig) {
61
61
  super({
62
- baseUrl:
63
- typeof window !== "undefined" ? window.location.origin : "http://localhost",
62
+ baseUrl: typeof window !== "undefined" ? window.location.origin : "http://localhost",
64
63
  apiPrefix: config.basePath,
65
64
  credentials: "include",
66
65
  headers: {},
@@ -261,9 +260,7 @@ export class MastraPluginClient extends MastraClient {
261
260
  "DELETE",
262
261
  wire.MastraClearHistoryResponseSchema,
263
262
  {
264
- ...(options.threadId
265
- ? { headers: { [thread.THREAD_ID_HEADER]: options.threadId } }
266
- : {}),
263
+ ...(options.threadId ? { headers: { [thread.THREAD_ID_HEADER]: options.threadId } } : {}),
267
264
  ...(options.signal ? { signal: options.signal } : {}),
268
265
  },
269
266
  );
@@ -551,8 +548,7 @@ export const useMastraModels = (
551
548
  // lists a vectoriser. If the server didn't tag tasks at all,
552
549
  // pass everything through so we don't show an empty list.
553
550
  const llms = endpoints.filter(
554
- (e) =>
555
- e.task !== "llm/v1/embeddings" && (!e.task || e.task.startsWith("llm/v1/")),
551
+ (e) => e.task !== "llm/v1/embeddings" && (!e.task || e.task.startsWith("llm/v1/")),
556
552
  );
557
553
  setModels(llms.length > 0 ? llms : endpoints);
558
554
  })
@@ -709,8 +705,7 @@ export const useMastraThreads = (
709
705
  setError(null);
710
706
  })
711
707
  .catch((e: unknown) => {
712
- if (controller.signal.aborted || (e as { name?: string }).name === "AbortError")
713
- return;
708
+ if (controller.signal.aborted || (e as { name?: string }).name === "AbortError") return;
714
709
  setError(errorUtil.toError(e));
715
710
  setThreads([]);
716
711
  })
@@ -766,8 +761,7 @@ export interface ByIdFetchState<T> {
766
761
  * everything. Keyed by `<type>:<id>` (e.g. `chart:abc123`).
767
762
  */
768
763
  type FetchCacheEntry<T> =
769
- | { kind: "pending"; promise: Promise<T | undefined> }
770
- | { kind: "ready"; data: T | undefined };
764
+ { kind: "pending"; promise: Promise<T | undefined> } | { kind: "ready"; data: T | undefined };
771
765
 
772
766
  const fetchCache = new Map<string, FetchCacheEntry<unknown>>();
773
767
 
@@ -902,8 +896,7 @@ function useByIdFetch<T>(
902
896
  * stays stable - inlining a fresh closure would refire the
903
897
  * effect on every render.
904
898
  */
905
- const chartIsTerminal = (c: Chart): boolean =>
906
- c.result !== undefined || c.error !== undefined;
899
+ const chartIsTerminal = (c: Chart): boolean => c.result !== undefined || c.error !== undefined;
907
900
 
908
901
  /**
909
902
  * `isTerminal` for {@link useStatementFetch}. A statement
@@ -955,9 +948,6 @@ export const useStatementFetch = (
955
948
  ): ByIdFetchState<StatementData> => {
956
949
  const client = useMastraClient();
957
950
  const key = statementId ? `data:${statementId}` : undefined;
958
- const fetcher = useCallback(
959
- () => client.statement(statementId as string),
960
- [client, statementId],
961
- );
951
+ const fetcher = useCallback(() => client.statement(statementId as string), [client, statementId]);
962
952
  return useByIdFetch<StatementData>(key, fetcher, statementIsTerminal);
963
953
  };
@@ -57,10 +57,7 @@ export function isSessionRunning(session: ThreadSession): boolean {
57
57
  }
58
58
 
59
59
  /** Append a steer to the queue (oldest first). Returns a new array. */
60
- export function enqueueSteer(
61
- queue: QueuedSteer[],
62
- steer: QueuedSteer,
63
- ): QueuedSteer[] {
60
+ export function enqueueSteer(queue: QueuedSteer[], steer: QueuedSteer): QueuedSteer[] {
64
61
  return [...queue, steer];
65
62
  }
66
63
 
@@ -0,0 +1,101 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import type { QueuedSteer, ToolEvent } from "../src/react/types";
4
+ import {
5
+ enqueueSteer,
6
+ removeSteer,
7
+ reorderSteers,
8
+ terminateRunningToolEvents,
9
+ } from "../src/support/thread-sessions";
10
+
11
+ const event = (id: string, status: ToolEvent["status"]): ToolEvent => ({
12
+ id,
13
+ toolName: "ask_genie",
14
+ status,
15
+ });
16
+
17
+ describe("terminateRunningToolEvents", () => {
18
+ it("settles running pills to done", () => {
19
+ const next = terminateRunningToolEvents({
20
+ msg1: [event("a", "running"), event("b", "done")],
21
+ msg2: [event("c", "running")],
22
+ });
23
+ assert.deepEqual(
24
+ next.msg1!.map((e) => e.status),
25
+ ["done", "done"],
26
+ );
27
+ assert.deepEqual(
28
+ next.msg2!.map((e) => e.status),
29
+ ["done"],
30
+ );
31
+ });
32
+
33
+ it("leaves already-terminal pills untouched and returns the same ref when nothing ran", () => {
34
+ const input = {
35
+ msg1: [event("a", "done"), event("b", "error")],
36
+ };
37
+ const next = terminateRunningToolEvents(input);
38
+ // No running pills, so the map is returned unchanged (identity) to let
39
+ // callers skip a needless state update.
40
+ assert.equal(next, input);
41
+ });
42
+
43
+ it("handles an empty map", () => {
44
+ const input = {};
45
+ assert.equal(terminateRunningToolEvents(input), input);
46
+ });
47
+ });
48
+
49
+ describe("steer queue", () => {
50
+ const steer = (id: string, text: string): QueuedSteer => ({ id, text });
51
+
52
+ it("enqueues oldest-first without mutating the input", () => {
53
+ const q0: QueuedSteer[] = [];
54
+ const q1 = enqueueSteer(q0, steer("a", "first"));
55
+ const q2 = enqueueSteer(q1, steer("b", "second"));
56
+ assert.deepEqual(
57
+ q2.map((s) => s.id),
58
+ ["a", "b"],
59
+ );
60
+ assert.equal(q0.length, 0);
61
+ assert.equal(q1.length, 1);
62
+ });
63
+
64
+ it("removes by id and leaves the rest in order", () => {
65
+ const q = [steer("a", "1"), steer("b", "2"), steer("c", "3")];
66
+ assert.deepEqual(
67
+ removeSteer(q, "b").map((s) => s.id),
68
+ ["a", "c"],
69
+ );
70
+ });
71
+
72
+ it("removing an unknown id is a no-op copy", () => {
73
+ const q = [steer("a", "1")];
74
+ assert.deepEqual(removeSteer(q, "zzz"), q);
75
+ });
76
+
77
+ it("reorders to match the given id order", () => {
78
+ const q = [steer("a", "1"), steer("b", "2"), steer("c", "3")];
79
+ assert.deepEqual(
80
+ reorderSteers(q, ["c", "a", "b"]).map((s) => s.id),
81
+ ["c", "a", "b"],
82
+ );
83
+ });
84
+
85
+ it("appends any current steer missing from the order, and ignores unknown ids", () => {
86
+ const q = [steer("a", "1"), steer("b", "2"), steer("c", "3")];
87
+ // "b" omitted + a stale "zzz" present: zzz ignored, b appended after the rest.
88
+ assert.deepEqual(
89
+ reorderSteers(q, ["c", "zzz", "a"]).map((s) => s.id),
90
+ ["c", "a", "b"],
91
+ );
92
+ });
93
+
94
+ it("never duplicates when the order repeats an id", () => {
95
+ const q = [steer("a", "1"), steer("b", "2")];
96
+ assert.deepEqual(
97
+ reorderSteers(q, ["a", "a", "b"]).map((s) => s.id),
98
+ ["a", "b"],
99
+ );
100
+ });
101
+ });
@@ -0,0 +1,14 @@
1
+ // ~~ Generated by projen. To modify, edit .projenrc.js and run "pnpm exec projen".
2
+ {
3
+ "extends": "../tsconfig.json",
4
+ "compilerOptions": {
5
+ "noEmit": true,
6
+ "rootDir": ".."
7
+ },
8
+ "include": [
9
+ "**/*.ts"
10
+ ],
11
+ "exclude": [
12
+ "node_modules"
13
+ ]
14
+ }