@dbx-tools/appkit-mastra 0.6.14 → 0.6.27
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 +160 -20
- package/index.ts +8 -3
- package/lib/index.d.ts +8 -3
- package/lib/index.js +7 -2
- package/lib/src/chart.d.ts +39 -9
- package/lib/src/chart.js +460 -77
- package/lib/src/genie.js +24 -24
- package/lib/src/mlflow.d.ts +3 -1
- package/lib/src/mlflow.js +4 -2
- package/lib/src/observability.d.ts +9 -0
- package/lib/src/observability.js +17 -1
- package/lib/src/plugin.js +35 -2
- package/lib/src/remote-skills.js +10 -10
- package/lib/src/skill-paths.d.ts +15 -0
- package/lib/src/skill-paths.js +18 -0
- package/lib/src/trace-io.d.ts +53 -0
- package/lib/src/trace-io.js +117 -0
- package/lib/src/workspaces.d.ts +85 -15
- package/lib/src/workspaces.js +128 -64
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/src/chart.ts +519 -83
- package/src/genie.ts +24 -23
- package/src/mlflow.ts +3 -1
- package/src/observability.ts +16 -0
- package/src/plugin.ts +34 -1
- package/src/remote-skills.ts +10 -11
- package/src/skill-paths.ts +19 -0
- package/src/trace-io.ts +129 -0
- package/src/workspaces.ts +194 -84
package/src/workspaces.ts
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
2
2
|
* Mastra workspace factory for Databricks Apps.
|
|
3
3
|
*
|
|
4
4
|
* Builds a per-request {@link Workspace} whose filesystem is a
|
|
5
|
-
* {@link CompositeFilesystem} over
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* {@link CompositeFilesystem} over the NAMED skill folders resolved for that
|
|
6
|
+
* request. A skill folder maps a name to a location plus its readable /
|
|
7
|
+
* writable policy: a Databricks path mounted through the OBO client on
|
|
8
|
+
* {@link MASTRA_USER_KEY}, or any {@link WorkspaceFilesystem} a consuming
|
|
9
|
+
* library already owns. {@link DEFAULT_SKILL_FOLDERS} supplies the Assistant
|
|
10
|
+
* trees, and `skillFolders` merges over it - same name overrides, `false`
|
|
11
|
+
* disables, a new name adds. Optional mount resolvers contribute further
|
|
12
|
+
* filesystems and skill scan roots on top.
|
|
9
13
|
*
|
|
10
14
|
* Databricks mounts use `@dbx-tools/databricks` {@link DatabricksFileSystem}
|
|
11
15
|
* wrapped by {@link filesystems}; missing roots fall back to
|
|
@@ -16,7 +20,7 @@
|
|
|
16
20
|
|
|
17
21
|
import type { WorkspaceClient } from "@databricks/sdk-experimental";
|
|
18
22
|
import { DatabricksFileSystem } from "@dbx-tools/databricks";
|
|
19
|
-
import { log, string, token } from "@dbx-tools/shared-core";
|
|
23
|
+
import { error, log, string, token } from "@dbx-tools/shared-core";
|
|
20
24
|
import type { RequestContext } from "@mastra/core/request-context";
|
|
21
25
|
import {
|
|
22
26
|
CompositeFilesystem,
|
|
@@ -28,18 +32,10 @@ import {
|
|
|
28
32
|
|
|
29
33
|
import { MASTRA_SCOPES_KEY, MASTRA_USER_EMAIL_KEY, MASTRA_USER_KEY, type User } from "./config.ts";
|
|
30
34
|
import { scratchFilesystem, filesystems } from "./filesystems.ts";
|
|
35
|
+
import { ASSISTANT_SHARED_SKILLS_PATH, userAssistantSkillsPath } from "./skill-paths.ts";
|
|
31
36
|
|
|
32
37
|
/* ------------------------------ constants ------------------------------ */
|
|
33
38
|
|
|
34
|
-
/** Shared Assistant skills tree in the workspace namespace. */
|
|
35
|
-
const ASSISTANT_SHARED_SKILLS_PATH = "/Workspace/.assistant/skills";
|
|
36
|
-
|
|
37
|
-
/** Composite mount for {@link ASSISTANT_SHARED_SKILLS_PATH}. */
|
|
38
|
-
const ASSISTANT_WORKSPACE_SKILLS_MOUNT = "/workspace_skills";
|
|
39
|
-
|
|
40
|
-
/** Composite mount for the caller's `/.assistant/skills` tree. */
|
|
41
|
-
const ASSISTANT_USER_SKILLS_MOUNT = "/workspace_user_skills";
|
|
42
|
-
|
|
43
39
|
/** OAuth scopes that gate Databricks workspace file mounts. */
|
|
44
40
|
const WORKSPACE_FILE_SCOPES = ["workspace", "workspace.workspace", "all-apis"] as const;
|
|
45
41
|
|
|
@@ -47,23 +43,60 @@ const logger = log.logger("mastra/workspaces");
|
|
|
47
43
|
|
|
48
44
|
/* -------------------------------- types -------------------------------- */
|
|
49
45
|
|
|
50
|
-
/** Per-request context for mount resolvers. */
|
|
51
|
-
interface WorkspaceMountContext {
|
|
46
|
+
/** Per-request context for mount and skill-folder resolvers. */
|
|
47
|
+
export interface WorkspaceMountContext {
|
|
52
48
|
requestContext?: RequestContext;
|
|
53
49
|
}
|
|
54
50
|
|
|
51
|
+
/**
|
|
52
|
+
* A skill-folder field given either directly or as a per-request resolver.
|
|
53
|
+
* A resolver returning `undefined` skips the folder for that request.
|
|
54
|
+
*/
|
|
55
|
+
export type SkillFolderValue<T> =
|
|
56
|
+
T | ((context: WorkspaceMountContext) => T | undefined | Promise<T | undefined>);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* One named skill-folder location and its read / write policy.
|
|
60
|
+
*
|
|
61
|
+
* Give {@link path} for a Databricks workspace tree (mounted through the
|
|
62
|
+
* request's OBO client), or {@link filesystem} for a mount the consumer builds
|
|
63
|
+
* itself. {@link filesystem} wins when both are set.
|
|
64
|
+
*/
|
|
65
|
+
export interface SkillFolderOptions {
|
|
66
|
+
/** Absolute Databricks workspace path for this folder. */
|
|
67
|
+
path?: SkillFolderValue<string>;
|
|
68
|
+
/** Ready-made mount, for locations the OBO client cannot reach. */
|
|
69
|
+
filesystem?: SkillFolderValue<WorkspaceFilesystem>;
|
|
70
|
+
/**
|
|
71
|
+
* Scan this mount for `SKILL.md` files. Defaults to `true`; `false` mounts
|
|
72
|
+
* the location for file tools without adding it to skill discovery.
|
|
73
|
+
*/
|
|
74
|
+
readable?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Allow writes to a {@link path} mount (and create the root when missing).
|
|
77
|
+
* Defaults to `false`. A supplied {@link filesystem} carries its own
|
|
78
|
+
* read-only flag instead.
|
|
79
|
+
*/
|
|
80
|
+
writable?: boolean;
|
|
81
|
+
/** Mount point in the composite namespace. Defaults to `/<name>`. */
|
|
82
|
+
mount?: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
55
85
|
/** Mount map plus optional Mastra skill scan roots for one resolver. */
|
|
56
|
-
interface WorkspaceMountContribution {
|
|
86
|
+
export interface WorkspaceMountContribution {
|
|
57
87
|
mounts: Record<string, WorkspaceFilesystem>;
|
|
58
88
|
/** Paths within the composite namespace where `SKILL.md` files are scanned. */
|
|
59
89
|
skillPaths?: string[];
|
|
60
90
|
}
|
|
61
91
|
|
|
62
92
|
/** Contributes filesystem mounts (and optional skill paths) for one request. */
|
|
63
|
-
type WorkspaceMountResolver = (
|
|
93
|
+
export type WorkspaceMountResolver = (
|
|
64
94
|
context: WorkspaceMountContext,
|
|
65
95
|
) => WorkspaceMountContribution | Promise<WorkspaceMountContribution>;
|
|
66
96
|
|
|
97
|
+
/** Names carried by {@link DEFAULT_SKILL_FOLDERS}. */
|
|
98
|
+
export type DefaultSkillFolderName = "workspace-team" | "workspace-team-app";
|
|
99
|
+
|
|
67
100
|
/** Options for {@link createWorkspace}. */
|
|
68
101
|
export interface CreateWorkspaceOptions {
|
|
69
102
|
/** Workspace id; derived from `name` or `"workspace"` when omitted. */
|
|
@@ -71,11 +104,17 @@ export interface CreateWorkspaceOptions {
|
|
|
71
104
|
/** Display name; derived from `id` when omitted. */
|
|
72
105
|
name?: string;
|
|
73
106
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
107
|
+
* Start from {@link DEFAULT_SKILL_FOLDERS}. Defaults to `true`; `false`
|
|
108
|
+
* starts from an empty map, leaving only the {@link skillFolders} given here.
|
|
76
109
|
*/
|
|
77
110
|
assistantSkills?: boolean;
|
|
78
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Named skill folders merged over {@link DEFAULT_SKILL_FOLDERS}: a matching
|
|
113
|
+
* name overrides that default, `false` disables it, and any other name adds
|
|
114
|
+
* a folder.
|
|
115
|
+
*/
|
|
116
|
+
skillFolders?: Record<string, SkillFolderOptions | false>;
|
|
117
|
+
/** Extra per-request mount resolvers (run after the skill-folder mounts). */
|
|
79
118
|
mounts?: WorkspaceMountResolver[];
|
|
80
119
|
/** Replace the auto-built dynamic skills resolver. */
|
|
81
120
|
skills?: SkillsResolver;
|
|
@@ -93,18 +132,56 @@ export interface CreateWorkspaceOptions {
|
|
|
93
132
|
extraSkillPaths?: string[];
|
|
94
133
|
}
|
|
95
134
|
|
|
135
|
+
/* ------------------------------- defaults ------------------------------- */
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The skill folders every workspace starts with.
|
|
139
|
+
*
|
|
140
|
+
* - `workspace-team` - the shared workspace Assistant tree, read-only because
|
|
141
|
+
* writing it is a workspace-admin action.
|
|
142
|
+
* - `workspace-team-app` - the requesting user's own Assistant tree, writable
|
|
143
|
+
* so the app can save skills back to it. Skipped when the request carries no
|
|
144
|
+
* user email.
|
|
145
|
+
*/
|
|
146
|
+
export const DEFAULT_SKILL_FOLDERS: Readonly<Record<DefaultSkillFolderName, SkillFolderOptions>> = {
|
|
147
|
+
"workspace-team": {
|
|
148
|
+
path: ASSISTANT_SHARED_SKILLS_PATH,
|
|
149
|
+
readable: true,
|
|
150
|
+
writable: false,
|
|
151
|
+
},
|
|
152
|
+
"workspace-team-app": {
|
|
153
|
+
path: ({ requestContext }) => {
|
|
154
|
+
const email = resolveScopedEmail(requestContext);
|
|
155
|
+
return email ? userAssistantSkillsPath(email) : undefined;
|
|
156
|
+
},
|
|
157
|
+
readable: true,
|
|
158
|
+
writable: true,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
96
162
|
/**
|
|
97
163
|
* Create a Mastra {@link Workspace} with per-request Databricks mounts.
|
|
98
164
|
*
|
|
99
|
-
* @example
|
|
165
|
+
* @example Default skill folders only
|
|
100
166
|
* ```ts
|
|
101
167
|
* createWorkspace()
|
|
102
168
|
* ```
|
|
103
169
|
*
|
|
104
|
-
* @example
|
|
170
|
+
* @example Override a default, drop another, and add a location of your own
|
|
171
|
+
* ```ts
|
|
172
|
+
* createWorkspace({
|
|
173
|
+
* skillFolders: {
|
|
174
|
+
* "workspace-team": { path: "/Workspace/Shared/team-skills" },
|
|
175
|
+
* "workspace-team-app": false,
|
|
176
|
+
* runbooks: { path: "/Workspace/Shared/runbooks/skills", writable: true },
|
|
177
|
+
* volume: { filesystem: myVolumeFilesystem },
|
|
178
|
+
* },
|
|
179
|
+
* })
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* @example Skill folders plus a custom mount resolver
|
|
105
183
|
* ```ts
|
|
106
184
|
* createWorkspace({
|
|
107
|
-
* assistantSkills: true,
|
|
108
185
|
* mounts: [
|
|
109
186
|
* async ({ requestContext }) => ({
|
|
110
187
|
* mounts: { "/data": myFilesystem },
|
|
@@ -116,20 +193,22 @@ export interface CreateWorkspaceOptions {
|
|
|
116
193
|
*/
|
|
117
194
|
export function createWorkspace(options: CreateWorkspaceOptions = {}): Workspace {
|
|
118
195
|
const { id, name } = resolveWorkspaceIdentity(options);
|
|
119
|
-
const
|
|
196
|
+
const skillFolders = resolveSkillFolders(options);
|
|
197
|
+
const folderNames = Object.keys(skillFolders);
|
|
198
|
+
const resolvers = buildMountResolvers(skillFolders, options.mounts);
|
|
120
199
|
const extraSkillPaths = options.extraSkillPaths ?? [];
|
|
121
200
|
const skills =
|
|
122
201
|
options.skills ??
|
|
123
202
|
(resolvers.length > 0 || extraSkillPaths.length > 0
|
|
124
203
|
? buildWorkspaceSkillsResolver(resolvers, extraSkillPaths)
|
|
125
204
|
: undefined);
|
|
126
|
-
const checkSkillFileMtime = options.checkSkillFileMtime ??
|
|
205
|
+
const checkSkillFileMtime = options.checkSkillFileMtime ?? folderNames.length > 0;
|
|
127
206
|
const bm25 = options.bm25 !== false;
|
|
128
207
|
logger.debug("workspace:create", {
|
|
129
208
|
id,
|
|
130
209
|
name,
|
|
131
210
|
resolverCount: resolvers.length,
|
|
132
|
-
|
|
211
|
+
skillFolders: folderNames,
|
|
133
212
|
customMountResolvers: options.mounts?.length ?? 0,
|
|
134
213
|
customSkillsResolver: Boolean(options.skills),
|
|
135
214
|
checkSkillFileMtime,
|
|
@@ -151,16 +230,29 @@ export function createWorkspace(options: CreateWorkspaceOptions = {}): Workspace
|
|
|
151
230
|
});
|
|
152
231
|
}
|
|
153
232
|
|
|
154
|
-
/* ---------------------------- private helpers ---------------------------- */
|
|
155
|
-
|
|
156
233
|
/**
|
|
157
|
-
*
|
|
158
|
-
*
|
|
234
|
+
* Merge the configured skill folders over {@link DEFAULT_SKILL_FOLDERS}.
|
|
235
|
+
*
|
|
236
|
+
* `assistantSkills: false` drops the defaults, and a `false` value removes one
|
|
237
|
+
* entry by name.
|
|
159
238
|
*/
|
|
160
|
-
function
|
|
161
|
-
|
|
239
|
+
export function resolveSkillFolders(
|
|
240
|
+
options: Pick<CreateWorkspaceOptions, "assistantSkills" | "skillFolders"> = {},
|
|
241
|
+
): Record<string, SkillFolderOptions> {
|
|
242
|
+
const merged: Record<string, SkillFolderOptions> =
|
|
243
|
+
options.assistantSkills === false ? {} : { ...DEFAULT_SKILL_FOLDERS };
|
|
244
|
+
for (const [name, folder] of Object.entries(options.skillFolders ?? {})) {
|
|
245
|
+
if (folder === false) {
|
|
246
|
+
delete merged[name];
|
|
247
|
+
} else {
|
|
248
|
+
merged[name] = folder;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return merged;
|
|
162
252
|
}
|
|
163
253
|
|
|
254
|
+
/* ---------------------------- private helpers ---------------------------- */
|
|
255
|
+
|
|
164
256
|
/**
|
|
165
257
|
* Return whether the request token carries a scope that allows workspace
|
|
166
258
|
* file API access (`workspace` or `all-apis` on {@link MASTRA_SCOPES_KEY}).
|
|
@@ -173,61 +265,81 @@ function hasWorkspaceFileScope(requestContext: RequestContext | undefined): bool
|
|
|
173
265
|
}
|
|
174
266
|
|
|
175
267
|
/**
|
|
176
|
-
*
|
|
268
|
+
* Mount resolver for the named skill folders.
|
|
177
269
|
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* set. Returns empty mounts when the OBO user or client is missing.
|
|
181
|
-
* Mastra owns filesystem initialization.
|
|
270
|
+
* Gates on workspace file scope (or development mode), then mounts every
|
|
271
|
+
* folder whose location resolves for this request.
|
|
182
272
|
*/
|
|
183
|
-
async function
|
|
273
|
+
async function resolveSkillFolderMounts(
|
|
274
|
+
skillFolders: Record<string, SkillFolderOptions>,
|
|
184
275
|
context: WorkspaceMountContext,
|
|
185
276
|
): Promise<WorkspaceMountContribution> {
|
|
186
277
|
const mounts: Record<string, WorkspaceFilesystem> = {};
|
|
278
|
+
const skillPaths: string[] = [];
|
|
187
279
|
const requestContext = context.requestContext;
|
|
188
280
|
|
|
189
|
-
if (!
|
|
190
|
-
logger.debug("
|
|
281
|
+
if (!requestContext || !shouldMountSkillFolders(requestContext)) {
|
|
282
|
+
logger.debug("skill-folders:skipped", {
|
|
191
283
|
reason: !requestContext ? "no-request-context" : "missing-workspace-scope",
|
|
192
284
|
nodeEnv: process.env.NODE_ENV,
|
|
193
|
-
scopes:
|
|
285
|
+
scopes: requestContext?.get(MASTRA_SCOPES_KEY),
|
|
194
286
|
});
|
|
195
|
-
return { mounts, skillPaths
|
|
287
|
+
return { mounts, skillPaths };
|
|
196
288
|
}
|
|
197
289
|
|
|
198
|
-
const user = requestContext
|
|
290
|
+
const user = requestContext.get(MASTRA_USER_KEY) as User | undefined;
|
|
199
291
|
const client = user?.executionContext.client as WorkspaceClient | undefined;
|
|
200
|
-
if (!client) {
|
|
201
|
-
logger.debug("assistant-skills:skipped", {
|
|
202
|
-
reason: "missing-obo-client",
|
|
203
|
-
userId: user?.id,
|
|
204
|
-
});
|
|
205
|
-
return { mounts, skillPaths: [] };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
mounts[ASSISTANT_WORKSPACE_SKILLS_MOUNT] = await databricksFilesystem(
|
|
209
|
-
client,
|
|
210
|
-
ASSISTANT_SHARED_SKILLS_PATH,
|
|
211
|
-
);
|
|
212
292
|
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
);
|
|
293
|
+
for (const [name, folder] of Object.entries(skillFolders)) {
|
|
294
|
+
const filesystem = await resolveSkillFolderFilesystem(name, folder, context, client);
|
|
295
|
+
if (!filesystem) continue;
|
|
296
|
+
const mount = folder.mount ?? `/${name}`;
|
|
297
|
+
mounts[mount] = filesystem;
|
|
298
|
+
if (folder.readable !== false) skillPaths.push(mount);
|
|
220
299
|
}
|
|
221
300
|
|
|
222
|
-
logger.debug("
|
|
223
|
-
sharedPath: ASSISTANT_SHARED_SKILLS_PATH,
|
|
224
|
-
sharedMount: ASSISTANT_WORKSPACE_SKILLS_MOUNT,
|
|
225
|
-
userMount: email ? ASSISTANT_USER_SKILLS_MOUNT : undefined,
|
|
226
|
-
userPath: email ? userAssistantSkillsPath(email) : undefined,
|
|
301
|
+
logger.debug("skill-folders:mounted", {
|
|
227
302
|
mountKeys: Object.keys(mounts),
|
|
303
|
+
skillPaths,
|
|
228
304
|
});
|
|
229
305
|
|
|
230
|
-
return { mounts, skillPaths
|
|
306
|
+
return { mounts, skillPaths };
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Resolve one skill folder to a Mastra filesystem, or `undefined` to skip it
|
|
311
|
+
* for this request.
|
|
312
|
+
*/
|
|
313
|
+
async function resolveSkillFolderFilesystem(
|
|
314
|
+
name: string,
|
|
315
|
+
folder: SkillFolderOptions,
|
|
316
|
+
context: WorkspaceMountContext,
|
|
317
|
+
client: WorkspaceClient | undefined,
|
|
318
|
+
): Promise<WorkspaceFilesystem | undefined> {
|
|
319
|
+
if (folder.filesystem !== undefined) {
|
|
320
|
+
return resolveSkillFolderValue(folder.filesystem, context);
|
|
321
|
+
}
|
|
322
|
+
// A path mount needs the request's OBO client to reach the workspace.
|
|
323
|
+
if (folder.path === undefined || !client) {
|
|
324
|
+
logger.debug("skill-folder:skipped", {
|
|
325
|
+
name,
|
|
326
|
+
reason: folder.path === undefined ? "no-location" : "missing-obo-client",
|
|
327
|
+
});
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
const root = string.trimToNull(await resolveSkillFolderValue(folder.path, context));
|
|
331
|
+
if (!root) return undefined;
|
|
332
|
+
return databricksFilesystem(client, root, folder.writable !== true);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Read a {@link SkillFolderValue}, calling it when it is a per-request resolver. */
|
|
336
|
+
function resolveSkillFolderValue<T>(
|
|
337
|
+
value: SkillFolderValue<T>,
|
|
338
|
+
context: WorkspaceMountContext,
|
|
339
|
+
): T | undefined | Promise<T | undefined> {
|
|
340
|
+
return typeof value === "function"
|
|
341
|
+
? (value as (context: WorkspaceMountContext) => T | undefined | Promise<T | undefined>)(context)
|
|
342
|
+
: value;
|
|
231
343
|
}
|
|
232
344
|
|
|
233
345
|
/**
|
|
@@ -249,19 +361,21 @@ function resolveWorkspaceIdentity(options: CreateWorkspaceOptions): {
|
|
|
249
361
|
return { id, name };
|
|
250
362
|
}
|
|
251
363
|
|
|
252
|
-
/** Collect
|
|
253
|
-
function buildMountResolvers(
|
|
364
|
+
/** Collect the skill-folder resolver and any caller-supplied ones. */
|
|
365
|
+
function buildMountResolvers(
|
|
366
|
+
skillFolders: Record<string, SkillFolderOptions>,
|
|
367
|
+
mounts: WorkspaceMountResolver[] | undefined,
|
|
368
|
+
): WorkspaceMountResolver[] {
|
|
254
369
|
const resolvers: WorkspaceMountResolver[] = [];
|
|
255
|
-
const
|
|
256
|
-
if (
|
|
257
|
-
resolvers.push(
|
|
370
|
+
const folderCount = Object.keys(skillFolders).length;
|
|
371
|
+
if (folderCount > 0) {
|
|
372
|
+
resolvers.push((context) => resolveSkillFolderMounts(skillFolders, context));
|
|
258
373
|
}
|
|
259
374
|
if (mounts?.length) {
|
|
260
375
|
resolvers.push(...mounts);
|
|
261
376
|
}
|
|
262
377
|
logger.debug("mounts:resolvers", {
|
|
263
|
-
|
|
264
|
-
builtInResolver: assistantSkills,
|
|
378
|
+
skillFolderCount: folderCount,
|
|
265
379
|
customResolverCount: mounts?.length ?? 0,
|
|
266
380
|
totalResolverCount: resolvers.length,
|
|
267
381
|
});
|
|
@@ -269,23 +383,19 @@ function buildMountResolvers(options: CreateWorkspaceOptions): WorkspaceMountRes
|
|
|
269
383
|
}
|
|
270
384
|
|
|
271
385
|
/**
|
|
272
|
-
* Gate
|
|
386
|
+
* Gate skill-folder mounts on the request's token.
|
|
273
387
|
*
|
|
274
388
|
* Always allows mounts in development; in other environments requires
|
|
275
389
|
* {@link hasWorkspaceFileScope}.
|
|
276
390
|
*/
|
|
277
|
-
function
|
|
278
|
-
requestContext: RequestContext | undefined,
|
|
279
|
-
): requestContext is RequestContext {
|
|
280
|
-
if (!requestContext) return false;
|
|
391
|
+
function shouldMountSkillFolders(requestContext: RequestContext): boolean {
|
|
281
392
|
if (process.env.NODE_ENV === "development") return true;
|
|
282
393
|
return hasWorkspaceFileScope(requestContext);
|
|
283
394
|
}
|
|
284
395
|
|
|
285
396
|
/** Read the trimmed OBO user email stamped on {@link MASTRA_USER_EMAIL_KEY}. */
|
|
286
397
|
function resolveScopedEmail(requestContext: RequestContext | undefined): string | undefined {
|
|
287
|
-
|
|
288
|
-
return email?.trim() || undefined;
|
|
398
|
+
return string.trimToNull(requestContext?.get(MASTRA_USER_EMAIL_KEY)) ?? undefined;
|
|
289
399
|
}
|
|
290
400
|
|
|
291
401
|
/**
|
|
@@ -313,7 +423,7 @@ async function databricksFilesystem(
|
|
|
313
423
|
logger.debug("databricks-mount:scratch-fallback", {
|
|
314
424
|
root,
|
|
315
425
|
readOnly,
|
|
316
|
-
error:
|
|
426
|
+
error: error.errorMessage(err),
|
|
317
427
|
});
|
|
318
428
|
}
|
|
319
429
|
return scratchFilesystem();
|