@dbx-tools/appkit-mastra 0.9.79 → 0.9.95
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 +90 -48
- package/index.ts +4 -12
- package/lib/index.d.ts +4 -12
- package/lib/index.js +4 -9
- package/lib/src/agents.js +11 -23
- package/lib/src/chat.js +20 -1
- package/lib/src/config.d.ts +9 -11
- package/lib/src/config.js +7 -7
- package/lib/src/filesystems.d.ts +20 -2
- package/lib/src/filesystems.js +29 -2
- package/lib/src/monty-sandbox.d.ts +4 -3
- package/lib/src/monty-sandbox.js +54 -21
- package/lib/src/plugin.js +3 -2
- package/lib/src/remote-skills.d.ts +3 -4
- package/lib/src/remote-skills.js +5 -14
- package/lib/src/server.d.ts +7 -0
- package/lib/src/server.js +33 -2
- package/lib/src/skill-paths.d.ts +8 -4
- package/lib/src/skill-paths.js +12 -6
- package/lib/src/workspaces.d.ts +39 -33
- package/lib/src/workspaces.js +208 -168
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -38
- package/src/agents.ts +11 -24
- package/src/chat.ts +24 -0
- package/src/config.ts +15 -17
- package/src/filesystems.ts +43 -0
- package/src/monty-sandbox.ts +61 -22
- package/src/plugin.ts +2 -0
- package/src/remote-skills.ts +5 -15
- package/src/server.ts +33 -1
- package/src/skill-paths.ts +13 -5
- package/src/workspaces.ts +285 -210
- package/lib/src/monty-native.d.ts +0 -40
- package/lib/src/monty-native.js +0 -100
- package/lib/src/skill-cache.d.ts +0 -94
- package/lib/src/skill-cache.js +0 -251
- package/lib/src/skill-search.d.ts +0 -30
- package/lib/src/skill-search.js +0 -171
- package/src/monty-native.ts +0 -149
- package/src/skill-cache.ts +0 -347
- package/src/skill-search.ts +0 -203
package/lib/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/agents.ts","../src/chart.ts","../src/chat.ts","../src/config.ts","../src/defaults.ts","../src/evaluation.ts","../src/filesystems.ts","../src/genie.ts","../src/identity.ts","../src/mcp.ts","../src/memory.ts","../src/mlflow.ts","../src/model.ts","../src/monty-
|
|
1
|
+
{"root":["../src/agents.ts","../src/chart.ts","../src/chat.ts","../src/config.ts","../src/defaults.ts","../src/evaluation.ts","../src/filesystems.ts","../src/genie.ts","../src/identity.ts","../src/mcp.ts","../src/memory.ts","../src/mlflow.ts","../src/model.ts","../src/monty-sandbox.ts","../src/observability.ts","../src/openapi-tool.ts","../src/plugin.ts","../src/processors.ts","../src/remote-skills.ts","../src/rest.ts","../src/sandbox.ts","../src/server.ts","../src/serving-sanitize.ts","../src/serving.ts","../src/skill-paths.ts","../src/statement.ts","../src/storage-schema.ts","../src/style.ts","../src/summarize.ts","../src/telemetry.ts","../src/trace-attributes.ts","../src/validation.ts","../src/workspaces.ts","../src/writer.ts","../index.ts"],"version":"5.9.3"}
|
package/package.json
CHANGED
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@databricks/appkit": "0.81.0",
|
|
37
|
-
"@dbx-tools/appkit": "^0.9.
|
|
38
|
-
"@dbx-tools/core": "^0.9.
|
|
39
|
-
"@dbx-tools/databricks": "^0.9.
|
|
40
|
-
"@dbx-tools/fs": "^0.9.
|
|
41
|
-
"@dbx-tools/genie": "^0.9.
|
|
42
|
-
"@dbx-tools/model": "^0.9.
|
|
43
|
-
"@dbx-tools/path": "^0.9.
|
|
44
|
-
"@dbx-tools/postgres": "^0.9.
|
|
45
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
46
|
-
"@dbx-tools/shared-fs": "^0.9.
|
|
47
|
-
"@dbx-tools/shared-genie": "^0.9.
|
|
48
|
-
"@dbx-tools/shared-mastra": "^0.9.
|
|
49
|
-
"@dbx-tools/shared-model": "^0.9.
|
|
37
|
+
"@dbx-tools/appkit": "^0.9.95",
|
|
38
|
+
"@dbx-tools/core": "^0.9.95",
|
|
39
|
+
"@dbx-tools/databricks": "^0.9.95",
|
|
40
|
+
"@dbx-tools/fs": "^0.9.95",
|
|
41
|
+
"@dbx-tools/genie": "^0.9.95",
|
|
42
|
+
"@dbx-tools/model": "^0.9.95",
|
|
43
|
+
"@dbx-tools/path": "^0.9.95",
|
|
44
|
+
"@dbx-tools/postgres": "^0.9.95",
|
|
45
|
+
"@dbx-tools/shared-core": "^0.9.95",
|
|
46
|
+
"@dbx-tools/shared-fs": "^0.9.95",
|
|
47
|
+
"@dbx-tools/shared-genie": "^0.9.95",
|
|
48
|
+
"@dbx-tools/shared-mastra": "^0.9.95",
|
|
49
|
+
"@dbx-tools/shared-model": "^0.9.95",
|
|
50
50
|
"@mastra/ai-sdk": "1.10.5",
|
|
51
51
|
"@mastra/core": "1.71.0",
|
|
52
52
|
"@mastra/express": "1.5.15",
|
|
@@ -132,10 +132,6 @@
|
|
|
132
132
|
"types": "./lib/src/model.d.ts",
|
|
133
133
|
"default": "./lib/src/model.js"
|
|
134
134
|
},
|
|
135
|
-
"./monty-native": {
|
|
136
|
-
"types": "./lib/src/monty-native.d.ts",
|
|
137
|
-
"default": "./lib/src/monty-native.js"
|
|
138
|
-
},
|
|
139
135
|
"./monty-sandbox": {
|
|
140
136
|
"types": "./lib/src/monty-sandbox.d.ts",
|
|
141
137
|
"default": "./lib/src/monty-sandbox.js"
|
|
@@ -180,18 +176,10 @@
|
|
|
180
176
|
"types": "./lib/src/serving.d.ts",
|
|
181
177
|
"default": "./lib/src/serving.js"
|
|
182
178
|
},
|
|
183
|
-
"./skill-cache": {
|
|
184
|
-
"types": "./lib/src/skill-cache.d.ts",
|
|
185
|
-
"default": "./lib/src/skill-cache.js"
|
|
186
|
-
},
|
|
187
179
|
"./skill-paths": {
|
|
188
180
|
"types": "./lib/src/skill-paths.d.ts",
|
|
189
181
|
"default": "./lib/src/skill-paths.js"
|
|
190
182
|
},
|
|
191
|
-
"./skill-search": {
|
|
192
|
-
"types": "./lib/src/skill-search.d.ts",
|
|
193
|
-
"default": "./lib/src/skill-search.js"
|
|
194
|
-
},
|
|
195
183
|
"./statement": {
|
|
196
184
|
"types": "./lib/src/statement.d.ts",
|
|
197
185
|
"default": "./lib/src/statement.js"
|
|
@@ -231,7 +219,7 @@
|
|
|
231
219
|
"./package.json": "./package.json"
|
|
232
220
|
}
|
|
233
221
|
},
|
|
234
|
-
"version": "0.9.
|
|
222
|
+
"version": "0.9.95",
|
|
235
223
|
"types": "./lib/index.d.ts",
|
|
236
224
|
"dbxToolsConfig": {
|
|
237
225
|
"tags": [
|
|
@@ -296,10 +284,6 @@
|
|
|
296
284
|
"types": "./lib/src/model.d.ts",
|
|
297
285
|
"default": "./lib/src/model.js"
|
|
298
286
|
},
|
|
299
|
-
"./monty-native": {
|
|
300
|
-
"types": "./lib/src/monty-native.d.ts",
|
|
301
|
-
"default": "./lib/src/monty-native.js"
|
|
302
|
-
},
|
|
303
287
|
"./monty-sandbox": {
|
|
304
288
|
"types": "./lib/src/monty-sandbox.d.ts",
|
|
305
289
|
"default": "./lib/src/monty-sandbox.js"
|
|
@@ -344,18 +328,10 @@
|
|
|
344
328
|
"types": "./lib/src/serving.d.ts",
|
|
345
329
|
"default": "./lib/src/serving.js"
|
|
346
330
|
},
|
|
347
|
-
"./skill-cache": {
|
|
348
|
-
"types": "./lib/src/skill-cache.d.ts",
|
|
349
|
-
"default": "./lib/src/skill-cache.js"
|
|
350
|
-
},
|
|
351
331
|
"./skill-paths": {
|
|
352
332
|
"types": "./lib/src/skill-paths.d.ts",
|
|
353
333
|
"default": "./lib/src/skill-paths.js"
|
|
354
334
|
},
|
|
355
|
-
"./skill-search": {
|
|
356
|
-
"types": "./lib/src/skill-search.d.ts",
|
|
357
|
-
"default": "./lib/src/skill-search.js"
|
|
358
|
-
},
|
|
359
335
|
"./statement": {
|
|
360
336
|
"types": "./lib/src/statement.d.ts",
|
|
361
337
|
"default": "./lib/src/statement.js"
|
package/src/agents.ts
CHANGED
|
@@ -49,10 +49,9 @@ import type { MemoryBuilder } from "./memory.ts";
|
|
|
49
49
|
import { buildModel, RESPONSES_PROVIDER_OPTIONS } from "./model.ts";
|
|
50
50
|
import { stripStaleChartsProcessor } from "./processors.ts";
|
|
51
51
|
import { MASTRA_RESOLVED_MODEL_KEY } from "./serving.ts";
|
|
52
|
-
import { CatalogueSkillSearchProcessor } from "./skill-search.ts";
|
|
53
52
|
import { TYPOGRAPHY_RULE } from "./style.ts";
|
|
54
53
|
import { buildSummarizeTool } from "./summarize.ts";
|
|
55
|
-
import { createWorkspace
|
|
54
|
+
import { createWorkspace } from "./workspaces.ts";
|
|
56
55
|
|
|
57
56
|
/**
|
|
58
57
|
* Tool record accepted by every Mastra `Agent.tools` field and by the
|
|
@@ -188,16 +187,16 @@ export function createAgent<
|
|
|
188
187
|
* options, so {@link buildAgents} may rebuild it with startup-provisioned
|
|
189
188
|
* `extraSkillPaths` (a caller-supplied workspace is never touched).
|
|
190
189
|
*/
|
|
191
|
-
const
|
|
190
|
+
const defaultWorkspaces = new WeakSet<Workspace>();
|
|
192
191
|
|
|
193
192
|
/** Brand `workspace` as the auto-created default. */
|
|
194
193
|
function markDefaultWorkspace(workspace: Workspace): void {
|
|
195
|
-
(workspace
|
|
194
|
+
defaultWorkspaces.add(workspace);
|
|
196
195
|
}
|
|
197
196
|
|
|
198
197
|
/** Whether `workspace` was auto-created by {@link createAgent}. */
|
|
199
198
|
function isDefaultWorkspace(workspace: Workspace | undefined): boolean {
|
|
200
|
-
return
|
|
199
|
+
return workspace !== undefined && defaultWorkspaces.has(workspace);
|
|
201
200
|
}
|
|
202
201
|
|
|
203
202
|
/**
|
|
@@ -577,14 +576,14 @@ export async function buildAgents(opts: {
|
|
|
577
576
|
(def.workspace === undefined && !workspace) ||
|
|
578
577
|
((extraSkillPaths?.length ||
|
|
579
578
|
config.sandbox !== undefined ||
|
|
580
|
-
config.
|
|
579
|
+
config.workspaceTools !== undefined ||
|
|
580
|
+
context !== undefined) &&
|
|
581
581
|
isDefaultWorkspace(workspace))
|
|
582
582
|
) {
|
|
583
583
|
workspace = createWorkspace({
|
|
584
584
|
extraSkillPaths,
|
|
585
|
-
...(config.
|
|
586
|
-
|
|
587
|
-
: {}),
|
|
585
|
+
...(config.workspaceTools !== undefined ? { tools: config.workspaceTools } : {}),
|
|
586
|
+
pluginContext: context,
|
|
588
587
|
sandbox: config.sandbox === true ? "databricks" : config.sandbox,
|
|
589
588
|
});
|
|
590
589
|
markDefaultWorkspace(workspace);
|
|
@@ -668,21 +667,9 @@ function toolErrorLoggingProcessor(logger: log.Logger): OutputProcessor {
|
|
|
668
667
|
function workspaceSkillInputProcessors(
|
|
669
668
|
workspace: Workspace | undefined,
|
|
670
669
|
config: MastraPluginConfig,
|
|
671
|
-
):
|
|
672
|
-
if (!workspace || config.
|
|
673
|
-
const options =
|
|
674
|
-
typeof config.workspaceSkillSearch === "object" ? config.workspaceSkillSearch : undefined;
|
|
675
|
-
const catalogue = workspaceSkillCatalogueResolver(workspace);
|
|
676
|
-
if (catalogue) {
|
|
677
|
-
return [
|
|
678
|
-
new CatalogueSkillSearchProcessor({
|
|
679
|
-
resolve: catalogue,
|
|
680
|
-
topK: options?.topK ?? 5,
|
|
681
|
-
minScore: options?.minScore ?? 0.1,
|
|
682
|
-
...(options?.ttlMs !== undefined ? { ttlMs: options.ttlMs } : {}),
|
|
683
|
-
}),
|
|
684
|
-
];
|
|
685
|
-
}
|
|
670
|
+
): SkillSearchProcessor[] {
|
|
671
|
+
if (!workspace || config.workspaceSkills === false) return [];
|
|
672
|
+
const options = typeof config.workspaceSkills === "object" ? config.workspaceSkills : undefined;
|
|
686
673
|
if (!workspace.skills) return [];
|
|
687
674
|
return [
|
|
688
675
|
new SkillSearchProcessor({
|
package/src/chat.ts
CHANGED
|
@@ -4,9 +4,16 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { errorUtils, log } from "@dbx-tools/shared-core";
|
|
7
8
|
import { routes } from "@dbx-tools/shared-mastra";
|
|
9
|
+
import {
|
|
10
|
+
isStaleMastraResumeError,
|
|
11
|
+
STALE_MASTRA_RESUME_STREAM_TEXT,
|
|
12
|
+
} from "@dbx-tools/shared-mastra/resume";
|
|
8
13
|
import { chatRoute } from "@mastra/ai-sdk";
|
|
9
14
|
|
|
15
|
+
const logger = log.logger("mastra/chat");
|
|
16
|
+
|
|
10
17
|
/** Register the official AI SDK chat stream plus its approval continuation. */
|
|
11
18
|
export function agentChatRoutes() {
|
|
12
19
|
const path = `${routes.MASTRA_ROUTES.chat}/:agentId` as `${string}:agentId`;
|
|
@@ -15,6 +22,23 @@ export function agentChatRoutes() {
|
|
|
15
22
|
path,
|
|
16
23
|
sendReasoning: true,
|
|
17
24
|
sendSources: true,
|
|
25
|
+
onError: serializeChatStreamError,
|
|
18
26
|
}),
|
|
19
27
|
];
|
|
20
28
|
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Keep a late or duplicate resume from failing the UI stream. Mastra's
|
|
32
|
+
* `chatRoute` already swallows a couple of resume ids on the v6 approval
|
|
33
|
+
* path; this covers the generic workflow errors `consumeStream` still
|
|
34
|
+
* surfaces on v5.
|
|
35
|
+
*/
|
|
36
|
+
function serializeChatStreamError(error: unknown): string {
|
|
37
|
+
if (isStaleMastraResumeError(error)) {
|
|
38
|
+
logger.warn("ignored stale mastra resume", {
|
|
39
|
+
error: errorUtils.errorMessage(error),
|
|
40
|
+
});
|
|
41
|
+
return STALE_MASTRA_RESUME_STREAM_TEXT;
|
|
42
|
+
}
|
|
43
|
+
return errorUtils.errorMessage(error);
|
|
44
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type { BrandContext } from "@dbx-tools/shared-core";
|
|
|
20
20
|
import type { AgentConfig } from "@mastra/core/agent";
|
|
21
21
|
import type { RequestContext } from "@mastra/core/request-context";
|
|
22
22
|
import { MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
|
|
23
|
+
import type { WorkspaceToolsConfig } from "@mastra/core/workspace";
|
|
23
24
|
import type { PgVectorConfig, PostgresStoreConfig } from "@mastra/pg";
|
|
24
25
|
|
|
25
26
|
import type { AnyMastraAgentDefinition, MastraTools } from "./agents.ts";
|
|
@@ -147,8 +148,8 @@ export type MastraMemoryConfig = PgVectorConfig & {
|
|
|
147
148
|
id?: string;
|
|
148
149
|
};
|
|
149
150
|
|
|
150
|
-
/**
|
|
151
|
-
export interface
|
|
151
|
+
/** Mastra native workspace skill-search configuration. */
|
|
152
|
+
export interface MastraWorkspaceSkillsConfig {
|
|
152
153
|
/** Maximum skill matches returned by one search. Defaults to 5. */
|
|
153
154
|
topK?: number;
|
|
154
155
|
/** Minimum BM25 relevance score. Defaults to 0.1. */
|
|
@@ -217,16 +218,13 @@ export interface MastraPluginConfig extends BasePluginConfig {
|
|
|
217
218
|
* custom `workspace` keeps that workspace and its sandbox.
|
|
218
219
|
*/
|
|
219
220
|
sandbox?: boolean | "databricks" | "monty" | DatabricksWorkspaceSandboxOptions;
|
|
221
|
+
/** Native Mastra workspace tool availability, approval, and hook configuration. */
|
|
222
|
+
workspaceTools?: WorkspaceToolsConfig;
|
|
220
223
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
224
|
+
* Use Mastra's native workspace skill manager. Defaults to true. Pass an
|
|
225
|
+
* object to tune on-demand discovery and loaded-skill state.
|
|
223
226
|
*/
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Use dbx-tools catalogue-backed on-demand skill search. Defaults to true.
|
|
227
|
-
* Pass an object to tune search.
|
|
228
|
-
*/
|
|
229
|
-
workspaceSkillSearch?: boolean | MastraSkillSearchConfig;
|
|
227
|
+
workspaceSkills?: boolean | MastraWorkspaceSkillsConfig;
|
|
230
228
|
/**
|
|
231
229
|
* Code-defined agents. Accepts three shapes for convenience:
|
|
232
230
|
*
|
|
@@ -613,7 +611,7 @@ export interface MastraPluginConfig extends BasePluginConfig {
|
|
|
613
611
|
* through neither fails startup unless `failOnError: false`.
|
|
614
612
|
*
|
|
615
613
|
* Provisioned skills are written to the Databricks user's Assistant skills
|
|
616
|
-
* folder (`/Users/<email>/.assistant/skills`, the
|
|
614
|
+
* folder (`/Workspace/Users/<email>/.assistant/skills`, the personal skill
|
|
617
615
|
* target) so they persist and are picked up by the built-in Assistant-skills
|
|
618
616
|
* mount. With no writable workspace, they go to a local temp dir instead.
|
|
619
617
|
*
|
|
@@ -667,15 +665,15 @@ export const MASTRA_CONFIG_SCHEMA: ConfigSchema = {
|
|
|
667
665
|
description:
|
|
668
666
|
'Command sandbox for auto-created agent workspaces. Defaults to Monty; false disables command execution, and true, "databricks", or an object selects/configures Databricks Sandbox with optional fallback.',
|
|
669
667
|
},
|
|
670
|
-
|
|
671
|
-
type: "
|
|
668
|
+
workspaceSkills: {
|
|
669
|
+
type: ["boolean", "object"],
|
|
672
670
|
description:
|
|
673
|
-
"
|
|
671
|
+
"Use Mastra's native on-demand workspace skill search and writable skill saves. Defaults to true.",
|
|
674
672
|
},
|
|
675
|
-
|
|
676
|
-
type:
|
|
673
|
+
workspaceTools: {
|
|
674
|
+
type: "object",
|
|
677
675
|
description:
|
|
678
|
-
"
|
|
676
|
+
"Native Mastra workspace tool configuration for availability, approvals, read-before-write, output limits, and hooks.",
|
|
679
677
|
},
|
|
680
678
|
defaultAgent: {
|
|
681
679
|
type: "string",
|
package/src/filesystems.ts
CHANGED
|
@@ -22,12 +22,14 @@ import {
|
|
|
22
22
|
FileExistsError,
|
|
23
23
|
FileNotFoundError,
|
|
24
24
|
IsDirectoryError,
|
|
25
|
+
CompositeFilesystem,
|
|
25
26
|
MastraFilesystem,
|
|
26
27
|
NotDirectoryError,
|
|
27
28
|
PermissionError,
|
|
28
29
|
WorkspaceReadOnlyError,
|
|
29
30
|
} from "@mastra/core/workspace";
|
|
30
31
|
import type {
|
|
32
|
+
CompositeFilesystemConfig,
|
|
31
33
|
CopyOptions,
|
|
32
34
|
FileContent,
|
|
33
35
|
FileEntry,
|
|
@@ -49,6 +51,15 @@ export interface MastraFileSystemAdapterOptions extends MastraFilesystemOptions
|
|
|
49
51
|
/** Override the Mastra display name. Defaults to `MastraFileSystemAdapter`. */
|
|
50
52
|
name?: string;
|
|
51
53
|
|
|
54
|
+
/** Human-friendly mount name surfaced by composite filesystem listings. */
|
|
55
|
+
displayName?: string;
|
|
56
|
+
|
|
57
|
+
/** Mount description surfaced by composite filesystem listings and help. */
|
|
58
|
+
description?: string;
|
|
59
|
+
|
|
60
|
+
/** Replace the generated filesystem usage instructions. */
|
|
61
|
+
instructions?: string;
|
|
62
|
+
|
|
52
63
|
/**
|
|
53
64
|
* Override the Mastra provider id. Defaults to the source
|
|
54
65
|
* {@link FileSystem.backend}.
|
|
@@ -117,6 +128,14 @@ export class MastraFileSystemAdapter extends MastraFilesystem {
|
|
|
117
128
|
return this.options.provider ?? this.fs.backend;
|
|
118
129
|
}
|
|
119
130
|
|
|
131
|
+
get displayName(): string | undefined {
|
|
132
|
+
return this.options.displayName;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
get description(): string | undefined {
|
|
136
|
+
return this.options.description;
|
|
137
|
+
}
|
|
138
|
+
|
|
120
139
|
get readOnly(): boolean {
|
|
121
140
|
return this.options.readOnly === true || this.fs.readOnly;
|
|
122
141
|
}
|
|
@@ -145,7 +164,9 @@ export class MastraFileSystemAdapter extends MastraFilesystem {
|
|
|
145
164
|
}
|
|
146
165
|
|
|
147
166
|
getInstructions(): string {
|
|
167
|
+
if (this.options.instructions !== undefined) return this.options.instructions;
|
|
148
168
|
return [
|
|
169
|
+
...(this.description ? [this.description] : []),
|
|
149
170
|
`Files are served by a ${this.fs.backend} filesystem rooted at ${this.fs.root}.`,
|
|
150
171
|
"Workspace paths are absolute within this mount (for example `/notes/report.md`).",
|
|
151
172
|
].join(" ");
|
|
@@ -298,6 +319,28 @@ export class MastraFileSystemAdapter extends MastraFilesystem {
|
|
|
298
319
|
}
|
|
299
320
|
}
|
|
300
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Composite mount namespace whose virtual root has no repository-level
|
|
324
|
+
* `.gitignore`. Mastra's list tool probes that relative file before walking;
|
|
325
|
+
* an empty result keeps native ignore handling enabled without routing the
|
|
326
|
+
* virtual-root lookup into an unrelated mount.
|
|
327
|
+
*/
|
|
328
|
+
export class MountedCompositeFilesystem extends CompositeFilesystem {
|
|
329
|
+
constructor(config: CompositeFilesystemConfig) {
|
|
330
|
+
super(config);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
override async readFile(inputPath: string, options?: ReadOptions): Promise<string | Buffer> {
|
|
334
|
+
if (
|
|
335
|
+
(inputPath === ".gitignore" || inputPath === "/.gitignore") &&
|
|
336
|
+
!this.getFilesystemForPath(inputPath)
|
|
337
|
+
) {
|
|
338
|
+
return options?.encoding ? "" : Buffer.alloc(0);
|
|
339
|
+
}
|
|
340
|
+
return super.readFile(inputPath, options);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
301
344
|
/** Fresh writable local temp mount on a root unique to this call. */
|
|
302
345
|
export function scratchFilesystem(): MastraFileSystemAdapter {
|
|
303
346
|
return filesystems(localFS.scratchFS("mastra"));
|
package/src/monty-sandbox.ts
CHANGED
|
@@ -1,38 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pydantic Monty fallback for Mastra command execution.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Prefers Monty's native Node subprocess workers and falls back to its WASM
|
|
5
|
+
* workers when the native package is unavailable. It executes Python source
|
|
5
6
|
* with no host filesystem, network, environment, shell, or third-party package
|
|
6
|
-
* access
|
|
7
|
+
* access.
|
|
7
8
|
*
|
|
8
9
|
* @module
|
|
9
10
|
*/
|
|
10
11
|
|
|
11
|
-
import {
|
|
12
|
+
import { configUtils } from "@dbx-tools/core";
|
|
13
|
+
import { errorUtils, functionUtils, log } from "@dbx-tools/shared-core";
|
|
12
14
|
import type {
|
|
13
15
|
CommandResult,
|
|
14
16
|
ExecuteCommandOptions,
|
|
15
17
|
SandboxInfo,
|
|
16
18
|
WorkspaceSandbox,
|
|
17
19
|
} from "@mastra/core/workspace";
|
|
18
|
-
import type { CheckoutOptions, Monty
|
|
19
|
-
|
|
20
|
-
import { ensureMontyNativeBinding } from "./monty-native.ts";
|
|
20
|
+
import type { CheckoutOptions, Monty, MontyCrashedError, MontySession } from "@pydantic/monty";
|
|
21
21
|
|
|
22
22
|
const DEFAULT_COMMAND_TIMEOUT_MS = 30_000;
|
|
23
23
|
const DEFAULT_MAX_MEMORY_BYTES = 10_000_000;
|
|
24
|
+
const NATIVE_MONTY_TARGET = {
|
|
25
|
+
name: "native Monty",
|
|
26
|
+
load: () => import("@pydantic/monty/node"),
|
|
27
|
+
} as const;
|
|
28
|
+
const WASM_MONTY_TARGET = {
|
|
29
|
+
name: "WASM Monty",
|
|
30
|
+
load: () => import("@pydantic/monty/wasm"),
|
|
31
|
+
} as const;
|
|
32
|
+
const logger = log.logger("mastra/monty");
|
|
33
|
+
|
|
34
|
+
type MontyPool = Pick<Monty, "checkout">;
|
|
35
|
+
|
|
36
|
+
interface MontyContext {
|
|
37
|
+
crashedError: typeof MontyCrashedError;
|
|
38
|
+
pool: MontyPool;
|
|
39
|
+
}
|
|
24
40
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
const montyContext = functionUtils.memoize(async (): Promise<MontyContext> => {
|
|
42
|
+
const errors: Error[] = [];
|
|
43
|
+
const targets = configUtils.boolean(undefined, "MONTY_FORCE_WASM")
|
|
44
|
+
? [WASM_MONTY_TARGET]
|
|
45
|
+
: [NATIVE_MONTY_TARGET, WASM_MONTY_TARGET];
|
|
46
|
+
for (const target of targets) {
|
|
47
|
+
try {
|
|
48
|
+
const module = await target.load();
|
|
49
|
+
logger.debug(`${target.name} module available`);
|
|
50
|
+
const pool = await module.Monty.create({
|
|
51
|
+
minProcesses: 1,
|
|
52
|
+
maxProcesses: 4,
|
|
53
|
+
requestTimeout: 35,
|
|
54
|
+
});
|
|
55
|
+
logger.debug(`${target.name} pool created`);
|
|
56
|
+
return {
|
|
57
|
+
crashedError: module.MontyCrashedError,
|
|
58
|
+
pool,
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
errors.push(errorUtils.toError(error));
|
|
62
|
+
logger.debug(`${target.name} unavailable`, {
|
|
63
|
+
error: errorUtils.errorMessage(error),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
throw new AggregateError(errors, "Failed to create Monty pool");
|
|
36
68
|
});
|
|
37
69
|
|
|
38
70
|
/** Resource controls for the Monty Python fallback. */
|
|
@@ -49,7 +81,7 @@ export interface MontySandboxOptions {
|
|
|
49
81
|
typeCheck?: boolean;
|
|
50
82
|
}
|
|
51
83
|
|
|
52
|
-
/** Python-only, deny-by-default sandbox backed by Monty's
|
|
84
|
+
/** Python-only, deny-by-default sandbox backed by Monty's selected worker pool. */
|
|
53
85
|
export class MontySandbox implements WorkspaceSandbox {
|
|
54
86
|
readonly id: string;
|
|
55
87
|
readonly name: string;
|
|
@@ -77,7 +109,7 @@ export class MontySandbox implements WorkspaceSandbox {
|
|
|
77
109
|
this.status = "starting";
|
|
78
110
|
this.error = undefined;
|
|
79
111
|
try {
|
|
80
|
-
await
|
|
112
|
+
await montyContext();
|
|
81
113
|
this.status = "running";
|
|
82
114
|
} catch (caught) {
|
|
83
115
|
this.status = "error";
|
|
@@ -140,7 +172,7 @@ export class MontySandbox implements WorkspaceSandbox {
|
|
|
140
172
|
|
|
141
173
|
await this.start();
|
|
142
174
|
const timeout = options.timeout ?? this.commandTimeoutMs;
|
|
143
|
-
const pool = await
|
|
175
|
+
const pool = (await montyContext()).pool;
|
|
144
176
|
const session = await checkoutSession(
|
|
145
177
|
pool,
|
|
146
178
|
{
|
|
@@ -188,8 +220,8 @@ export class MontySandbox implements WorkspaceSandbox {
|
|
|
188
220
|
}
|
|
189
221
|
const message = errorUtils.errorMessage(caught);
|
|
190
222
|
output.emit("stderr", output.stderr.value ? `\n${message}` : message);
|
|
191
|
-
const {
|
|
192
|
-
const timedOut = caught instanceof
|
|
223
|
+
const { crashedError } = await montyContext();
|
|
224
|
+
const timedOut = caught instanceof crashedError && caught.timedOut;
|
|
193
225
|
return {
|
|
194
226
|
command,
|
|
195
227
|
args,
|
|
@@ -409,3 +441,10 @@ function failedResult(
|
|
|
409
441
|
executionTimeMs: performance.now() - started,
|
|
410
442
|
};
|
|
411
443
|
}
|
|
444
|
+
|
|
445
|
+
if (import.meta.main) {
|
|
446
|
+
const sandbox = new MontySandbox();
|
|
447
|
+
await sandbox.start();
|
|
448
|
+
console.log(await sandbox.executeCommand("print('Hello, world!')"));
|
|
449
|
+
await sandbox.stop();
|
|
450
|
+
}
|
package/src/plugin.ts
CHANGED
|
@@ -111,6 +111,7 @@ import { buildObservability, configureOtelPropagation } from "./observability.ts
|
|
|
111
111
|
import { provisionRemoteSkills } from "./remote-skills.ts";
|
|
112
112
|
import {
|
|
113
113
|
attachRoutePatchMiddleware,
|
|
114
|
+
attachStaleResumeRecovery,
|
|
114
115
|
createRequestContext,
|
|
115
116
|
isMastraRequestAllowed,
|
|
116
117
|
MastraServer,
|
|
@@ -1185,6 +1186,7 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
|
|
|
1185
1186
|
customApiRoutes: agentChatRoutes(),
|
|
1186
1187
|
});
|
|
1187
1188
|
await this.mastraServer.init();
|
|
1189
|
+
attachStaleResumeRecovery(this.mastraApp);
|
|
1188
1190
|
this.logger.info("ready", {
|
|
1189
1191
|
agents: Object.keys(this.built.agents),
|
|
1190
1192
|
defaultAgent: this.built.defaultAgentId,
|
package/src/remote-skills.ts
CHANGED
|
@@ -36,10 +36,9 @@
|
|
|
36
36
|
* Pass `refreshTtlMs: 0` to download on every boot.
|
|
37
37
|
*
|
|
38
38
|
* The default destination is the Databricks workspace Assistant skills tree
|
|
39
|
-
* (`/Workspace/.assistant/skills
|
|
40
|
-
* action writes to), so provisioned skills persist across restarts and are
|
|
39
|
+
* (`/Workspace/.assistant/skills`), so provisioned skills persist across restarts and are
|
|
41
40
|
* discovered by the built-in Assistant-skills mount. Pass `userEmail` (or an
|
|
42
|
-
* explicit `databricksBasePath`) to target `/Users/<email>/.assistant/skills`
|
|
41
|
+
* explicit `databricksBasePath`) to target `/Workspace/Users/<email>/.assistant/skills`
|
|
43
42
|
* instead. When no Databricks client is resolvable at startup - or the resolved
|
|
44
43
|
* identity cannot WRITE the destination, which is the normal case for a
|
|
45
44
|
* Databricks App service principal against the admin-owned shared tree (see
|
|
@@ -73,8 +72,7 @@ import {
|
|
|
73
72
|
import type { OneOrMany } from "@dbx-tools/shared-core";
|
|
74
73
|
import type { FileSystem } from "@dbx-tools/shared-fs";
|
|
75
74
|
|
|
76
|
-
import {
|
|
77
|
-
import { clearWorkspaceSkillCache } from "./skill-cache.ts";
|
|
75
|
+
import { ORGANIZATION_SKILLS_PATH, personalSkillsPath } from "./skill-paths.ts";
|
|
78
76
|
|
|
79
77
|
const logger = log.logger("mastra/remote-skills");
|
|
80
78
|
|
|
@@ -208,7 +206,7 @@ export interface ProvisionRemoteSkillsOptions {
|
|
|
208
206
|
failOnError?: boolean;
|
|
209
207
|
/**
|
|
210
208
|
* Absolute Databricks path that roots the destination Assistant skills tree.
|
|
211
|
-
* Defaults to the OBO user's `/Users/<email>/.assistant/skills`.
|
|
209
|
+
* Defaults to the OBO user's `/Workspace/Users/<email>/.assistant/skills`.
|
|
212
210
|
*/
|
|
213
211
|
databricksBasePath?: string;
|
|
214
212
|
/** Auth-scoped Databricks client. Defaults to the AppKit execution context. */
|
|
@@ -442,7 +440,6 @@ export async function provisionRemoteSkills(
|
|
|
442
440
|
const localSkillPaths: string[] = [];
|
|
443
441
|
const skillNames: string[] = [];
|
|
444
442
|
let staging: LocalFileSystem | undefined;
|
|
445
|
-
let workspaceUpdated = false;
|
|
446
443
|
|
|
447
444
|
try {
|
|
448
445
|
const sources = Array.isArray(options.sources) ? options.sources : [options.sources];
|
|
@@ -491,7 +488,6 @@ export async function provisionRemoteSkills(
|
|
|
491
488
|
// Only after the copy lands: a metadata entry written first would
|
|
492
489
|
// mark a failed provision as fresh and suppress the retry for a day.
|
|
493
490
|
await writeMetadata(destination, key, record);
|
|
494
|
-
workspaceUpdated = true;
|
|
495
491
|
} else {
|
|
496
492
|
localSkillPaths.push(await persistLocally(key, staged, record));
|
|
497
493
|
}
|
|
@@ -520,12 +516,6 @@ export async function provisionRemoteSkills(
|
|
|
520
516
|
}
|
|
521
517
|
}
|
|
522
518
|
|
|
523
|
-
if (workspaceUpdated && client?.config?.getHost) {
|
|
524
|
-
await clearWorkspaceSkillCache({
|
|
525
|
-
host: (await client.config.getHost()).toString(),
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
|
|
529
519
|
return { localSkillPaths, databricksBasePath, skillNames };
|
|
530
520
|
}
|
|
531
521
|
|
|
@@ -603,7 +593,7 @@ function resolveDatabricksBasePath(
|
|
|
603
593
|
// A named user targets their personal Assistant tree (the "save a skill"
|
|
604
594
|
// target); otherwise the shared workspace Assistant tree, which the built-in
|
|
605
595
|
// Assistant-skills mount already scans.
|
|
606
|
-
return email ?
|
|
596
|
+
return email ? personalSkillsPath(email) : ORGANIZATION_SKILLS_PATH;
|
|
607
597
|
}
|
|
608
598
|
|
|
609
599
|
/**
|
package/src/server.ts
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { getExecutionContext } from "@databricks/appkit";
|
|
9
|
-
import { hash, http, log, object, stringUtils, token } from "@dbx-tools/shared-core";
|
|
9
|
+
import { errorUtils, hash, http, log, object, stringUtils, token } from "@dbx-tools/shared-core";
|
|
10
10
|
import { feedback, thread } from "@dbx-tools/shared-mastra";
|
|
11
|
+
import { isStaleMastraResumeError } from "@dbx-tools/shared-mastra/resume";
|
|
11
12
|
import {
|
|
12
13
|
MASTRA_RESOURCE_ID_KEY,
|
|
13
14
|
MASTRA_THREAD_ID_KEY,
|
|
@@ -42,6 +43,7 @@ import { recordActiveTraceAuth, recordActiveTraceUser } from "./telemetry.ts";
|
|
|
42
43
|
* when no SDK is registered, which must never be surfaced as a trace to
|
|
43
44
|
* attach feedback to.
|
|
44
45
|
*/
|
|
46
|
+
const logger = log.logger("mastra/server");
|
|
45
47
|
const INVALID_TRACE_ID = "0".repeat(32);
|
|
46
48
|
const TRUSTED_REQUEST_CONTEXT_KEYS = [
|
|
47
49
|
MASTRA_RESOURCE_ID_KEY,
|
|
@@ -460,3 +462,33 @@ export function attachRoutePatchMiddleware(app: express.Express): void {
|
|
|
460
462
|
next();
|
|
461
463
|
});
|
|
462
464
|
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Finish a chat request when Mastra throws because the workflow is no
|
|
468
|
+
* longer suspended. Duplicate approve/resume and late `consumeStream`
|
|
469
|
+
* both hit that path; the client already has (or will reload) the
|
|
470
|
+
* completed turn.
|
|
471
|
+
*/
|
|
472
|
+
export function attachStaleResumeRecovery(app: express.Express): void {
|
|
473
|
+
app.use((error: unknown, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
474
|
+
if (!isStaleMastraResumeError(error)) {
|
|
475
|
+
next(error);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
logger.warn("ignored stale mastra resume", {
|
|
479
|
+
path: req.path,
|
|
480
|
+
error: errorUtils.errorMessage(error),
|
|
481
|
+
});
|
|
482
|
+
if (res.headersSent) {
|
|
483
|
+
res.end();
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
res.status(200);
|
|
487
|
+
res.setHeader("content-type", "text/event-stream; charset=utf-8");
|
|
488
|
+
res.setHeader("cache-control", "no-cache");
|
|
489
|
+
res.write(`data: ${JSON.stringify({ type: "start" })}\n\n`);
|
|
490
|
+
res.write(`data: ${JSON.stringify({ type: "finish" })}\n\n`);
|
|
491
|
+
res.write("data: [DONE]\n\n");
|
|
492
|
+
res.end();
|
|
493
|
+
});
|
|
494
|
+
}
|