@dbx-tools/appkit-mastra-shared 0.1.12 → 0.1.18
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 +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/src/genie.d.ts +635 -0
- package/dist/src/genie.js +349 -0
- package/dist/src/mastra.d.ts +31 -0
- package/dist/src/mastra.js +44 -0
- package/dist/src/protocol.d.ts +148 -105
- package/dist/src/protocol.js +132 -36
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/index.ts +2 -0
- package/package.json +13 -3
- package/src/genie.ts +407 -0
- package/src/mastra.ts +53 -0
- package/src/protocol.ts +137 -125
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mastra-only surface for the Genie agent that
|
|
3
|
+
* `@dbx-tools/appkit-mastra` runs server-side.
|
|
4
|
+
*
|
|
5
|
+
* The pure Genie wire vocabulary (chat events, terminal-status
|
|
6
|
+
* helpers, attachment shapes) lives in `@dbx-tools/genie-shared`
|
|
7
|
+
* so anything that doesn't speak Mastra (browser bundles,
|
|
8
|
+
* headless renderers, non-Mastra clients) can import the protocol
|
|
9
|
+
* without dragging Mastra in. We re-export that surface from this
|
|
10
|
+
* module so downstream callers keep a single
|
|
11
|
+
* `@dbx-tools/appkit-mastra-shared` import.
|
|
12
|
+
*
|
|
13
|
+
* What lives here:
|
|
14
|
+
*
|
|
15
|
+
* - {@link MinimalWriter}: structural shape of `ctx.writer`,
|
|
16
|
+
* used by every Mastra tool that publishes Genie events.
|
|
17
|
+
* - {@link GenieAgentEvent}: lifecycle and chart events the
|
|
18
|
+
* Mastra Genie agent emits that are NOT on the Genie wire
|
|
19
|
+
* (`started`, `ask_genie_done`, `error`, `chart`). Same flat
|
|
20
|
+
* `{type, ...fields}` shape as the wire's
|
|
21
|
+
* {@link GenieChatEvent} so subscribers union both with one
|
|
22
|
+
* `switch (event.type)`.
|
|
23
|
+
* - {@link GenieWriterEvent}: the unified vocabulary the Genie
|
|
24
|
+
* agent writes through `ctx.writer`. Subscribers narrow on
|
|
25
|
+
* `type` and read the event's fields directly - no
|
|
26
|
+
* translation layer.
|
|
27
|
+
* - Workflow output shapes ({@link GenieDataset},
|
|
28
|
+
* {@link GenieDatasetChart}, {@link GenieSummaryItem},
|
|
29
|
+
* {@link GenieAgentResult}): structurally Mastra-only because
|
|
30
|
+
* the agent's two-step workflow (agent step + finalize step)
|
|
31
|
+
* embeds a chart-planner output (`dataset.chart`) and a mixed
|
|
32
|
+
* `(string | visualize)[]` summary that the Genie wire knows
|
|
33
|
+
* nothing about.
|
|
34
|
+
* - {@link genieResultToWriterEvents}: helper that replays the
|
|
35
|
+
* terminal `error` event from a completed
|
|
36
|
+
* {@link GenieAgentResult} (e.g. on history reload). Chart
|
|
37
|
+
* replay is intentionally not supported - the resolved
|
|
38
|
+
* Echarts spec is held off-band on the per-request
|
|
39
|
+
* `RequestContext`, not on the persisted summary.
|
|
40
|
+
*
|
|
41
|
+
* Pure types and small helpers; no Node-only imports, safe for
|
|
42
|
+
* browser bundles.
|
|
43
|
+
*/
|
|
44
|
+
import { GenieChatEventSchema, } from "@dbx-tools/genie-shared";
|
|
45
|
+
import { z } from "zod";
|
|
46
|
+
/* ---------------- mastra-only genie-agent events ---------------- */
|
|
47
|
+
/**
|
|
48
|
+
* Mastra-only lifecycle event: the Genie tool invocation started.
|
|
49
|
+
* Emitted immediately when the calling agent invokes the Genie
|
|
50
|
+
* tool, before any inner agent / wire activity, so the UI can
|
|
51
|
+
* pop a "Thinking..." pill the instant the model decides to
|
|
52
|
+
* delegate. `conversationId` / `messageId` are absent on this
|
|
53
|
+
* first emit (no Genie round-trip yet). Field names are
|
|
54
|
+
* camelCase (vs the snake_case wire events) to mirror the
|
|
55
|
+
* Genie agent's own internal data plumbing.
|
|
56
|
+
*/
|
|
57
|
+
export const StartedEventSchema = z.object({
|
|
58
|
+
type: z.literal("started"),
|
|
59
|
+
spaceId: z.string(),
|
|
60
|
+
/**
|
|
61
|
+
* Genie conversation id, populated only when this `started`
|
|
62
|
+
* event corresponds to a follow-up turn on an existing
|
|
63
|
+
* conversation. Absent on the first turn.
|
|
64
|
+
*/
|
|
65
|
+
conversationId: z.string().optional(),
|
|
66
|
+
/**
|
|
67
|
+
* Genie message id, populated only after the first wire
|
|
68
|
+
* `message` event lands. Absent on the immediate-on-invoke
|
|
69
|
+
* emit.
|
|
70
|
+
*/
|
|
71
|
+
messageId: z.string().optional(),
|
|
72
|
+
/** Question the Genie agent sent to Genie. */
|
|
73
|
+
content: z.string(),
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Mastra-only lifecycle event: one `ask_genie` invocation
|
|
77
|
+
* finished. Carries the hydrated `statementIds` (rows are fetched
|
|
78
|
+
* via `getStatement` separately) and Genie's final prose answer
|
|
79
|
+
* so the UI can move from "thinking" to "answered" without
|
|
80
|
+
* waiting for the Genie agent's whole reasoning loop to end.
|
|
81
|
+
*/
|
|
82
|
+
export const AskGenieDoneEventSchema = z.object({
|
|
83
|
+
type: z.literal("ask_genie_done"),
|
|
84
|
+
spaceId: z.string(),
|
|
85
|
+
conversationId: z.string().optional(),
|
|
86
|
+
messageId: z.string().optional(),
|
|
87
|
+
/** Genie's natural-language answer for the turn, if any. */
|
|
88
|
+
answer: z.string().optional(),
|
|
89
|
+
/** Statement ids for any non-empty result sets this turn produced. */
|
|
90
|
+
statementIds: z.array(z.string()),
|
|
91
|
+
/**
|
|
92
|
+
* Terminal wire status (`COMPLETED` / `FAILED` / `CANCELLED`).
|
|
93
|
+
* Mirrors the source `result` event's status so subscribers
|
|
94
|
+
* can react to ask-level completion without re-walking history.
|
|
95
|
+
* Treated as `z.custom<MessageStatus>` because the SDK is the
|
|
96
|
+
* source of truth for the enum values.
|
|
97
|
+
*/
|
|
98
|
+
status: z.custom((v) => typeof v === "string"),
|
|
99
|
+
});
|
|
100
|
+
/**
|
|
101
|
+
* Mastra-only error event: terminal Genie agent / transport
|
|
102
|
+
* error. Genie's own `FAILED` / `CANCELLED` come through the
|
|
103
|
+
* wire's `result` event - this variant is for failures the wire
|
|
104
|
+
* can't represent (network, Genie agent crash, planner error,
|
|
105
|
+
* etc.) plus a UI-friendly mirror of `result` when the status is
|
|
106
|
+
* non-`COMPLETED`.
|
|
107
|
+
*/
|
|
108
|
+
export const MastraGenieErrorEventSchema = z.object({
|
|
109
|
+
type: z.literal("error"),
|
|
110
|
+
spaceId: z.string().optional(),
|
|
111
|
+
conversationId: z.string().optional(),
|
|
112
|
+
messageId: z.string().optional(),
|
|
113
|
+
error: z.string(),
|
|
114
|
+
});
|
|
115
|
+
/**
|
|
116
|
+
* Mastra-only lifecycle event: the inner Genie agent's
|
|
117
|
+
* structured-output coercion has landed. Fires once per Genie
|
|
118
|
+
* tool invocation, AFTER `agent.generate(...)` completes (i.e.
|
|
119
|
+
* the inner loop + Mastra's structuring pass have both
|
|
120
|
+
* finished) and BEFORE the wrapper hydrates each `data` item
|
|
121
|
+
* with a chart. Signals to the host UI that the agent has
|
|
122
|
+
* stopped reasoning and is moving into chart generation.
|
|
123
|
+
*
|
|
124
|
+
* The structuring pass itself is opaque (it runs inside
|
|
125
|
+
* Mastra's `agent.generate(...)` together with the tool loop)
|
|
126
|
+
* so this is the earliest hook we can offer; we can't fire a
|
|
127
|
+
* "summary started" event the way we fire `started`.
|
|
128
|
+
*/
|
|
129
|
+
export const SummaryEventSchema = z.object({
|
|
130
|
+
type: z.literal("summary"),
|
|
131
|
+
spaceId: z.string(),
|
|
132
|
+
/** Total number of items in the agent's structured summary. */
|
|
133
|
+
items: z.number().int().nonnegative(),
|
|
134
|
+
/** Count of `text` / prose items in the summary. */
|
|
135
|
+
textItems: z.number().int().nonnegative(),
|
|
136
|
+
/**
|
|
137
|
+
* Count of `data` items the wrapper will hydrate into charts.
|
|
138
|
+
* The host UI can use this to seed N chart skeletons before
|
|
139
|
+
* the per-chart events arrive.
|
|
140
|
+
*/
|
|
141
|
+
dataItems: z.number().int().nonnegative(),
|
|
142
|
+
});
|
|
143
|
+
/**
|
|
144
|
+
* Mastra-only render event: a chart was rendered for the active
|
|
145
|
+
* turn. Emitted by the chart-rendering tool (and replayed from
|
|
146
|
+
* `genieResultToWriterEvents` on history reload) so the host UI
|
|
147
|
+
* can drop an `[[chart:<chartId>]]`-keyed slot inline. Carries
|
|
148
|
+
* the dataset (for the table fallback / hover) and the resolved
|
|
149
|
+
* Echarts `option` in a single event keyed by `chartId`.
|
|
150
|
+
*/
|
|
151
|
+
export const ChartEventSchema = z.object({
|
|
152
|
+
type: z.literal("chart"),
|
|
153
|
+
chartId: z.string(),
|
|
154
|
+
title: z.string().optional(),
|
|
155
|
+
description: z.string().optional(),
|
|
156
|
+
/** Dataset rows; populated on the first emit per `chartId`. */
|
|
157
|
+
data: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
158
|
+
/** Echarts option spec; populated on the follow-up emit. */
|
|
159
|
+
option: z.record(z.string(), z.unknown()).optional(),
|
|
160
|
+
/**
|
|
161
|
+
* Statement id the chart was built from, when known. Lets the
|
|
162
|
+
* host UI correlate the chart with the matching `query` /
|
|
163
|
+
* `statement` events from the same turn.
|
|
164
|
+
*/
|
|
165
|
+
statementId: z.string().optional(),
|
|
166
|
+
/**
|
|
167
|
+
* Genie `message_id` the chart was built from. Stamped from the
|
|
168
|
+
* `ask_genie` turn whose statement produced these rows so the
|
|
169
|
+
* host UI can group the chart into the same pill bucket as the
|
|
170
|
+
* other `message_id`-keyed events from that turn.
|
|
171
|
+
*/
|
|
172
|
+
messageId: z.string().optional(),
|
|
173
|
+
});
|
|
174
|
+
/**
|
|
175
|
+
* Mastra-only event union. Each variant uses the same flat
|
|
176
|
+
* `{type, ...fields}` shape as {@link GenieChatEvent} so
|
|
177
|
+
* subscribers union both with a single `switch (event.type)`.
|
|
178
|
+
*/
|
|
179
|
+
export const GenieAgentEventSchema = z.discriminatedUnion("type", [
|
|
180
|
+
StartedEventSchema,
|
|
181
|
+
AskGenieDoneEventSchema,
|
|
182
|
+
MastraGenieErrorEventSchema,
|
|
183
|
+
SummaryEventSchema,
|
|
184
|
+
ChartEventSchema,
|
|
185
|
+
]);
|
|
186
|
+
/**
|
|
187
|
+
* The unified writer-event vocabulary subscribers see on
|
|
188
|
+
* `ctx.writer`: the wire-derived {@link GenieChatEvent} union
|
|
189
|
+
* **plus** Mastra-only events from {@link GenieAgentEvent}. Each
|
|
190
|
+
* variant is a flat `{type, ...fields}` object; consumers narrow
|
|
191
|
+
* on `type` and read fields inline - there is no payload wrapper
|
|
192
|
+
* and no writer-boundary translator.
|
|
193
|
+
*
|
|
194
|
+
* Composed via `z.union` (not `z.discriminatedUnion`) because
|
|
195
|
+
* both halves are themselves discriminated unions on the same
|
|
196
|
+
* `type` key.
|
|
197
|
+
*/
|
|
198
|
+
export const GenieWriterEventSchema = z.union([
|
|
199
|
+
GenieChatEventSchema,
|
|
200
|
+
GenieAgentEventSchema,
|
|
201
|
+
]);
|
|
202
|
+
/* ------------------------- summary + dataset ------------------------ */
|
|
203
|
+
/**
|
|
204
|
+
* Tabular payload embedded in every {@link GenieSummaryItem}
|
|
205
|
+
* `visualize` dataset. Always present: hydrated by the workflow's
|
|
206
|
+
* agent step before the finalize step runs, so consumers can render
|
|
207
|
+
* a table fallback regardless of chart-planner outcome.
|
|
208
|
+
*
|
|
209
|
+
* Fields:
|
|
210
|
+
* - `columns`: column names in display order.
|
|
211
|
+
* - `rows`: tabular rows keyed by column name.
|
|
212
|
+
* - `rowCount`: total row count Genie reported (may exceed
|
|
213
|
+
* `rows.length` when the statement was truncated).
|
|
214
|
+
*/
|
|
215
|
+
export const GenieDatasetDataSchema = z.object({
|
|
216
|
+
columns: z.array(z.string()),
|
|
217
|
+
rows: z.array(z.record(z.string(), z.unknown())),
|
|
218
|
+
rowCount: z.number(),
|
|
219
|
+
});
|
|
220
|
+
/**
|
|
221
|
+
* Slim chart reference attached to a visualize dataset once the
|
|
222
|
+
* workflow's finalize step runs the chart-planner. Only present
|
|
223
|
+
* when planning succeeded.
|
|
224
|
+
*
|
|
225
|
+
* `option` is intentionally NOT included. The resolved Echarts
|
|
226
|
+
* spec lives off-band:
|
|
227
|
+
*
|
|
228
|
+
* - On the wire to the UI: in the matching {@link ChartEvent}
|
|
229
|
+
* writer event (the host UI receives both this dataset and
|
|
230
|
+
* the writer event and joins them on `chartId`).
|
|
231
|
+
* - On the server: in the per-request {@link RequestContext}
|
|
232
|
+
* under the chart inventory key (see appkit-mastra's
|
|
233
|
+
* `chartInventoryFromContext`), so output processors and
|
|
234
|
+
* downstream tools can look up the full payload by `chartId`
|
|
235
|
+
* without round-tripping through the LLM.
|
|
236
|
+
*
|
|
237
|
+
* Why slim: full Echarts options nest deeply and are several
|
|
238
|
+
* KB per chart. Embedding them in the tool result means every
|
|
239
|
+
* subsequent turn of the agent loop reads them back into context
|
|
240
|
+
* for zero LLM benefit (the model only needs the `chartId` to
|
|
241
|
+
* place a `[[chart:<chartId>]]` marker).
|
|
242
|
+
*/
|
|
243
|
+
export const GenieDatasetChartSchema = z.object({
|
|
244
|
+
chartId: z.string(),
|
|
245
|
+
chartType: z.enum(["bar", "line", "area", "scatter", "pie"]),
|
|
246
|
+
});
|
|
247
|
+
/**
|
|
248
|
+
* Dataset bundle attached to a {@link GenieSummaryItem} `visualize`
|
|
249
|
+
* item. `data` is always populated; `chart` is best-effort and
|
|
250
|
+
* absent when the workflow's chart-planner failed (timeout,
|
|
251
|
+
* malformed plan, abort) so the host UI can still render the
|
|
252
|
+
* underlying table.
|
|
253
|
+
*/
|
|
254
|
+
export const GenieDatasetSchema = z.object({
|
|
255
|
+
data: GenieDatasetDataSchema,
|
|
256
|
+
chart: GenieDatasetChartSchema.optional(),
|
|
257
|
+
});
|
|
258
|
+
/**
|
|
259
|
+
* One item inside the Genie workflow's final summary. The
|
|
260
|
+
* workflow produces a mixed sequence of:
|
|
261
|
+
*
|
|
262
|
+
* - `string`: a markdown paragraph (interpretation, callouts,
|
|
263
|
+
* transitions between data blocks).
|
|
264
|
+
* - `visualize`: a request from the agent step to visualize a
|
|
265
|
+
* specific Genie statement at this position in the prose.
|
|
266
|
+
* The finalize step hydrates `dataset.data` (rows from the
|
|
267
|
+
* matching `statementId`) and attaches `dataset.chart` after
|
|
268
|
+
* running the chart-planner. The agent NEVER picks the chart
|
|
269
|
+
* type - it only marks where a visualization belongs.
|
|
270
|
+
*
|
|
271
|
+
* The host UI walks the array in display order to compose the
|
|
272
|
+
* final assistant message.
|
|
273
|
+
*/
|
|
274
|
+
export const GenieSummaryItemSchema = z.discriminatedUnion("type", [
|
|
275
|
+
z.object({
|
|
276
|
+
type: z.literal("string"),
|
|
277
|
+
text: z.string(),
|
|
278
|
+
}),
|
|
279
|
+
z.object({
|
|
280
|
+
type: z.literal("visualize"),
|
|
281
|
+
statementId: z.string(),
|
|
282
|
+
title: z.string().optional(),
|
|
283
|
+
description: z.string().optional(),
|
|
284
|
+
dataset: GenieDatasetSchema,
|
|
285
|
+
}),
|
|
286
|
+
]);
|
|
287
|
+
/**
|
|
288
|
+
* The Genie agent's final output shape - what the calling agent's
|
|
289
|
+
* Genie tool returns to the calling LLM. The `summary` array is
|
|
290
|
+
* the user-facing renderable; `conversationId` lets the calling
|
|
291
|
+
* agent (or the UI) follow up in the same Genie thread on the
|
|
292
|
+
* next turn.
|
|
293
|
+
*/
|
|
294
|
+
export const GenieAgentResultSchema = z.object({
|
|
295
|
+
spaceId: z.string(),
|
|
296
|
+
conversationId: z.string().optional(),
|
|
297
|
+
summary: z.array(GenieSummaryItemSchema),
|
|
298
|
+
error: z.string().optional(),
|
|
299
|
+
});
|
|
300
|
+
/**
|
|
301
|
+
* Structural type guard for {@link GenieAgentResult}. Used by
|
|
302
|
+
* host UIs to detect the Genie agent's payload off Mastra's
|
|
303
|
+
* `tool-result` chunks without coupling to a specific Mastra tool
|
|
304
|
+
* name (per-space variants like `tool-genie-<alias>` all return
|
|
305
|
+
* the same shape).
|
|
306
|
+
*
|
|
307
|
+
* Cheap structural check (vs full `safeParse`) so the guard stays
|
|
308
|
+
* O(1) on the hot path; consumers that want full validation can
|
|
309
|
+
* call {@link GenieAgentResultSchema}`.safeParse(value)` directly.
|
|
310
|
+
*/
|
|
311
|
+
export function isGenieAgentResult(value) {
|
|
312
|
+
if (!value || typeof value !== "object")
|
|
313
|
+
return false;
|
|
314
|
+
const v = value;
|
|
315
|
+
return typeof v.spaceId === "string" && Array.isArray(v.summary);
|
|
316
|
+
}
|
|
317
|
+
/* ---------------------- result -> writer-event helpers ---------------------- */
|
|
318
|
+
/**
|
|
319
|
+
* Walk a {@link GenieAgentResult} and produce the lifecycle
|
|
320
|
+
* writer events a host UI needs to replay terminal state inline.
|
|
321
|
+
*
|
|
322
|
+
* Chart replay is intentionally NOT supported: the resolved
|
|
323
|
+
* Echarts `option` is held off-band in the per-request
|
|
324
|
+
* `RequestContext` (and on the live writer event when the run is
|
|
325
|
+
* in flight), not on the persisted summary, so a completed run
|
|
326
|
+
* read back from storage has no chart spec to replay. Host UIs
|
|
327
|
+
* that want post-reload chart rendering need to plumb the spec
|
|
328
|
+
* through a separate persisted side-channel.
|
|
329
|
+
*
|
|
330
|
+
* Currently extracted:
|
|
331
|
+
*
|
|
332
|
+
* - `type: "error"` when `output.error` is set (Genie returned
|
|
333
|
+
* `FAILED` / `CANCELLED`, `getStatement` errored, etc.).
|
|
334
|
+
*
|
|
335
|
+
* `string` summary items are not surfaced here - the calling
|
|
336
|
+
* LLM's text reply renders them inline.
|
|
337
|
+
*/
|
|
338
|
+
export function genieResultToWriterEvents(output) {
|
|
339
|
+
const events = [];
|
|
340
|
+
if (output.error) {
|
|
341
|
+
events.push({
|
|
342
|
+
type: "error",
|
|
343
|
+
spaceId: output.spaceId,
|
|
344
|
+
...(output.conversationId ? { conversationId: output.conversationId } : {}),
|
|
345
|
+
error: output.error,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return events;
|
|
349
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL helpers for the Mastra plugin's published
|
|
3
|
+
* {@link MastraClientConfig} surface. Kept in a separate module
|
|
4
|
+
* from `protocol.ts` so the protocol stays purely declarative
|
|
5
|
+
* (schemas + inferred types) and consumers that only need URL
|
|
6
|
+
* composition import this file without re-evaluating the schemas.
|
|
7
|
+
*
|
|
8
|
+
* Both helpers accept a `Pick<MastraClientConfig, ...>` so callers
|
|
9
|
+
* can pass a freshly read config or any object that exposes the
|
|
10
|
+
* relevant fields - useful for tests and for partial configs the
|
|
11
|
+
* React client composes from `usePluginClientConfig`.
|
|
12
|
+
*/
|
|
13
|
+
import type { MastraClientConfig } from "./protocol.js";
|
|
14
|
+
/**
|
|
15
|
+
* Compute the chat URL for a given agent, falling back to the
|
|
16
|
+
* default when `agentId` is omitted. Returns `config.chatPath`
|
|
17
|
+
* directly for the default agent (the `chatRoute` mount that does
|
|
18
|
+
* not require an `:agentId` segment).
|
|
19
|
+
*/
|
|
20
|
+
export declare function chatUrl(config: Pick<MastraClientConfig, "chatPath" | "defaultAgent">, agentId?: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Build the history URL for a given agent + page. Mirrors
|
|
23
|
+
* {@link chatUrl}: the default agent uses the bare `historyPath`,
|
|
24
|
+
* any other agent appends `/<encoded id>` to it. `page` and
|
|
25
|
+
* `perPage` are appended as query parameters when provided.
|
|
26
|
+
*/
|
|
27
|
+
export declare function historyUrl(config: Pick<MastraClientConfig, "historyPath" | "defaultAgent">, options?: {
|
|
28
|
+
agentId?: string;
|
|
29
|
+
page?: number;
|
|
30
|
+
perPage?: number;
|
|
31
|
+
}): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL helpers for the Mastra plugin's published
|
|
3
|
+
* {@link MastraClientConfig} surface. Kept in a separate module
|
|
4
|
+
* from `protocol.ts` so the protocol stays purely declarative
|
|
5
|
+
* (schemas + inferred types) and consumers that only need URL
|
|
6
|
+
* composition import this file without re-evaluating the schemas.
|
|
7
|
+
*
|
|
8
|
+
* Both helpers accept a `Pick<MastraClientConfig, ...>` so callers
|
|
9
|
+
* can pass a freshly read config or any object that exposes the
|
|
10
|
+
* relevant fields - useful for tests and for partial configs the
|
|
11
|
+
* React client composes from `usePluginClientConfig`.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Compute the chat URL for a given agent, falling back to the
|
|
15
|
+
* default when `agentId` is omitted. Returns `config.chatPath`
|
|
16
|
+
* directly for the default agent (the `chatRoute` mount that does
|
|
17
|
+
* not require an `:agentId` segment).
|
|
18
|
+
*/
|
|
19
|
+
export function chatUrl(config, agentId) {
|
|
20
|
+
const id = agentId ?? config.defaultAgent;
|
|
21
|
+
if (!id || id === config.defaultAgent)
|
|
22
|
+
return config.chatPath;
|
|
23
|
+
return `${config.chatPath}/${encodeURIComponent(id)}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build the history URL for a given agent + page. Mirrors
|
|
27
|
+
* {@link chatUrl}: the default agent uses the bare `historyPath`,
|
|
28
|
+
* any other agent appends `/<encoded id>` to it. `page` and
|
|
29
|
+
* `perPage` are appended as query parameters when provided.
|
|
30
|
+
*/
|
|
31
|
+
export function historyUrl(config, options = {}) {
|
|
32
|
+
const id = options.agentId ?? config.defaultAgent;
|
|
33
|
+
const base = !id || id === config.defaultAgent
|
|
34
|
+
? config.historyPath
|
|
35
|
+
: `${config.historyPath}/${encodeURIComponent(id)}`;
|
|
36
|
+
const params = new URLSearchParams();
|
|
37
|
+
if (options.page !== undefined)
|
|
38
|
+
params.set("page", String(options.page));
|
|
39
|
+
if (options.perPage !== undefined) {
|
|
40
|
+
params.set("perPage", String(options.perPage));
|
|
41
|
+
}
|
|
42
|
+
const qs = params.toString();
|
|
43
|
+
return qs ? `${base}?${qs}` : base;
|
|
44
|
+
}
|