@dbx-tools/appkit-mastra 0.1.58 → 0.1.68

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.
Files changed (51) hide show
  1. package/README.md +41 -1
  2. package/dist/index.d.ts +1229 -17
  3. package/dist/index.js +3348 -19
  4. package/package.json +17 -30
  5. package/dist/src/agents.d.ts +0 -316
  6. package/dist/src/agents.js +0 -470
  7. package/dist/src/chart.d.ts +0 -153
  8. package/dist/src/chart.js +0 -570
  9. package/dist/src/config.d.ts +0 -295
  10. package/dist/src/config.js +0 -55
  11. package/dist/src/genie.d.ts +0 -161
  12. package/dist/src/genie.js +0 -973
  13. package/dist/src/history.d.ts +0 -95
  14. package/dist/src/history.js +0 -278
  15. package/dist/src/memory.d.ts +0 -109
  16. package/dist/src/memory.js +0 -253
  17. package/dist/src/model.d.ts +0 -52
  18. package/dist/src/model.js +0 -198
  19. package/dist/src/observability.d.ts +0 -64
  20. package/dist/src/observability.js +0 -83
  21. package/dist/src/plugin.d.ts +0 -177
  22. package/dist/src/plugin.js +0 -554
  23. package/dist/src/processor.d.ts +0 -8
  24. package/dist/src/processor.js +0 -40
  25. package/dist/src/processors/strip-stale-charts.d.ts +0 -32
  26. package/dist/src/processors/strip-stale-charts.js +0 -98
  27. package/dist/src/server.d.ts +0 -51
  28. package/dist/src/server.js +0 -152
  29. package/dist/src/serving.d.ts +0 -65
  30. package/dist/src/serving.js +0 -79
  31. package/dist/src/statement.d.ts +0 -66
  32. package/dist/src/statement.js +0 -111
  33. package/dist/src/writer.d.ts +0 -23
  34. package/dist/src/writer.js +0 -37
  35. package/dist/tsconfig.build.tsbuildinfo +0 -1
  36. package/index.ts +0 -27
  37. package/src/agents.ts +0 -772
  38. package/src/chart.ts +0 -716
  39. package/src/config.ts +0 -320
  40. package/src/genie.ts +0 -1123
  41. package/src/history.ts +0 -322
  42. package/src/memory.ts +0 -293
  43. package/src/model.ts +0 -257
  44. package/src/observability.ts +0 -114
  45. package/src/plugin.ts +0 -623
  46. package/src/processor.ts +0 -46
  47. package/src/processors/strip-stale-charts.ts +0 -102
  48. package/src/server.ts +0 -195
  49. package/src/serving.ts +0 -104
  50. package/src/statement.ts +0 -120
  51. package/src/writer.ts +0 -44
@@ -1,95 +0,0 @@
1
- /**
2
- * Thread history loader exposed as a Mastra custom API route.
3
- *
4
- * Backed entirely by native Mastra: looks up the active agent by id,
5
- * asks its `Memory` instance to `recall` a page of `MastraDBMessage`s,
6
- * and converts the result to AI SDK V5 `UIMessage`s with the official
7
- * {@link toAISdkV5Messages} helper from `@mastra/ai-sdk/ui`. No direct
8
- * database reads.
9
- *
10
- * The route is registered through {@link historyRoute} as a Mastra
11
- * `registerApiRoute` so it sits in the same dispatcher pipeline as
12
- * the standard agent routes. That means the `MastraServer` auth
13
- * middleware (in `./server.ts`) has already populated `RequestContext` with
14
- * `MASTRA_THREAD_ID_KEY` and `MASTRA_RESOURCE_ID_KEY` by the time
15
- * the handler runs - no cookie or user lookups happen here, and the
16
- * session-cookie logic stays the single source of truth in `server.ts`.
17
- */
18
- import type { MastraHistoryResponse } from "@dbx-tools/appkit-mastra-shared";
19
- import type { Agent } from "@mastra/core/agent";
20
- /** Inputs accepted by {@link loadHistory}. */
21
- export interface LoadHistoryOptions {
22
- agent: Agent;
23
- threadId: string;
24
- resourceId?: string;
25
- page?: number;
26
- perPage?: number;
27
- /** When true, returns the *oldest* page first (chronological). */
28
- ascending?: boolean;
29
- }
30
- /**
31
- * Fetch a page of UI-formatted messages for a thread.
32
- *
33
- * Uses the agent's resolved `Memory` (`getMemory()`) so per-agent
34
- * storage namespaces (`mastra_<agentId>` schemas) and any future
35
- * memory-side filters apply automatically. When the agent has no
36
- * memory configured the response is a successful empty page so
37
- * callers don't have to special-case stateless agents.
38
- *
39
- * Pagination is descending-by-default: page 0 is the most recent
40
- * page, page 1 the page before that, etc. The returned `uiMessages`
41
- * are always re-sorted into chronological order (oldest -> newest)
42
- * so the client can prepend them above the existing transcript
43
- * without sorting locally.
44
- */
45
- export declare function loadHistory(opts: LoadHistoryOptions): Promise<MastraHistoryResponse>;
46
- /** Inputs accepted by {@link clearHistory}. */
47
- export interface ClearHistoryOptions {
48
- agent: Agent;
49
- threadId: string;
50
- }
51
- /**
52
- * Wipe every persisted message tied to a thread. Returns the count
53
- * of messages that were on the thread at delete time so the caller
54
- * can render a "cleared N messages" affordance without an
55
- * additional round-trip.
56
- *
57
- * Agents without a configured `Memory` resolve to a no-op (count
58
- * 0), matching {@link loadHistory}'s "stateless agents return an
59
- * empty page" stance so callers don't have to special-case them.
60
- * Threads that don't exist yet are also a successful no-op - the
61
- * operation is idempotent so the UI can fire-and-forget without
62
- * tracking thread existence.
63
- */
64
- export declare function clearHistory(opts: ClearHistoryOptions): Promise<{
65
- cleared: number;
66
- }>;
67
- /** Options accepted by {@link historyRoute}. */
68
- export type HistoryRouteOptions = {
69
- path: `${string}:agentId${string}`;
70
- agent?: never;
71
- } | {
72
- path: string;
73
- agent: string;
74
- };
75
- /**
76
- * Register the `<path>` Mastra custom API route. Handles two
77
- * methods on the same mount:
78
- *
79
- * - `GET`: return a page of AI SDK V5 `UIMessage`s for the
80
- * caller's current thread ({@link loadHistory}).
81
- * - `DELETE`: wipe every persisted message on the caller's
82
- * thread ({@link clearHistory}). The session cookie that
83
- * anchors the thread id is left alone so the user keeps the
84
- * same thread - only the contents go away.
85
- *
86
- * Follows the `@mastra/ai-sdk` `chatRoute` convention for agent
87
- * binding: pass `agent` for a fixed-agent mount, or include
88
- * `:agentId` in the path for dynamic routing. The plugin registers
89
- * both `/route/history` (default agent) and `/route/history/:agentId`.
90
- *
91
- * The handler reads `threadId` and `resourceId` from `RequestContext`
92
- * (populated upstream by `MastraServer.registerAuthMiddleware`), so
93
- * no cookie or user lookups happen here.
94
- */
95
- export declare function historyRoute(options: HistoryRouteOptions): import("@mastra/core/server").ApiRoute[];
@@ -1,278 +0,0 @@
1
- /**
2
- * Thread history loader exposed as a Mastra custom API route.
3
- *
4
- * Backed entirely by native Mastra: looks up the active agent by id,
5
- * asks its `Memory` instance to `recall` a page of `MastraDBMessage`s,
6
- * and converts the result to AI SDK V5 `UIMessage`s with the official
7
- * {@link toAISdkV5Messages} helper from `@mastra/ai-sdk/ui`. No direct
8
- * database reads.
9
- *
10
- * The route is registered through {@link historyRoute} as a Mastra
11
- * `registerApiRoute` so it sits in the same dispatcher pipeline as
12
- * the standard agent routes. That means the `MastraServer` auth
13
- * middleware (in `./server.ts`) has already populated `RequestContext` with
14
- * `MASTRA_THREAD_ID_KEY` and `MASTRA_RESOURCE_ID_KEY` by the time
15
- * the handler runs - no cookie or user lookups happen here, and the
16
- * session-cookie logic stays the single source of truth in `server.ts`.
17
- */
18
- import { commonUtils, logUtils } from "@dbx-tools/shared";
19
- import { toAISdkV5Messages } from "@mastra/ai-sdk/ui";
20
- import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, } from "@mastra/core/request-context";
21
- import { registerApiRoute } from "@mastra/core/server";
22
- const log = logUtils.logger("mastra/history");
23
- /** Default history page size; matches the Mastra storage default. */
24
- const DEFAULT_PER_PAGE = 20;
25
- /** Hard cap so a misbehaving client can't fetch the whole thread at once. */
26
- const MAX_PER_PAGE = 200;
27
- /**
28
- * Fetch a page of UI-formatted messages for a thread.
29
- *
30
- * Uses the agent's resolved `Memory` (`getMemory()`) so per-agent
31
- * storage namespaces (`mastra_<agentId>` schemas) and any future
32
- * memory-side filters apply automatically. When the agent has no
33
- * memory configured the response is a successful empty page so
34
- * callers don't have to special-case stateless agents.
35
- *
36
- * Pagination is descending-by-default: page 0 is the most recent
37
- * page, page 1 the page before that, etc. The returned `uiMessages`
38
- * are always re-sorted into chronological order (oldest -> newest)
39
- * so the client can prepend them above the existing transcript
40
- * without sorting locally.
41
- */
42
- export async function loadHistory(opts) {
43
- const perPage = clampPerPage(opts.perPage);
44
- const page = Math.max(0, Math.trunc(opts.page ?? 0));
45
- const memory = await opts.agent.getMemory();
46
- if (!memory) {
47
- log.debug("recall:no-memory", { agentId: opts.agent.id, threadId: opts.threadId });
48
- return { uiMessages: [], page, perPage, total: 0, hasMore: false };
49
- }
50
- const startedAt = Date.now();
51
- const result = await memory.recall({
52
- threadId: opts.threadId,
53
- ...(opts.resourceId ? { resourceId: opts.resourceId } : {}),
54
- page,
55
- perPage,
56
- orderBy: {
57
- field: "createdAt",
58
- direction: opts.ascending ? "ASC" : "DESC",
59
- },
60
- });
61
- const chronological = sortChronological(result.messages);
62
- const uiMessages = toAISdkV5Messages(chronological);
63
- log.debug("recall:done", {
64
- agentId: opts.agent.id,
65
- threadId: opts.threadId,
66
- page,
67
- perPage,
68
- returned: uiMessages.length,
69
- total: result.total,
70
- hasMore: result.hasMore,
71
- elapsedMs: Date.now() - startedAt,
72
- });
73
- return {
74
- uiMessages,
75
- page,
76
- perPage,
77
- total: result.total,
78
- hasMore: result.hasMore,
79
- };
80
- }
81
- /**
82
- * Wipe every persisted message tied to a thread. Returns the count
83
- * of messages that were on the thread at delete time so the caller
84
- * can render a "cleared N messages" affordance without an
85
- * additional round-trip.
86
- *
87
- * Agents without a configured `Memory` resolve to a no-op (count
88
- * 0), matching {@link loadHistory}'s "stateless agents return an
89
- * empty page" stance so callers don't have to special-case them.
90
- * Threads that don't exist yet are also a successful no-op - the
91
- * operation is idempotent so the UI can fire-and-forget without
92
- * tracking thread existence.
93
- */
94
- export async function clearHistory(opts) {
95
- const memory = await opts.agent.getMemory();
96
- if (!memory) {
97
- log.debug("clear:no-memory", { agentId: opts.agent.id, threadId: opts.threadId });
98
- return { cleared: 0 };
99
- }
100
- // Mastra's `deleteThread` cascades to the message table, so we
101
- // can't ask for a count after the fact. Read it pre-delete with a
102
- // one-page recall sized to fit common threads in a single round
103
- // trip; the value is for telemetry / UI, not correctness.
104
- let cleared = 0;
105
- try {
106
- const probe = await memory.recall({
107
- threadId: opts.threadId,
108
- page: 0,
109
- perPage: 1,
110
- });
111
- cleared = probe.total;
112
- }
113
- catch (err) {
114
- // A missing-thread error is the happy-path "nothing to count";
115
- // every other error is logged but doesn't block the delete.
116
- log.debug("clear:probe-failed", {
117
- agentId: opts.agent.id,
118
- threadId: opts.threadId,
119
- error: commonUtils.errorMessage(err),
120
- });
121
- }
122
- const startedAt = Date.now();
123
- try {
124
- await memory.deleteThread(opts.threadId);
125
- }
126
- catch (err) {
127
- // Mastra's `deleteThread` raises when the thread row was never
128
- // created (e.g. clearing an empty session). Surface as a soft
129
- // warn and treat as success - the user-facing semantic is
130
- // "history is now empty" which is already true.
131
- log.warn("clear:delete-soft-failed", {
132
- agentId: opts.agent.id,
133
- threadId: opts.threadId,
134
- error: commonUtils.errorMessage(err),
135
- });
136
- }
137
- log.info("clear:done", {
138
- agentId: opts.agent.id,
139
- threadId: opts.threadId,
140
- cleared,
141
- elapsedMs: Date.now() - startedAt,
142
- });
143
- return { cleared };
144
- }
145
- /**
146
- * Register the `<path>` Mastra custom API route. Handles two
147
- * methods on the same mount:
148
- *
149
- * - `GET`: return a page of AI SDK V5 `UIMessage`s for the
150
- * caller's current thread ({@link loadHistory}).
151
- * - `DELETE`: wipe every persisted message on the caller's
152
- * thread ({@link clearHistory}). The session cookie that
153
- * anchors the thread id is left alone so the user keeps the
154
- * same thread - only the contents go away.
155
- *
156
- * Follows the `@mastra/ai-sdk` `chatRoute` convention for agent
157
- * binding: pass `agent` for a fixed-agent mount, or include
158
- * `:agentId` in the path for dynamic routing. The plugin registers
159
- * both `/route/history` (default agent) and `/route/history/:agentId`.
160
- *
161
- * The handler reads `threadId` and `resourceId` from `RequestContext`
162
- * (populated upstream by `MastraServer.registerAuthMiddleware`), so
163
- * no cookie or user lookups happen here.
164
- */
165
- export function historyRoute(options) {
166
- const { path } = options;
167
- const fixedAgent = "agent" in options ? options.agent : undefined;
168
- if (!fixedAgent && !path.includes(":agentId")) {
169
- throw new Error("historyRoute path must include `:agentId` or `agent` must be passed explicitly");
170
- }
171
- // Tiny resolver shared by GET / DELETE: derive the active agent
172
- // and thread id, returning a JSON error response when either is
173
- // missing. Keeps both handlers thin and gives them identical
174
- // validation behaviour.
175
- const resolveContext = (c) => {
176
- const mastra = c.get("mastra");
177
- const requestContext = c.get("requestContext");
178
- const agentId = fixedAgent ?? c.req.param("agentId");
179
- if (!agentId) {
180
- return { error: c.json({ error: "agentId is required" }, 400) };
181
- }
182
- const agent = mastra.getAgentById(agentId);
183
- if (!agent) {
184
- return {
185
- error: c.json({ error: `Unknown agent "${agentId}"` }, 404),
186
- };
187
- }
188
- const threadId = requestContext.get(MASTRA_THREAD_ID_KEY);
189
- if (!threadId) {
190
- return {
191
- error: c.json({ error: "thread id missing from request context" }, 400),
192
- };
193
- }
194
- const resourceId = requestContext.get(MASTRA_RESOURCE_ID_KEY);
195
- return { agentId, agent, threadId, resourceId };
196
- };
197
- return [
198
- registerApiRoute(path, {
199
- method: "GET",
200
- handler: async (c) => {
201
- const ctx = resolveContext(c);
202
- if ("error" in ctx)
203
- return ctx.error;
204
- const payload = await loadHistory({
205
- agent: ctx.agent,
206
- threadId: ctx.threadId,
207
- ...(ctx.resourceId ? { resourceId: ctx.resourceId } : {}),
208
- page: parseIntParam(c.req.query("page")),
209
- perPage: parseIntParam(c.req.query("perPage")),
210
- });
211
- return c.json(payload);
212
- },
213
- }),
214
- registerApiRoute(path, {
215
- method: "DELETE",
216
- handler: async (c) => {
217
- const ctx = resolveContext(c);
218
- if ("error" in ctx)
219
- return ctx.error;
220
- const { cleared } = await clearHistory({
221
- agent: ctx.agent,
222
- threadId: ctx.threadId,
223
- });
224
- const payload = {
225
- ok: true,
226
- agentId: ctx.agentId,
227
- threadId: ctx.threadId,
228
- cleared,
229
- };
230
- return c.json(payload);
231
- },
232
- }),
233
- ];
234
- }
235
- /** Coerce / clamp `perPage`; falls back to the page-size default. */
236
- function clampPerPage(value) {
237
- if (value === undefined || Number.isNaN(value))
238
- return DEFAULT_PER_PAGE;
239
- const n = Math.trunc(value);
240
- if (n <= 0)
241
- return DEFAULT_PER_PAGE;
242
- return Math.min(n, MAX_PER_PAGE);
243
- }
244
- /**
245
- * Sort messages oldest-first by `createdAt`, falling back to whatever
246
- * order the storage returned them in. The native `recall` call honors
247
- * `orderBy` but doesn't guarantee a stable secondary sort, so we
248
- * normalize here before handing the page to the AI SDK converter.
249
- */
250
- function sortChronological(messages) {
251
- return [...messages].sort((a, b) => {
252
- const ta = toEpoch(a.createdAt);
253
- const tb = toEpoch(b.createdAt);
254
- return ta - tb;
255
- });
256
- }
257
- function toEpoch(value) {
258
- if (value instanceof Date)
259
- return value.getTime();
260
- if (typeof value === "string" || typeof value === "number") {
261
- const parsed = new Date(value).getTime();
262
- return Number.isNaN(parsed) ? 0 : parsed;
263
- }
264
- return 0;
265
- }
266
- /**
267
- * Coerce a Hono query value into a non-negative integer. Returns
268
- * `undefined` for empty / non-numeric / negative inputs so
269
- * {@link loadHistory} can apply its built-in defaults.
270
- */
271
- function parseIntParam(value) {
272
- if (!value)
273
- return undefined;
274
- const n = Number(value);
275
- if (!Number.isFinite(n) || n < 0)
276
- return undefined;
277
- return Math.trunc(n);
278
- }
@@ -1,109 +0,0 @@
1
- /**
2
- * Lakebase-backed Mastra memory wiring.
3
- *
4
- * Provides a {@link MemoryBuilder} that mints one `Memory` per agent
5
- * with two independent knobs:
6
- *
7
- * - **Storage** (threads / messages via `PostgresStore`): defaults to
8
- * **per-agent** namespacing via `schemaName: "mastra_<agentId>"` so
9
- * conversation history stays isolated between agents in the same
10
- * database. `PostgresStore` auto-creates the schema with
11
- * `CREATE SCHEMA IF NOT EXISTS` on init.
12
- * - **Memory** (semantic recall via `PgVector`): defaults to a single
13
- * **shared** instance across every agent. Cross-agent recall on one
14
- * index is almost always what users want; opt into per-agent recall
15
- * by passing a {@link MastraMemoryConfigOverride} on the agent.
16
- *
17
- * Additionally, {@link MemoryBuilder.instanceStorage} returns a
18
- * **Mastra-instance-level** `PostgresStore` (schema `mastra_instance`)
19
- * used for workflow snapshots - the persistence layer
20
- * `agent.resumeStream()` reads from when waking a suspended
21
- * `requireApproval` tool call. Per-agent stores are not enough for
22
- * this: workflow runs are scoped to the Mastra instance, not an
23
- * individual agent's `Memory`.
24
- *
25
- * Plugin-level `config.storage` / `config.memory` act as the baseline
26
- * (auto-defaulted to `true` in `plugin.ts` when the `lakebase` plugin
27
- * is registered); per-agent settings cascade on top of that.
28
- */
29
- import { Memory } from "@mastra/memory";
30
- import { PostgresStore } from "@mastra/pg";
31
- import { Pool, type PoolConfig } from "pg";
32
- import type { MastraAgentDefinition } from "./agents.js";
33
- import type { MastraPluginConfig } from "./config.js";
34
- /**
35
- * Build a dedicated **service-principal** Lakebase pool for Mastra
36
- * memory from the lakebase plugin's resolved SP pg config.
37
- *
38
- * The plugin's `exports().pool` is a `RoutingPool` that switches to
39
- * the per-user (OBO) pool whenever a query runs inside an `asUser`
40
- * scope - exactly the context the mastra plugin establishes around
41
- * every chat turn. Memory (threads / messages + semantic recall) must
42
- * instead always act as the app service principal: it owns the
43
- * auto-created `mastra_*` schemas (a per-user role usually can't
44
- * `CREATE SCHEMA`) and is shared across users, so it cannot inherit a
45
- * request's OBO identity.
46
- *
47
- * `pgConfig` must be the plugin's `exports().getPgConfig()` evaluated
48
- * **outside** any `asUser` scope (i.e. during setup), so it carries
49
- * the SP connection target, OAuth token-refresh `password` callback,
50
- * and any `lakebase({ pool })` tuning overrides - all of which this
51
- * pool inherits. See the call site in `plugin.ts`.
52
- */
53
- export declare function createServicePrincipalPool(pgConfig: PoolConfig): Promise<Pool>;
54
- /**
55
- * True when any plugin-level or per-agent setting could need the
56
- * Lakebase pool. Used by `plugin.ts` to gate creation of the
57
- * service-principal pool and the {@link MemoryBuilder} that consumes
58
- * it; when false neither is built.
59
- */
60
- export declare function needsLakebase(config: MastraPluginConfig): boolean;
61
- /**
62
- * Construct a per-agent {@link Memory} factory bound to the supplied
63
- * service-principal pool (see {@link createServicePrincipalPool}).
64
- * Caches the shared `PgVector` singleton (built on first need) so each
65
- * agent build is O(1) after the first.
66
- */
67
- export declare function createMemoryBuilder(config: MastraPluginConfig, servicePrincipalPool: Pool): MemoryBuilder;
68
- /**
69
- * Builds one `Memory` per agent against a shared service-principal
70
- * Lakebase pool. Per-instance state keeps the shared `PgVector` alive
71
- * across calls so registering N agents stays cheap.
72
- */
73
- export declare class MemoryBuilder {
74
- private readonly config;
75
- private readonly servicePrincipalPool;
76
- private sharedVector;
77
- constructor(config: MastraPluginConfig, servicePrincipalPool: Pool);
78
- /**
79
- * Build a `Memory` for `agentId` after the plugin/agent cascade.
80
- * Returns `undefined` when the agent has neither storage nor a
81
- * vector store enabled - Mastra accepts a missing `memory` field
82
- * and treats the agent as stateless.
83
- */
84
- /**
85
- * Build the Mastra-instance-level storage used for workflow
86
- * snapshots. Returns `undefined` when plugin-level `storage` is
87
- * disabled, in which case `agent.resumeStream()` (and therefore
88
- * the `requireApproval` flow) will not be available.
89
- *
90
- * The store lives in a dedicated `mastra_instance` schema so it
91
- * never collides with per-agent `mastra_<agentId>` namespaces.
92
- * Workflow snapshots are not per-agent state; they belong to the
93
- * `Mastra` instance that owns the workflow execution.
94
- */
95
- instanceStorage(): PostgresStore | undefined;
96
- forAgent(agentId: string, def: MastraAgentDefinition): Memory | undefined;
97
- private buildStorage;
98
- /**
99
- * Resolve the agent's vector store. Cascade:
100
- *
101
- * - falsy: no vector.
102
- * - `boolean` / `undefined-inheriting-true`: return the shared
103
- * singleton (built lazily on first call). All agents that
104
- * default-enable memory write into and recall from one index.
105
- * - object: build a dedicated `PgVector` for this agent.
106
- */
107
- private buildVector;
108
- private getSharedVector;
109
- }