@dbx-tools/appkit-mastra 0.1.18 → 0.1.19
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 +78 -66
- package/dist/src/agents.js +6 -7
- package/dist/src/chart.js +7 -29
- package/dist/src/genie.d.ts +5 -6
- package/dist/src/genie.js +16 -36
- package/dist/src/history.js +3 -3
- package/dist/src/writer.d.ts +23 -0
- package/dist/src/writer.js +37 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/agents.ts +6 -7
- package/src/chart.ts +24 -40
- package/src/genie.ts +91 -111
- package/src/history.ts +3 -3
- package/src/writer.ts +44 -0
package/README.md
CHANGED
|
@@ -190,65 +190,72 @@ that implements the standard `getAgentTools()` + `executeAgentTool()` +
|
|
|
190
190
|
`executeAgentTool`, so OBO auth (`asUser`) and telemetry spans stay
|
|
191
191
|
intact.
|
|
192
192
|
|
|
193
|
-
`plugins.genie` is special-cased: it
|
|
194
|
-
(
|
|
195
|
-
|
|
196
|
-
`
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
Genie tool-result shape (LLM-bound):
|
|
193
|
+
`plugins.genie` is special-cased: it talks to Genie directly via
|
|
194
|
+
`@dbx-tools/genie` (`genieEventChat`) rather than calling AppKit's
|
|
195
|
+
stock `genie` toolkit. Each invocation spins up a per-call inner
|
|
196
|
+
Mastra `Agent` with three tools (`ask_genie`,
|
|
197
|
+
`get_space_description`, `get_space_serialized`), runs it with
|
|
198
|
+
`structuredOutput`, and produces a hydrated
|
|
199
|
+
{@link GenieAgentResult}. AppKit's `genie()` plugin is honored
|
|
200
|
+
only for its `spaces` config (and the matching
|
|
201
|
+
`app.yaml`-declared resources). Tool ids are stable: `genie` for
|
|
202
|
+
the default alias, `genie_<alias>` for additional aliases.
|
|
203
|
+
|
|
204
|
+
Genie tool-result shape (LLM-bound) is the
|
|
205
|
+
[`GenieAgentResult`](../appkit-mastra-shared/src/genie.ts) type:
|
|
207
206
|
|
|
208
|
-
```
|
|
209
|
-
{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
207
|
+
```ts
|
|
208
|
+
type GenieAgentResult = {
|
|
209
|
+
spaceId: string;
|
|
210
|
+
conversationId?: string; // thread back to continue the same Genie thread
|
|
211
|
+
summary: Array< // ordered prose + visualize slots
|
|
212
|
+
| { type: "string"; text: string }
|
|
213
|
+
| {
|
|
214
|
+
type: "visualize";
|
|
215
|
+
statementId: string;
|
|
216
|
+
title?: string;
|
|
217
|
+
description?: string;
|
|
218
|
+
dataset: {
|
|
219
|
+
data: { columns: string[]; rows: Row[]; rowCount: number };
|
|
220
|
+
chart?: { chartId: string; chartType: "bar" | "line" | "area" | "scatter" | "pie" };
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
>;
|
|
224
|
+
error?: string;
|
|
225
|
+
};
|
|
223
226
|
```
|
|
224
227
|
|
|
225
|
-
`
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
228
|
+
The `summary` is the user-facing renderable: a mixed sequence of
|
|
229
|
+
prose paragraphs (`type: "string"`) and `visualize` slots that
|
|
230
|
+
mark where a chart should appear in the model's final answer.
|
|
231
|
+
Visualize slots embed the dataset (rows + columns) plus a slim
|
|
232
|
+
`chart` reference (just `chartId` + `chartType`); the resolved
|
|
233
|
+
Echarts spec rides a separate `type: "chart"` writer event so the
|
|
234
|
+
LLM never holds it in context. The host UI joins the dataset and
|
|
235
|
+
the writer event by `chartId` and renders inline at the matching
|
|
236
|
+
`[[chart:<chartId>]]` marker.
|
|
237
|
+
|
|
238
|
+
Genie writer event flow:
|
|
239
|
+
|
|
240
|
+
- The writer emits the flat
|
|
241
|
+
[`GenieWriterEvent`](../appkit-mastra-shared/src/genie.ts)
|
|
242
|
+
union for the live loading pill - the wire-derived
|
|
243
|
+
`GenieChatEvent` (status / thinking / sql / rows / suggested)
|
|
244
|
+
plus the Mastra-only lifecycle events (`started`,
|
|
245
|
+
`ask_genie_done`, `summary`, `chart`, `error`).
|
|
246
|
+
- The writer emits one `type: "chart"` event per executed SQL
|
|
247
|
+
statement carrying `{chartId, title, description?, data,
|
|
248
|
+
option, statementId, messageId}`. The chat client's
|
|
249
|
+
`<ChartSlot>` renders inline at the matching
|
|
250
|
+
`[[chart:<chartId>]]` marker. This is the exact same wire
|
|
251
|
+
format as the `render_data` tool, so Genie and hand-built
|
|
252
|
+
charts are indistinguishable on the client.
|
|
253
|
+
- After a hard reload, `synthesizeToolEventsFromHistory`
|
|
254
|
+
reconstructs lifecycle events from the persisted summary
|
|
255
|
+
(`error` events via `genieResultToWriterEvents`); live-only
|
|
256
|
+
events (rows, SQL pill, chart specs) don't replay because the
|
|
257
|
+
resolved Echarts spec is held off-band on the per-request
|
|
258
|
+
`RequestContext`.
|
|
252
259
|
|
|
253
260
|
### `render_data` (system-default ambient tool)
|
|
254
261
|
|
|
@@ -710,20 +717,25 @@ function Chat() {
|
|
|
710
717
|
mount, so a custom `mastra({ name: "myMastra" })` rewrites every path):
|
|
711
718
|
|
|
712
719
|
|
|
713
|
-
| Field
|
|
714
|
-
|
|
|
715
|
-
| `basePath`
|
|
716
|
-
| `chatPath`
|
|
717
|
-
| `chatPathTemplate`
|
|
718
|
-
| `modelsPath`
|
|
719
|
-
| `
|
|
720
|
-
| `
|
|
720
|
+
| Field | Example | Description |
|
|
721
|
+
| --------------------- | -------------------------------------- | -------------------------------------------------------------------- |
|
|
722
|
+
| `basePath` | `"/api/mastra"` | Plugin mount path. |
|
|
723
|
+
| `chatPath` | `"/api/mastra/route/chat"` | Default-agent chat URL. Use `chatUrl(config)` to get it. |
|
|
724
|
+
| `chatPathTemplate` | `"/api/mastra/route/chat/:agentId"` | OpenAPI-style template for tools / docs. |
|
|
725
|
+
| `modelsPath` | `"/api/mastra/models"` | `GET` cached endpoint catalogue. |
|
|
726
|
+
| `historyPath` | `"/api/mastra/route/history"` | Default-agent thread history. Use `historyUrl(config, opts)`. |
|
|
727
|
+
| `historyPathTemplate` | `"/api/mastra/route/history/:agentId"` | OpenAPI-style template for tools / docs. |
|
|
728
|
+
| `defaultAgent` | `"analyst"` | Agent id `chatRoute` binds to when none is supplied. |
|
|
729
|
+
| `agents` | `["analyst", "helper"]` | Every registered agent id in order. |
|
|
721
730
|
|
|
722
731
|
|
|
723
732
|
`chatUrl(config, agentId?)` returns `config.chatPath` for the default
|
|
724
733
|
agent (the registered `chatRoute` mount that omits `:agentId`), and
|
|
725
|
-
`${config.chatPath}/${encodeURIComponent(agentId)}` otherwise.
|
|
726
|
-
|
|
734
|
+
`${config.chatPath}/${encodeURIComponent(agentId)}` otherwise. The
|
|
735
|
+
sibling `historyUrl(config, { agentId?, page?, perPage? })` mirrors
|
|
736
|
+
that pattern for the `/history` endpoint and appends pagination
|
|
737
|
+
query parameters when provided. Both are pure functions: no React,
|
|
738
|
+
no hooks, safe in service workers and SSR.
|
|
727
739
|
|
|
728
740
|
## License
|
|
729
741
|
|
package/dist/src/agents.js
CHANGED
|
@@ -389,13 +389,12 @@ function buildPluginsMap(config, context) {
|
|
|
389
389
|
* Genie agent inherits the same model resolver / fallback
|
|
390
390
|
* ladder the calling agents use.
|
|
391
391
|
*
|
|
392
|
-
* The
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
* keep working without change.
|
|
392
|
+
* The Genie agent talks to Genie directly via `@dbx-tools/genie`
|
|
393
|
+
* (`genieEventChat`) and the workspace
|
|
394
|
+
* `statementExecution.getStatement` API. AppKit's stock `genie`
|
|
395
|
+
* plugin is honored only for its resource manifest and `spaces`
|
|
396
|
+
* config so existing `app.yaml` configs and `genie({ spaces })`
|
|
397
|
+
* wiring keep working without change.
|
|
399
398
|
*/
|
|
400
399
|
function resolveProvider(config, context, propName) {
|
|
401
400
|
if (propName === "genie") {
|
package/dist/src/chart.js
CHANGED
|
@@ -31,6 +31,7 @@ import { Agent } from "@mastra/core/agent";
|
|
|
31
31
|
import { createTool } from "@mastra/core/tools";
|
|
32
32
|
import { z } from "zod";
|
|
33
33
|
import { ModelTier, modelForTier, buildModel } from "./model.js";
|
|
34
|
+
import { safeWrite } from "./writer.js";
|
|
34
35
|
/**
|
|
35
36
|
* Module-level logger tagged `[mastra/chart]`. Uses the shared
|
|
36
37
|
* {@link logUtils.logger} so calls below `LOG_LEVEL` are
|
|
@@ -373,56 +374,33 @@ export function buildRenderDataTool(config) {
|
|
|
373
374
|
// for the table-like fallback / hover, option for the
|
|
374
375
|
// actual render. Best-effort write so a closed
|
|
375
376
|
// downstream stream can't take the tool down.
|
|
376
|
-
await safeWrite(
|
|
377
|
+
await safeWrite(log, writer, {
|
|
377
378
|
type: "chart",
|
|
378
379
|
chartId,
|
|
379
380
|
title,
|
|
380
381
|
...(description ? { description } : {}),
|
|
381
382
|
data,
|
|
382
383
|
option,
|
|
383
|
-
});
|
|
384
|
+
}, { chartId });
|
|
384
385
|
}
|
|
385
386
|
catch (err) {
|
|
386
387
|
log.warn("render:error", {
|
|
387
388
|
chartId,
|
|
388
389
|
elapsedMs: Date.now() - startedAt,
|
|
389
|
-
error:
|
|
390
|
+
error: commonUtils.errorMessage(err),
|
|
390
391
|
});
|
|
391
392
|
// Surface as a writer-level error so the slot can
|
|
392
393
|
// transition to "couldn't render chart" without the
|
|
393
394
|
// parent agent surfacing a stack trace.
|
|
394
|
-
await safeWrite(
|
|
395
|
+
await safeWrite(log, writer, {
|
|
395
396
|
type: "error",
|
|
396
|
-
error:
|
|
397
|
-
});
|
|
397
|
+
error: commonUtils.errorMessage(err),
|
|
398
|
+
}, { chartId });
|
|
398
399
|
}
|
|
399
400
|
return { chartId };
|
|
400
401
|
},
|
|
401
402
|
});
|
|
402
403
|
}
|
|
403
|
-
/**
|
|
404
|
-
* Best-effort writer.write. Failures are logged at `warn` (a
|
|
405
|
-
* persistently-closed writer is the most likely culprit when
|
|
406
|
-
* chart events go missing client-side) but swallowed so a closed
|
|
407
|
-
* downstream stream (cancelled request, client navigated away)
|
|
408
|
-
* can't take a tool down.
|
|
409
|
-
*/
|
|
410
|
-
async function safeWrite(writer, chartId, chunk) {
|
|
411
|
-
if (!writer) {
|
|
412
|
-
log.debug("write:no-writer", { chartId });
|
|
413
|
-
return;
|
|
414
|
-
}
|
|
415
|
-
try {
|
|
416
|
-
await writer.write(chunk);
|
|
417
|
-
log.debug("write:ok", { chartId });
|
|
418
|
-
}
|
|
419
|
-
catch (err) {
|
|
420
|
-
log.warn("write:error", {
|
|
421
|
-
chartId,
|
|
422
|
-
error: err instanceof Error ? err.message : String(err),
|
|
423
|
-
});
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
404
|
/**
|
|
427
405
|
* Expand a {@link ChartPlan} into a full Echarts `EChartsOption`
|
|
428
406
|
* JSON. Centralized here so the planner agent only fills in the
|
package/dist/src/genie.d.ts
CHANGED
|
@@ -32,12 +32,11 @@
|
|
|
32
32
|
* {@link GenieSummaryItem} `string` variant, and returns the
|
|
33
33
|
* hydrated {@link GenieAgentResult}.
|
|
34
34
|
*
|
|
35
|
-
* The
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* keeps working without change.
|
|
35
|
+
* The inner agent talks to Genie directly via
|
|
36
|
+
* `@dbx-tools/genie` (`genieEventChat`) and the workspace
|
|
37
|
+
* `statementExecution.getStatement` API. AppKit's stock `genie`
|
|
38
|
+
* plugin is honored only for its `spaces` config so existing
|
|
39
|
+
* AppKit-style wiring keeps working without change.
|
|
41
40
|
*/
|
|
42
41
|
import { type ChartEvent } from "@dbx-tools/appkit-mastra-shared";
|
|
43
42
|
import { appkitUtils } from "@dbx-tools/shared";
|
package/dist/src/genie.js
CHANGED
|
@@ -32,12 +32,11 @@
|
|
|
32
32
|
* {@link GenieSummaryItem} `string` variant, and returns the
|
|
33
33
|
* hydrated {@link GenieAgentResult}.
|
|
34
34
|
*
|
|
35
|
-
* The
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* keeps working without change.
|
|
35
|
+
* The inner agent talks to Genie directly via
|
|
36
|
+
* `@dbx-tools/genie` (`genieEventChat`) and the workspace
|
|
37
|
+
* `statementExecution.getStatement` API. AppKit's stock `genie`
|
|
38
|
+
* plugin is honored only for its `spaces` config so existing
|
|
39
|
+
* AppKit-style wiring keeps working without change.
|
|
41
40
|
*/
|
|
42
41
|
import { CacheManager, genie } from "@databricks/appkit";
|
|
43
42
|
import { ApiError, HttpError, WorkspaceClient } from "@databricks/sdk-experimental";
|
|
@@ -52,6 +51,7 @@ import { z } from "zod";
|
|
|
52
51
|
import { runChartPlanner } from "./chart.js";
|
|
53
52
|
import { MASTRA_USER_KEY } from "./config.js";
|
|
54
53
|
import { buildModel } from "./model.js";
|
|
54
|
+
import { safeWrite } from "./writer.js";
|
|
55
55
|
const log = logUtils.logger("mastra/genie");
|
|
56
56
|
/** Default alias used when a single unnamed Genie space is wired up. */
|
|
57
57
|
export const DEFAULT_GENIE_ALIAS = "default";
|
|
@@ -118,26 +118,6 @@ function extractStatementId(message) {
|
|
|
118
118
|
}
|
|
119
119
|
return undefined;
|
|
120
120
|
}
|
|
121
|
-
/**
|
|
122
|
-
* Best-effort `writer.write`. The writer carries the unified flat
|
|
123
|
-
* event vocabulary directly - no translation layer - so
|
|
124
|
-
* subscribers narrow on `event.type` and read fields inline.
|
|
125
|
-
* Failures (downstream stream closed, cancelled request) are
|
|
126
|
-
* swallowed with a `warn` log so an in-flight Genie turn isn't
|
|
127
|
-
* taken down by a navigated-away client.
|
|
128
|
-
*/
|
|
129
|
-
async function safeWrite(writer, chunk) {
|
|
130
|
-
if (!writer)
|
|
131
|
-
return;
|
|
132
|
-
try {
|
|
133
|
-
await writer.write(chunk);
|
|
134
|
-
}
|
|
135
|
-
catch (err) {
|
|
136
|
-
log.warn("writer:error", {
|
|
137
|
-
error: err instanceof Error ? err.message : String(err),
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
121
|
/**
|
|
142
122
|
* Lowercased placeholder strings we reject at the `ask_genie`
|
|
143
123
|
* boundary so the LLM doesn't spend a Genie round-trip on a
|
|
@@ -279,7 +259,7 @@ async function readCachedConversationId(cacheKey) {
|
|
|
279
259
|
}
|
|
280
260
|
catch (err) {
|
|
281
261
|
log.warn("conversation-cache:read-error", {
|
|
282
|
-
error:
|
|
262
|
+
error: commonUtils.errorMessage(err),
|
|
283
263
|
});
|
|
284
264
|
return undefined;
|
|
285
265
|
}
|
|
@@ -301,7 +281,7 @@ async function saveCachedConversationId(cacheKey, conversationId) {
|
|
|
301
281
|
}
|
|
302
282
|
catch (err) {
|
|
303
283
|
log.warn("conversation-cache:write-error", {
|
|
304
|
-
error:
|
|
284
|
+
error: commonUtils.errorMessage(err),
|
|
305
285
|
});
|
|
306
286
|
}
|
|
307
287
|
}
|
|
@@ -314,7 +294,7 @@ async function evictCachedConversationId(cacheKey) {
|
|
|
314
294
|
}
|
|
315
295
|
catch (err) {
|
|
316
296
|
log.warn("conversation-cache:delete-error", {
|
|
317
|
-
error:
|
|
297
|
+
error: commonUtils.errorMessage(err),
|
|
318
298
|
});
|
|
319
299
|
}
|
|
320
300
|
}
|
|
@@ -397,7 +377,7 @@ function buildAskGenieTool(deps) {
|
|
|
397
377
|
...(seedConversationId ? { conversationId: seedConversationId } : {}),
|
|
398
378
|
...(signal ? { context: signal } : {}),
|
|
399
379
|
})) {
|
|
400
|
-
await safeWrite(writer, event);
|
|
380
|
+
await safeWrite(log, writer, event);
|
|
401
381
|
// Wire events come in two flavors: the lifecycle `message`
|
|
402
382
|
// event embeds the raw `GenieMessage` (read its
|
|
403
383
|
// `conversation_id`), and the rest carry a flat
|
|
@@ -437,7 +417,7 @@ function buildAskGenieTool(deps) {
|
|
|
437
417
|
log.warn("conversation-cache:stale, resetting", {
|
|
438
418
|
spaceId,
|
|
439
419
|
conversationId: seeded,
|
|
440
|
-
error:
|
|
420
|
+
error: commonUtils.errorMessage(err),
|
|
441
421
|
});
|
|
442
422
|
await evictCachedConversationId(cacheKey);
|
|
443
423
|
writeContextConversationId(requestContext, spaceId, undefined);
|
|
@@ -663,7 +643,7 @@ export function createGenieTool(opts) {
|
|
|
663
643
|
spaceId,
|
|
664
644
|
content: input.question,
|
|
665
645
|
};
|
|
666
|
-
await safeWrite(writer, startedEvent);
|
|
646
|
+
await safeWrite(log, writer, startedEvent);
|
|
667
647
|
const resultSets = new Map();
|
|
668
648
|
// Seed the active Genie `conversation_id` onto
|
|
669
649
|
// `RequestContext` from AppKit's `CacheManager` when a Mastra
|
|
@@ -801,7 +781,7 @@ export function createGenieTool(opts) {
|
|
|
801
781
|
textItems: textItemCount,
|
|
802
782
|
dataItems: dataItemCount,
|
|
803
783
|
};
|
|
804
|
-
await safeWrite(writer, summaryEvent);
|
|
784
|
+
await safeWrite(log, writer, summaryEvent);
|
|
805
785
|
// Chart every `data` item in parallel; map `text` items to
|
|
806
786
|
// the shared `string` summary variant verbatim. Missing
|
|
807
787
|
// statement ids are dropped (the agent referenced something
|
|
@@ -856,7 +836,7 @@ export function createGenieTool(opts) {
|
|
|
856
836
|
data: data.rows,
|
|
857
837
|
option: planned.option,
|
|
858
838
|
};
|
|
859
|
-
await safeWrite(writer, chartEvent);
|
|
839
|
+
await safeWrite(log, writer, chartEvent);
|
|
860
840
|
// Stash the resolved chart on the per-request
|
|
861
841
|
// `RequestContext` so downstream code in the same
|
|
862
842
|
// request (output processors, follow-up tool calls,
|
|
@@ -865,7 +845,7 @@ export function createGenieTool(opts) {
|
|
|
865
845
|
recordChartInContext(requestContext, chartEvent);
|
|
866
846
|
}
|
|
867
847
|
catch (err) {
|
|
868
|
-
const errorMessage =
|
|
848
|
+
const errorMessage = commonUtils.errorMessage(err);
|
|
869
849
|
log.warn("chart:error", {
|
|
870
850
|
statementId: item.statementId,
|
|
871
851
|
messageId,
|
|
@@ -883,7 +863,7 @@ export function createGenieTool(opts) {
|
|
|
883
863
|
messageId,
|
|
884
864
|
error: `chart-planner: ${errorMessage}`,
|
|
885
865
|
};
|
|
886
|
-
await safeWrite(writer, errorEvent);
|
|
866
|
+
await safeWrite(log, writer, errorEvent);
|
|
887
867
|
}
|
|
888
868
|
return {
|
|
889
869
|
type: "visualize",
|
package/dist/src/history.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* the handler runs - no cookie or user lookups happen here, and the
|
|
16
16
|
* session-cookie logic stays the single source of truth in `server.ts`.
|
|
17
17
|
*/
|
|
18
|
-
import { logUtils } from "@dbx-tools/shared";
|
|
18
|
+
import { commonUtils, logUtils } from "@dbx-tools/shared";
|
|
19
19
|
import { toAISdkV5Messages } from "@mastra/ai-sdk/ui";
|
|
20
20
|
import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY, } from "@mastra/core/request-context";
|
|
21
21
|
import { registerApiRoute } from "@mastra/core/server";
|
|
@@ -116,7 +116,7 @@ export async function clearHistory(opts) {
|
|
|
116
116
|
log.debug("clear:probe-failed", {
|
|
117
117
|
agentId: opts.agent.id,
|
|
118
118
|
threadId: opts.threadId,
|
|
119
|
-
error:
|
|
119
|
+
error: commonUtils.errorMessage(err),
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
const startedAt = Date.now();
|
|
@@ -131,7 +131,7 @@ export async function clearHistory(opts) {
|
|
|
131
131
|
log.warn("clear:delete-soft-failed", {
|
|
132
132
|
agentId: opts.agent.id,
|
|
133
133
|
threadId: opts.threadId,
|
|
134
|
-
error:
|
|
134
|
+
error: commonUtils.errorMessage(err),
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
log.info("clear:done", {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper for publishing events through Mastra's
|
|
3
|
+
* `ctx.writer`. Centralizes the "the downstream stream may already
|
|
4
|
+
* be closed, don't take the whole tool down" pattern that the
|
|
5
|
+
* Genie agent and chart tool both need.
|
|
6
|
+
*
|
|
7
|
+
* Failures are logged at `warn` (a persistently-closed writer is
|
|
8
|
+
* the most likely culprit when events go missing client-side) but
|
|
9
|
+
* swallowed so a cancelled request or a client that navigated
|
|
10
|
+
* away can't crash a tool mid-flight.
|
|
11
|
+
*/
|
|
12
|
+
import type { MinimalWriter } from "@dbx-tools/appkit-mastra-shared";
|
|
13
|
+
import { type logUtils } from "@dbx-tools/shared";
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort `writer.write`. No-op when `writer` is undefined;
|
|
16
|
+
* caught errors are logged via `log.warn("writer:error", ...)`
|
|
17
|
+
* along with any caller-supplied `context` fields (e.g. a
|
|
18
|
+
* `chartId` or `messageId`) so the warning is greppable per
|
|
19
|
+
* resource.
|
|
20
|
+
*
|
|
21
|
+
* Returns when the write resolves or rejects; never throws.
|
|
22
|
+
*/
|
|
23
|
+
export declare function safeWrite(log: logUtils.Logger, writer: MinimalWriter | undefined, chunk: unknown, context?: Record<string, unknown>): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper for publishing events through Mastra's
|
|
3
|
+
* `ctx.writer`. Centralizes the "the downstream stream may already
|
|
4
|
+
* be closed, don't take the whole tool down" pattern that the
|
|
5
|
+
* Genie agent and chart tool both need.
|
|
6
|
+
*
|
|
7
|
+
* Failures are logged at `warn` (a persistently-closed writer is
|
|
8
|
+
* the most likely culprit when events go missing client-side) but
|
|
9
|
+
* swallowed so a cancelled request or a client that navigated
|
|
10
|
+
* away can't crash a tool mid-flight.
|
|
11
|
+
*/
|
|
12
|
+
import { commonUtils } from "@dbx-tools/shared";
|
|
13
|
+
/**
|
|
14
|
+
* Best-effort `writer.write`. No-op when `writer` is undefined;
|
|
15
|
+
* caught errors are logged via `log.warn("writer:error", ...)`
|
|
16
|
+
* along with any caller-supplied `context` fields (e.g. a
|
|
17
|
+
* `chartId` or `messageId`) so the warning is greppable per
|
|
18
|
+
* resource.
|
|
19
|
+
*
|
|
20
|
+
* Returns when the write resolves or rejects; never throws.
|
|
21
|
+
*/
|
|
22
|
+
export async function safeWrite(log, writer, chunk, context = {}) {
|
|
23
|
+
if (!writer) {
|
|
24
|
+
log.debug("writer:no-writer", context);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
await writer.write(chunk);
|
|
29
|
+
log.debug("writer:ok", context);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
log.warn("writer:error", {
|
|
33
|
+
...context,
|
|
34
|
+
error: commonUtils.errorMessage(err),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|