@dbx-tools/appkit-mastra 0.9.153 → 0.9.157

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 (76) hide show
  1. package/README.md +4 -3
  2. package/index.ts +32 -24
  3. package/lib/index.d.ts +32 -24
  4. package/lib/index.js +32 -23
  5. package/lib/src/agents.d.ts +5 -6
  6. package/lib/src/agents.js +12 -15
  7. package/lib/src/chart.js +33 -33
  8. package/lib/src/chat.js +10 -13
  9. package/lib/src/config.d.ts +12 -13
  10. package/lib/src/config.js +4 -4
  11. package/lib/src/evaluation.js +7 -9
  12. package/lib/src/feedback-mode.d.ts +1 -1
  13. package/lib/src/feedback-mode.js +1 -1
  14. package/lib/src/filesystems.js +6 -6
  15. package/lib/src/follow-up-suggestions.js +10 -10
  16. package/lib/src/genie-chat.js +27 -29
  17. package/lib/src/genie.d.ts +2 -2
  18. package/lib/src/genie.js +29 -29
  19. package/lib/src/identity.d.ts +3 -30
  20. package/lib/src/identity.js +2 -27
  21. package/lib/src/memory.d.ts +1 -1
  22. package/lib/src/memory.js +24 -6
  23. package/lib/src/mlflow.d.ts +4 -4
  24. package/lib/src/mlflow.js +15 -18
  25. package/lib/src/model.d.ts +3 -3
  26. package/lib/src/model.js +6 -6
  27. package/lib/src/monty-sandbox.js +8 -8
  28. package/lib/src/observability.d.ts +6 -5
  29. package/lib/src/observability.js +8 -6
  30. package/lib/src/plugin.d.ts +1 -1
  31. package/lib/src/plugin.js +49 -51
  32. package/lib/src/remote-skills.d.ts +3 -4
  33. package/lib/src/remote-skills.js +46 -46
  34. package/lib/src/rest.d.ts +2 -2
  35. package/lib/src/rest.js +3 -3
  36. package/lib/src/server.js +17 -20
  37. package/lib/src/serving.js +10 -11
  38. package/lib/src/statement.js +7 -7
  39. package/lib/src/storage-schema.js +4 -4
  40. package/lib/src/summarize.js +5 -5
  41. package/lib/src/telemetry.d.ts +0 -6
  42. package/lib/src/telemetry.js +34 -41
  43. package/lib/src/validation.js +3 -4
  44. package/lib/src/workspaces.d.ts +2 -2
  45. package/lib/src/workspaces.js +34 -36
  46. package/lib/src/writer.d.ts +2 -2
  47. package/lib/src/writer.js +3 -3
  48. package/package.json +17 -305
  49. package/src/agents.ts +27 -21
  50. package/src/chart.ts +43 -37
  51. package/src/chat.ts +10 -12
  52. package/src/config.ts +14 -15
  53. package/src/evaluation.ts +6 -8
  54. package/src/feedback-mode.ts +1 -1
  55. package/src/filesystems.ts +5 -5
  56. package/src/follow-up-suggestions.ts +9 -9
  57. package/src/genie-chat.ts +32 -31
  58. package/src/genie.ts +29 -29
  59. package/src/identity.ts +3 -38
  60. package/src/memory.ts +24 -6
  61. package/src/mlflow.ts +21 -21
  62. package/src/model.ts +7 -7
  63. package/src/monty-sandbox.ts +7 -7
  64. package/src/observability.ts +8 -6
  65. package/src/plugin.ts +78 -65
  66. package/src/remote-skills.ts +63 -55
  67. package/src/rest.ts +4 -4
  68. package/src/server.ts +32 -20
  69. package/src/serving.ts +14 -11
  70. package/src/statement.ts +10 -6
  71. package/src/storage-schema.ts +3 -3
  72. package/src/summarize.ts +4 -4
  73. package/src/telemetry.ts +49 -55
  74. package/src/validation.ts +2 -3
  75. package/src/workspaces.ts +52 -42
  76. package/src/writer.ts +3 -3
package/src/telemetry.ts CHANGED
@@ -20,10 +20,25 @@
20
20
 
21
21
  import { StringDecoder } from "node:string_decoder";
22
22
 
23
- import { telemetry as appkitTelemetry } from "@dbx-tools/appkit";
24
- import { getRequestTags } from "@dbx-tools/appkit/request-tags";
25
- import { environmentUtils, json, log, object, stringUtils } from "@dbx-tools/shared-core";
26
- import { feedback, thread } from "@dbx-tools/shared-mastra";
23
+ import {
24
+ USER_TRACE_ATTRIBUTE,
25
+ registerNativeSpanProcessor,
26
+ getRequestTags,
27
+ } from "@dbx-tools/appkit";
28
+ import {
29
+ log,
30
+ isDatabricksAppEnv,
31
+ parse,
32
+ isRecord,
33
+ trimToNull,
34
+ USER_EMAIL_HEADER,
35
+ USER_ID_HEADER,
36
+ } from "@dbx-tools/shared-core";
37
+ import {
38
+ MLFLOW_TRACE_ID_HEADER,
39
+ THREAD_ID_HEADER,
40
+ THREAD_ID_QUERY,
41
+ } from "@dbx-tools/shared-mastra";
27
42
  import type { TracingOptions } from "@mastra/core/observability";
28
43
  import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
29
44
  import {
@@ -40,7 +55,6 @@ import type { ReadableSpan, Span as SdkSpan, SpanProcessor } from "@opentelemetr
40
55
  import type express from "express";
41
56
 
42
57
  import { MASTRA_AUTH_MODE_KEY, MASTRA_USER_EMAIL_KEY, MASTRA_USER_NAME_KEY } from "./config.ts";
43
- import { USER_EMAIL_HEADER, USER_ID_HEADER } from "./identity.ts";
44
58
  import {
45
59
  appMlflowTraceInfoConfigured,
46
60
  directMlflowTracingActive,
@@ -61,21 +75,6 @@ import {
61
75
  MLFLOW_TRACE_TAG_PREFIX,
62
76
  } from "./trace-attributes.ts";
63
77
 
64
- export {
65
- MLFLOW_AGENT_TAG,
66
- MLFLOW_AGENT_TAG_ATTR,
67
- APPKIT_AGENT_TRACE_ROOT_ATTR,
68
- MLFLOW_GENIE_TAG,
69
- MLFLOW_GENIE_TAG_ATTR,
70
- MLFLOW_LOCAL_TAG,
71
- MLFLOW_LOCAL_TAG_ATTR,
72
- MLFLOW_OBO_AUTH_TAG,
73
- MLFLOW_OBO_AUTH_TAG_ATTR,
74
- MLFLOW_SP_AUTH_TAG,
75
- MLFLOW_SP_AUTH_TAG_ATTR,
76
- MLFLOW_TRACE_TAG_PREFIX,
77
- } from "./trace-attributes.ts";
78
-
79
78
  const logger = log.logger("mastra/telemetry");
80
79
 
81
80
  /** Cap on each payload copied onto a span, so one turn cannot bloat the export. */
@@ -85,7 +84,7 @@ export const TRACE_IO_LIMIT = 8_000;
85
84
  const RESPONSE_BODY_LIMIT = TRACE_IO_LIMIT * 4;
86
85
 
87
86
  /** Tracer scope used only when AppKit did not create a recording HTTP span. */
88
- const CHAT_TURN_TRACER = "@dbx-tools/appkit-mastra/telemetry";
87
+ const CHAT_TURN_TRACER = "@dbx-tools/appkit-mastra";
89
88
 
90
89
  /**
91
90
  * Mount-relative Mastra agent invoke paths that carry a chat turn body
@@ -115,11 +114,6 @@ export const CHAT_GENIE_USED_ATTR = "appkit.mastra.genie.used";
115
114
  export const MLFLOW_SPAN_TYPE_ATTR = "mlflow.spanType";
116
115
  /** GenAI semantic-convention operation name, an alternate span-type source. */
117
116
  export const GEN_AI_OPERATION_NAME_ATTR = "gen_ai.operation.name";
118
- /**
119
- * Root-span user id the MLflow experiment UI's User column reads from OTel
120
- * traces. Prefer the forwarded email when present so the column is human.
121
- */
122
- export const MLFLOW_USER_ATTR = appkitTelemetry.USER_TRACE_ATTRIBUTE;
123
117
  /** Root-span session id that enables the MLflow Sessions tab. */
124
118
  export const MLFLOW_SESSION_ATTR = "session.id";
125
119
  /** Root-span type for a Mastra agent turn. */
@@ -170,25 +164,23 @@ export function stampGenieToolSpan(span: Span | undefined = trace.getActiveSpan(
170
164
  }
171
165
 
172
166
  function requestHeader(req: express.Request, name: string): string | undefined {
173
- const fromMethod =
174
- typeof req.header === "function" ? stringUtils.trimToNull(req.header(name)) : undefined;
167
+ const fromMethod = typeof req.header === "function" ? trimToNull(req.header(name)) : undefined;
175
168
  if (fromMethod) return fromMethod;
176
169
  const raw = req.headers?.[name.toLowerCase()];
177
170
  const value = Array.isArray(raw) ? raw[0] : raw;
178
- return stringUtils.trimToNull(typeof value === "string" ? value : undefined) ?? undefined;
171
+ return trimToNull(typeof value === "string" ? value : undefined) ?? undefined;
179
172
  }
180
173
 
181
174
  function requestQuery(req: express.Request, name: string): string | undefined {
182
175
  const raw = req.query?.[name];
183
176
  const value = Array.isArray(raw) ? raw[0] : raw;
184
- return stringUtils.trimToNull(typeof value === "string" ? value : undefined) ?? undefined;
177
+ return trimToNull(typeof value === "string" ? value : undefined) ?? undefined;
185
178
  }
186
179
 
187
180
  function stampMlflowActor(span: Span, req: express.Request): string | undefined {
188
181
  const user = requestHeader(req, USER_EMAIL_HEADER) ?? requestHeader(req, USER_ID_HEADER);
189
- if (user) span.setAttribute(MLFLOW_USER_ATTR, user);
190
- const session =
191
- requestHeader(req, thread.THREAD_ID_HEADER) ?? requestQuery(req, thread.THREAD_ID_QUERY);
182
+ if (user) span.setAttribute(USER_TRACE_ATTRIBUTE, user);
183
+ const session = requestHeader(req, THREAD_ID_HEADER) ?? requestQuery(req, THREAD_ID_QUERY);
192
184
  if (session) span.setAttribute(MLFLOW_SESSION_ATTR, session);
193
185
  return user;
194
186
  }
@@ -223,7 +215,7 @@ export function activeChatTracingOptions(
223
215
  }
224
216
 
225
217
  function setChatTraceTag(state: ChatTraceState, name: string, value: ChatTraceTagValue): void {
226
- const tag = stringUtils.trimToNull(name);
218
+ const tag = trimToNull(name);
227
219
  if (!tag) return;
228
220
  state.tags.set(tag, String(value));
229
221
  }
@@ -247,7 +239,7 @@ export function recordActiveTraceTags(
247
239
 
248
240
  /** Record the first selected model as the active chat trace's `agent` tag. */
249
241
  export function recordActiveTraceModel(modelId: string): void {
250
- const value = stringUtils.trimToNull(modelId);
242
+ const value = trimToNull(modelId);
251
243
  if (!value) return;
252
244
  const state = activeChatTraceState();
253
245
  if (!state || state.firstModel) return;
@@ -260,7 +252,7 @@ export function recordActiveTraceModel(modelId: string): void {
260
252
 
261
253
  /** Record the best resolved user identifier on the active chat trace. */
262
254
  export function recordActiveTraceUser(user: string | undefined): void {
263
- const value = stringUtils.trimToNull(user);
255
+ const value = trimToNull(user);
264
256
  if (!value) return;
265
257
  const state = activeChatTraceState();
266
258
  if (state) state.user = value;
@@ -275,7 +267,7 @@ export function recordActiveTraceAuth(auth: "obo" | "service-principal"): void {
275
267
  function stampMlflowTraceId(res: express.Response, traceId: string): void {
276
268
  if (res.headersSent) return;
277
269
  if (!traceId || traceId === INVALID_TRACE_ID) return;
278
- res.setHeader(feedback.MLFLOW_TRACE_ID_HEADER, `tr-${traceId}`);
270
+ res.setHeader(MLFLOW_TRACE_ID_HEADER, `tr-${traceId}`);
279
271
  }
280
272
 
281
273
  /** Return one raw prompt when the request is exactly one text-only user message. */
@@ -283,7 +275,7 @@ export function textOnlyChatInput(messages: unknown): string | undefined {
283
275
  if (typeof messages === "string") return messages || undefined;
284
276
  if (!Array.isArray(messages) || messages.length !== 1) return undefined;
285
277
  const message = messages[0];
286
- if (!object.isRecord(message) || message.role !== "user") return undefined;
278
+ if (!isRecord(message) || message.role !== "user") return undefined;
287
279
  if (typeof message.content === "string") return message.content || undefined;
288
280
  return textFromParts(message.parts) ?? textFromParts(message.content);
289
281
  }
@@ -292,7 +284,7 @@ function textFromParts(value: unknown): string | undefined {
292
284
  if (!Array.isArray(value) || value.length === 0) return undefined;
293
285
  const text: string[] = [];
294
286
  for (const part of value) {
295
- if (!object.isRecord(part) || part.type !== "text" || typeof part.text !== "string") {
287
+ if (!isRecord(part) || part.type !== "text" || typeof part.text !== "string") {
296
288
  return undefined;
297
289
  }
298
290
  text.push(part.text);
@@ -307,13 +299,13 @@ function serialized(value: unknown, limit = TRACE_IO_LIMIT): string {
307
299
 
308
300
  function sseFrame(line: string): unknown {
309
301
  if (!line.startsWith("data:")) return undefined;
310
- return json.parse(line.slice(5));
302
+ return parse(line.slice(5));
311
303
  }
312
304
 
313
305
  function valueUsesGenie(value: unknown, depth = 0): boolean {
314
306
  if (depth > 3) return false;
315
307
  if (Array.isArray(value)) return value.some((item) => valueUsesGenie(item, depth + 1));
316
- if (!object.isRecord(value)) return false;
308
+ if (!isRecord(value)) return false;
317
309
  if (
318
310
  value.type === "data-genie-progress" ||
319
311
  value.type === "ask_genie_done" ||
@@ -332,11 +324,11 @@ function assistantTextFromSseLine(line: string): string {
332
324
  }
333
325
 
334
326
  function assistantTextFromSseFrame(frame: unknown): string {
335
- if (!object.isRecord(frame) || frame.type !== "text-delta") return "";
327
+ if (!isRecord(frame) || frame.type !== "text-delta") return "";
336
328
  const text =
337
329
  typeof frame.delta === "string"
338
330
  ? frame.delta
339
- : object.isRecord(frame.payload)
331
+ : isRecord(frame.payload)
340
332
  ? frame.payload.text
341
333
  : undefined;
342
334
  return typeof text === "string" ? text : "";
@@ -361,7 +353,7 @@ export function assistantTextFromSse(body: string): string {
361
353
 
362
354
  /** Read the final assistant text from a non-streaming Mastra response. */
363
355
  export function assistantTextFromJson(body: unknown): string {
364
- if (!object.isRecord(body) || typeof body.text !== "string") return "";
356
+ if (!isRecord(body) || typeof body.text !== "string") return "";
365
357
  return body.text.slice(0, TRACE_IO_LIMIT);
366
358
  }
367
359
 
@@ -381,7 +373,7 @@ interface AppMlflowTraceState {
381
373
 
382
374
  function attributeString(span: ReadableSpan, name: string): string | undefined {
383
375
  const value = span.attributes[name];
384
- return typeof value === "string" ? (stringUtils.trimToNull(value) ?? undefined) : undefined;
376
+ return typeof value === "string" ? (trimToNull(value) ?? undefined) : undefined;
385
377
  }
386
378
 
387
379
  function metadataAttribute(key: string): string {
@@ -391,9 +383,9 @@ function metadataAttribute(key: string): string {
391
383
  function modelFromSpan(span: ReadableSpan): string | undefined {
392
384
  const direct = attributeString(span, GEN_AI_REQUEST_MODEL_ATTR);
393
385
  if (direct) return direct;
394
- const metadata = json.parse(attributeString(span, MASTRA_MODEL_METADATA_ATTR));
395
- return object.isRecord(metadata) && typeof metadata.modelId === "string"
396
- ? (stringUtils.trimToNull(metadata.modelId) ?? undefined)
386
+ const metadata = parse(attributeString(span, MASTRA_MODEL_METADATA_ATTR));
387
+ return isRecord(metadata) && typeof metadata.modelId === "string"
388
+ ? (trimToNull(metadata.modelId) ?? undefined)
397
389
  : undefined;
398
390
  }
399
391
 
@@ -425,13 +417,13 @@ function hrTimeMilliseconds(value: readonly [number, number]): number {
425
417
  function previewInput(span: ReadableSpan): string | undefined {
426
418
  const raw = attributeString(span, MASTRA_AGENT_INPUT_ATTR);
427
419
  if (!raw) return undefined;
428
- return (textOnlyChatInput(json.parse(raw)) ?? raw).slice(0, TRACE_IO_LIMIT);
420
+ return (textOnlyChatInput(parse(raw)) ?? raw).slice(0, TRACE_IO_LIMIT);
429
421
  }
430
422
 
431
423
  function previewOutput(span: ReadableSpan): string | undefined {
432
424
  const raw = attributeString(span, MASTRA_AGENT_OUTPUT_ATTR);
433
425
  if (!raw) return undefined;
434
- const parsed = json.parse(raw);
426
+ const parsed = parse(raw);
435
427
  const text = assistantTextFromJson(parsed) || (typeof parsed === "string" ? parsed : raw);
436
428
  return text.slice(0, TRACE_IO_LIMIT);
437
429
  }
@@ -510,7 +502,7 @@ export async function registerAppMlflowTraceInfoProcessor(): Promise<boolean> {
510
502
  if (appMlflowTraceInfoProcessorRegistered) return true;
511
503
  if (!appMlflowTraceInfoConfigured()) return false;
512
504
  await initializeAppMlflowTraceInfo();
513
- await appkitTelemetry.registerNativeSpanProcessor(new AppMlflowTraceInfoSpanProcessor());
505
+ await registerNativeSpanProcessor(new AppMlflowTraceInfoSpanProcessor());
514
506
  appMlflowTraceInfoProcessorRegistered = true;
515
507
  return true;
516
508
  }
@@ -580,7 +572,7 @@ class AssistantResponseCollector {
580
572
  }
581
573
 
582
574
  private jsonAnswer(): string {
583
- return assistantTextFromJson(json.parse(this.body));
575
+ return assistantTextFromJson(parse(this.body));
584
576
  }
585
577
  }
586
578
 
@@ -677,7 +669,7 @@ export function chatTurnTelemetryMiddleware(
677
669
  parentSpanId: target.span.spanContext().spanId,
678
670
  };
679
671
  const traceRequestTime = Date.now();
680
- if (!environmentUtils.isDatabricksAppEnv()) {
672
+ if (!isDatabricksAppEnv()) {
681
673
  setChatTraceTag(traceState, MLFLOW_LOCAL_TAG, true);
682
674
  }
683
675
  for (const [name, value] of Object.entries(getRequestTags(req))) {
@@ -752,14 +744,16 @@ export function chatTurnTelemetryMiddleware(
752
744
  for (const [name, value] of traceState.tags) {
753
745
  target.span.setAttribute(`${MLFLOW_TRACE_TAG_PREFIX}${name}`, value);
754
746
  }
755
- if (traceState.user) target.span.setAttribute(MLFLOW_USER_ATTR, traceState.user);
747
+ if (traceState.user) {
748
+ target.span.setAttribute(USER_TRACE_ATTRIBUTE, traceState.user);
749
+ }
756
750
  context.with(trace.setSpan(context.active(), target.span), () => {
757
751
  updateActiveMlflowTrace({
758
752
  ...(Object.keys(tags).length > 0 ? { tags } : {}),
759
753
  ...(traceState.user ? { user: traceState.user } : {}),
760
754
  });
761
755
  });
762
- if (!environmentUtils.isDatabricksAppEnv()) {
756
+ if (!isDatabricksAppEnv()) {
763
757
  persistAppMlflowTraceInfo({
764
758
  traceId: traceState.traceId,
765
759
  requestTime: traceRequestTime,
package/src/validation.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * @module
11
11
  */
12
- import { object } from "@dbx-tools/shared-core";
12
+ import { sequence } from "@dbx-tools/shared-core";
13
13
 
14
14
  /** The subset of a failed parse result these helpers read. */
15
15
  export interface SchemaIssues {
@@ -19,8 +19,7 @@ export interface SchemaIssues {
19
19
  /** Distinct dot-joined field paths a failed parse flagged. */
20
20
  export function invalidFields(error: SchemaIssues): string[] {
21
21
  return [
22
- ...object
23
- .sequence(error.issues)
22
+ ...sequence(error.issues)
24
23
  .map((issue) => issue.path.map(String).join("."))
25
24
  .filter(Boolean)
26
25
  .distinct(),
package/src/workspaces.ts CHANGED
@@ -16,16 +16,27 @@ import { createHash } from "node:crypto";
16
16
  import { tmpdir } from "node:os";
17
17
  import { join } from "node:path";
18
18
  import type { WorkspaceClient } from "@databricks/appkit";
19
- import { appkit, pluginRegistry } from "@dbx-tools/appkit";
20
19
  import {
21
- filesCache as filesCachePlugin,
20
+ tryGetExecutionContext,
21
+ type PluginContextLike,
22
+ instance,
22
23
  type FilesCacheExports,
23
24
  type FilesCacheScope,
24
- } from "@dbx-tools/appkit/files-cache";
25
- import { DatabricksFileSystem, workspaceClient } from "@dbx-tools/databricks";
25
+ filesCache as filesCachePlugin,
26
+ } from "@dbx-tools/appkit";
27
+ import { DatabricksFileSystem, toLegacyWorkspaceClient } from "@dbx-tools/databricks";
26
28
  import { LocalFileSystem } from "@dbx-tools/fs";
27
- import { find, match, type PathMatchInput } from "@dbx-tools/path";
28
- import { errorUtils, log, object, stringUtils, token } from "@dbx-tools/shared-core";
29
+ import { type PathMatchInput, findFiles, toPathMatcher } from "@dbx-tools/path";
30
+ import {
31
+ log,
32
+ toError,
33
+ toStableKey,
34
+ isRecord,
35
+ trimToNull,
36
+ toSlug,
37
+ tokenize,
38
+ includesAccessTokenScope,
39
+ } from "@dbx-tools/shared-core";
29
40
  import {
30
41
  fs as sharedFS,
31
42
  posixPath,
@@ -34,6 +45,11 @@ import {
34
45
  type FileSystemCache,
35
46
  type FileSystemCacheOptions,
36
47
  MemoryFileSystem,
48
+ isAbsolute,
49
+ normalize,
50
+ normalizeRoot,
51
+ isWithinRoot,
52
+ basename,
37
53
  } from "@dbx-tools/shared-fs";
38
54
  import type { RequestContext } from "@mastra/core/request-context";
39
55
  import { createSkill, validateSkillContent, type InlineSkill } from "@mastra/core/skills";
@@ -200,7 +216,7 @@ export interface DatabricksWorkspaceOptions extends Omit<
200
216
  /** Filesystem cache filters. Ignored when the AppKit files-cache plugin is absent. */
201
217
  cache?: DatabricksWorkspaceCache;
202
218
  /** AppKit plugin context used to discover optional sibling capabilities. */
203
- pluginContext?: pluginRegistry.PluginContextLike;
219
+ pluginContext?: PluginContextLike;
204
220
  /**
205
221
  * Command sandbox. Defaults to Monty. Pass `false` to disable it, or an
206
222
  * explicit Mastra sandbox/provider resolver for a remote transport.
@@ -269,7 +285,7 @@ export function databricksWorkspaceConfig(
269
285
  const paths = resolveDatabricksWorkspacePaths(options);
270
286
  const configuredPaths = paths.length;
271
287
  const extraSkillMounts = options.extraSkillMounts ?? [];
272
- const filesCache = pluginRegistry.instance(options.pluginContext, filesCachePlugin)?.exports();
288
+ const filesCache = instance(options.pluginContext, filesCachePlugin)?.exports();
273
289
  const configuredCache = options.cache;
274
290
  const mountFilesCache = configuredCache === false ? undefined : filesCache;
275
291
  const retainFilesystemSource =
@@ -369,7 +385,7 @@ export function databricksWorkspace(options: DatabricksWorkspaceOptions = {}): W
369
385
  /** @internal Bind a caller-created Databricks workspace to its AppKit plugin context. */
370
386
  export function bindDatabricksWorkspaceContext(
371
387
  workspace: Workspace,
372
- pluginContext: pluginRegistry.PluginContextLike | undefined,
388
+ pluginContext: PluginContextLike | undefined,
373
389
  excludeSkillNames: readonly string[] = [],
374
390
  ): Workspace {
375
391
  const options = databricksWorkspaceOptions.get(workspace);
@@ -447,10 +463,7 @@ function sandboxName(selection: WorkspaceSandboxSelection | undefined): string {
447
463
  * file API access (`workspace` or `all-apis` on {@link MASTRA_SCOPES_KEY}).
448
464
  */
449
465
  function hasWorkspaceFileScope(requestContext: RequestContext | undefined): boolean {
450
- return token.includesAccessTokenScope(
451
- requestContext?.get(MASTRA_SCOPES_KEY),
452
- WORKSPACE_FILE_SCOPES,
453
- );
466
+ return includesAccessTokenScope(requestContext?.get(MASTRA_SCOPES_KEY), WORKSPACE_FILE_SCOPES);
454
467
  }
455
468
 
456
469
  /** Resolve the request client and authorization-safe files-cache scope. */
@@ -479,19 +492,19 @@ async function resolveFilesCacheScope(context: DatabricksWorkspaceContext): Prom
479
492
 
480
493
  /** Join one relative skill path to its actual composite mount path. */
481
494
  function mountedSkillPath(mount: string, skillPath: string): string {
482
- if (posixPath.isAbsolute(skillPath)) {
495
+ if (isAbsolute(skillPath)) {
483
496
  throw new TypeError(`Skill path must be relative to its mount: ${skillPath}`);
484
497
  }
485
- const normalized = posixPath.normalize(skillPath);
498
+ const normalized = normalize(skillPath);
486
499
  if (!normalized.ok) {
487
500
  throw new TypeError(`Skill path escapes its mount: ${skillPath}`);
488
501
  }
489
- return posixPath.join(posixPath.normalizeRoot(mount), normalized.path.slice(1));
502
+ return posixPath.join(normalizeRoot(mount), normalized.path.slice(1));
490
503
  }
491
504
 
492
505
  /** Return whether a Databricks path belongs to the writable Workspace namespace. */
493
506
  function isWorkspaceRoot(root: string): boolean {
494
- const normalized = posixPath.normalizeRoot(root);
507
+ const normalized = normalizeRoot(root);
495
508
  return normalized === "/Workspace" || normalized.startsWith("/Workspace/");
496
509
  }
497
510
 
@@ -522,7 +535,7 @@ async function resolveWorkspacePathMounts(
522
535
  for (const [index, path] of paths.entries()) {
523
536
  const configured = await resolveDatabricksWorkspacePath(path, context);
524
537
  if (!configured) continue;
525
- if (posixPath.isWithinRoot(SCRATCH_MOUNT, configured.path)) {
538
+ if (isWithinRoot(SCRATCH_MOUNT, configured.path)) {
526
539
  const mount = configured.mount ?? configured.path;
527
540
  mounts[mount] = userTempFilesystem(context, configured.path);
528
541
  hasWritableMount = true;
@@ -622,7 +635,7 @@ async function resolveSkillFolderFilesystem(
622
635
  });
623
636
  return undefined;
624
637
  }
625
- const root = stringUtils.trimToNull(folder.path);
638
+ const root = trimToNull(folder.path);
626
639
  if (!root) return undefined;
627
640
  const writable = folder.writable ?? isWorkspaceRoot(root);
628
641
  const cacheOptions = cache.fileSystemCache
@@ -660,10 +673,10 @@ function resolveHomePath(
660
673
  input: string | undefined,
661
674
  requestContext: Record<string, unknown>,
662
675
  ): string | undefined {
663
- const value = stringUtils.trimToNull(input);
676
+ const value = trimToNull(input);
664
677
  if (!value || (value !== "~" && !value.startsWith("~/"))) return value ?? undefined;
665
678
  const emailValue = requestContext[MASTRA_USER_EMAIL_KEY];
666
- const email = typeof emailValue === "string" ? stringUtils.trimToNull(emailValue) : undefined;
679
+ const email = typeof emailValue === "string" ? trimToNull(emailValue) : undefined;
667
680
  if (!email) return undefined;
668
681
  const home = personalWorkspacePath(email);
669
682
  return value === "~" ? home : `${home}/${value.slice(2)}`;
@@ -693,12 +706,12 @@ function cacheFilterMatches(
693
706
  const expanded = resolveHomePath(input, requestContext);
694
707
  if (!expanded) continue;
695
708
  inputs.push(
696
- !root || posixPath.isAbsolute(expanded) || expanded.startsWith("**")
709
+ !root || isAbsolute(expanded) || expanded.startsWith("**")
697
710
  ? expanded
698
- : `${posixPath.normalizeRoot(root)}/${expanded.replace(/^\.\//, "")}`,
711
+ : `${normalizeRoot(root)}/${expanded.replace(/^\.\//, "")}`,
699
712
  );
700
713
  }
701
- return inputs.length > 0 && match.toPathMatcher(...inputs)(path);
714
+ return inputs.length > 0 && toPathMatcher(...inputs)(path);
702
715
  }
703
716
 
704
717
  async function resolveFileCacheOptions(
@@ -715,8 +728,7 @@ async function resolveFileCacheOptions(
715
728
  return {
716
729
  operations: CACHEABLE_FILESYSTEM_OPERATIONS,
717
730
  filter: (operation, path) =>
718
- operation !== "readFile" ||
719
- roots.some((skillRoot) => posixPath.isWithinRoot(skillRoot, path)),
731
+ operation !== "readFile" || roots.some((skillRoot) => isWithinRoot(skillRoot, path)),
720
732
  };
721
733
  }
722
734
  const policies = toPolicyArray(resolved);
@@ -746,10 +758,10 @@ function resolveWorkspaceIdentity(options: DatabricksWorkspaceOptions): {
746
758
  let id = options.id;
747
759
  let name = options.name;
748
760
  if (!id) {
749
- id = name ? stringUtils.toSlug(name) : "workspace";
761
+ id = name ? toSlug(name) : "workspace";
750
762
  }
751
763
  if (!name) {
752
- name = Array.from(stringUtils.tokenize(id)).join(" ");
764
+ name = Array.from(tokenize(id)).join(" ");
753
765
  }
754
766
  return { id, name };
755
767
  }
@@ -788,10 +800,10 @@ function userTempFilesystem(
788
800
  ): WorkspaceFilesystem {
789
801
  const userKey = resolveUserKey(context.requestContext);
790
802
  const digest = createHash("sha256")
791
- .update(object.toStableKey({ package: "@dbx-tools/appkit-mastra", userKey }))
803
+ .update(toStableKey({ package: "@dbx-tools/appkit-mastra", userKey }))
792
804
  .digest("hex")
793
805
  .slice(0, 16);
794
- const normalized = posixPath.normalizeRoot(workspacePath);
806
+ const normalized = normalizeRoot(workspacePath);
795
807
  const relative = normalized === SCRATCH_MOUNT ? "" : normalized.slice(`${SCRATCH_MOUNT}/`.length);
796
808
  const source = new LocalFileSystem({
797
809
  root: join(tmpdir(), "dbx-tools", "mastra", digest, relative),
@@ -814,7 +826,7 @@ function localSkillMountResolvers(mounts: readonly LocalSkillMount[]): Workspace
814
826
  unique.set(`${entry.mountPath}\0${identity}`, entry);
815
827
  }
816
828
  return [...unique.values()].map((entry) => {
817
- const mount = posixPath.normalizeRoot(entry.mountPath);
829
+ const mount = normalizeRoot(entry.mountPath);
818
830
  const filesystem = inMemorySkillFilesystem(entry);
819
831
  return async () => {
820
832
  const source = await filesystem;
@@ -866,7 +878,7 @@ export async function inlineSkillsFromLocalMounts(
866
878
  ...(metadata.compatibility !== undefined
867
879
  ? { compatibility: metadata.compatibility }
868
880
  : {}),
869
- ...(object.isRecord(metadata.metadata) ? { metadata: metadata.metadata } : {}),
881
+ ...(isRecord(metadata.metadata) ? { metadata: metadata.metadata } : {}),
870
882
  ...(Object.keys(references).length > 0 ? { references } : {}),
871
883
  }),
872
884
  );
@@ -903,7 +915,7 @@ async function loadInMemorySkillFilesystem(mount: LocalSkillMount): Promise<File
903
915
  root: "/",
904
916
  });
905
917
  await memory.init();
906
- for await (const relative of find.findFiles("**/*", { cwd: mount.root, nodir: true })) {
918
+ for await (const relative of findFiles("**/*", { cwd: mount.root, nodir: true })) {
907
919
  await memory.writeFile(relative, await source.readFile(relative), { overwrite: true });
908
920
  }
909
921
  await source.close();
@@ -941,7 +953,7 @@ async function databricksFilesystem(
941
953
  | undefined
942
954
  > {
943
955
  const fs = new DatabricksFileSystem({
944
- client: () => workspaceClient.toLegacyWorkspaceClient(requestWorkspaceClient(client)),
956
+ client: () => toLegacyWorkspaceClient(requestWorkspaceClient(client)),
945
957
  root,
946
958
  readOnly,
947
959
  createRoot,
@@ -959,7 +971,7 @@ async function databricksFilesystem(
959
971
  logger.debug("databricks-mount:skipped", {
960
972
  root,
961
973
  readOnly,
962
- error: errorUtils.toError(err),
974
+ error: toError(err),
963
975
  });
964
976
  }
965
977
  return undefined;
@@ -968,9 +980,7 @@ async function databricksFilesystem(
968
980
  /** @internal Keep service context from replacing the request-scoped workspace client. */
969
981
  export function requestWorkspaceClient(
970
982
  initialClient: WorkspaceClient,
971
- executionContext: ReturnType<
972
- typeof appkit.tryGetExecutionContext
973
- > = appkit.tryGetExecutionContext(),
983
+ executionContext: ReturnType<typeof tryGetExecutionContext> = tryGetExecutionContext(),
974
984
  ): WorkspaceClient {
975
985
  if (
976
986
  executionContext &&
@@ -1008,7 +1018,7 @@ function verifyFirstFileSystemAccess<TFileSystem extends FileSystem>(
1008
1018
  readCheck = undefined;
1009
1019
  logger.debug("databricks-mount:read-check-failed", {
1010
1020
  root,
1011
- error: errorUtils.toError(error),
1021
+ error: toError(error),
1012
1022
  });
1013
1023
  throw error;
1014
1024
  }
@@ -1039,7 +1049,7 @@ function verifyFirstFileSystemAccess<TFileSystem extends FileSystem>(
1039
1049
  if (!writeVerified) {
1040
1050
  logger.debug("databricks-mount:write-check-failed", {
1041
1051
  root,
1042
- error: errorUtils.toError(error),
1052
+ error: toError(error),
1043
1053
  });
1044
1054
  }
1045
1055
  throw error;
@@ -1132,7 +1142,7 @@ async function resolveDistinctSkillPaths(
1132
1142
  try {
1133
1143
  const entries = await filesystem.readdir(path);
1134
1144
  if (entries.some((entry) => entry.type === "file" && entry.name === "SKILL.md")) {
1135
- const name = posixPath.basename(path);
1145
+ const name = basename(path);
1136
1146
  if (!excludedSkillNames.has(name) && !selected.has(name)) selected.set(name, path);
1137
1147
  continue;
1138
1148
  }
@@ -1149,7 +1159,7 @@ async function resolveDistinctSkillPaths(
1149
1159
  } catch (error) {
1150
1160
  logger.debug("skill-path:skipped", {
1151
1161
  path,
1152
- error: errorUtils.toError(error),
1162
+ error: toError(error),
1153
1163
  });
1154
1164
  }
1155
1165
  }
package/src/writer.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  * @module
11
11
  */
12
12
 
13
- import { errorUtils, log } from "@dbx-tools/shared-core";
13
+ import { toError, type Logger } from "@dbx-tools/shared-core";
14
14
  import { GENIE_PROGRESS_PART_TYPE, type GenieWriterEvent } from "@dbx-tools/shared-mastra";
15
15
  import type { ToolExecutionContext } from "@mastra/core/tools";
16
16
 
@@ -25,7 +25,7 @@ import type { ToolExecutionContext } from "@mastra/core/tools";
25
25
  * Returns when the write resolves or rejects; never throws.
26
26
  */
27
27
  export async function safeWriteProgress(
28
- log: log.Logger,
28
+ log: Logger,
29
29
  writer: ToolExecutionContext["writer"],
30
30
  toolCallId: string | undefined,
31
31
  event: GenieWriterEvent,
@@ -44,7 +44,7 @@ export async function safeWriteProgress(
44
44
  } catch (err) {
45
45
  log.warn("writer:error", {
46
46
  ...context,
47
- error: errorUtils.toError(err),
47
+ error: toError(err),
48
48
  });
49
49
  }
50
50
  }