@dbx-tools/appkit-mastra 0.9.118 → 0.9.120
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 +122 -108
- package/index.ts +3 -6
- package/lib/index.d.ts +3 -6
- package/lib/index.js +3 -5
- package/lib/src/agents.js +4 -5
- package/lib/src/chart.js +4 -4
- package/lib/src/chat.js +2 -2
- package/lib/src/config.d.ts +24 -19
- package/lib/src/config.js +6 -6
- package/lib/src/defaults.js +4 -4
- package/lib/src/genie.d.ts +3 -1
- package/lib/src/genie.js +18 -14
- package/lib/src/memory.d.ts +2 -22
- package/lib/src/memory.js +2 -32
- package/lib/src/mlflow.d.ts +3 -10
- package/lib/src/mlflow.js +6 -6
- package/lib/src/monty-sandbox.js +2 -2
- package/lib/src/plugin.d.ts +2 -19
- package/lib/src/plugin.js +14 -72
- package/lib/src/remote-skills.d.ts +32 -28
- package/lib/src/remote-skills.js +113 -33
- package/lib/src/server.js +2 -2
- package/lib/src/workspaces.d.ts +4 -7
- package/lib/src/workspaces.js +59 -56
- package/lib/src/writer.js +2 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -24
- package/src/agents.ts +3 -4
- package/src/chart.ts +3 -3
- package/src/chat.ts +1 -1
- package/src/config.ts +33 -24
- package/src/defaults.ts +3 -3
- package/src/genie.ts +18 -15
- package/src/memory.ts +2 -32
- package/src/mlflow.ts +7 -15
- package/src/monty-sandbox.ts +1 -1
- package/src/plugin.ts +15 -70
- package/src/remote-skills.ts +168 -42
- package/src/server.ts +1 -1
- package/src/workspaces.ts +62 -78
- package/src/writer.ts +1 -1
- package/lib/src/sandbox.d.ts +0 -107
- package/lib/src/sandbox.js +0 -461
- package/src/sandbox.ts +0 -556
package/src/workspaces.ts
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import { tmpdir } from "node:os";
|
|
17
17
|
import { join } from "node:path";
|
|
18
|
-
import { ConfigurationError } from "@databricks/appkit";
|
|
19
18
|
import type { WorkspaceClient } from "@databricks/appkit";
|
|
20
19
|
import { appkit, pluginRegistry } from "@dbx-tools/appkit";
|
|
21
20
|
import {
|
|
@@ -25,7 +24,7 @@ import {
|
|
|
25
24
|
} from "@dbx-tools/appkit/files-cache";
|
|
26
25
|
import { DatabricksFileSystem, workspaceClient } from "@dbx-tools/databricks";
|
|
27
26
|
import { LocalFileSystem } from "@dbx-tools/fs";
|
|
28
|
-
import { match, type PathMatchInput } from "@dbx-tools/path";
|
|
27
|
+
import { find, match, type PathMatchInput } from "@dbx-tools/path";
|
|
29
28
|
import { errorUtils, log, object, stringUtils, token } from "@dbx-tools/shared-core";
|
|
30
29
|
import {
|
|
31
30
|
fs as sharedFS,
|
|
@@ -61,7 +60,6 @@ import {
|
|
|
61
60
|
} from "./filesystems.ts";
|
|
62
61
|
import { MontySandbox } from "./monty-sandbox.ts";
|
|
63
62
|
import type { LocalSkillMount } from "./remote-skills.ts";
|
|
64
|
-
import { DatabricksSandbox, type DatabricksWorkspaceSandboxOptions } from "./sandbox.ts";
|
|
65
63
|
import { ORGANIZATION_ASSISTANT_PATH, personalWorkspacePath } from "./skill-paths.ts";
|
|
66
64
|
|
|
67
65
|
/* ------------------------------ constants ------------------------------ */
|
|
@@ -79,6 +77,7 @@ const CACHEABLE_FILESYSTEM_OPERATIONS = [
|
|
|
79
77
|
const logger = log.logger("mastra/workspaces");
|
|
80
78
|
let workspaceSourceSequence = 0;
|
|
81
79
|
const databricksWorkspaceOptions = new WeakMap<Workspace, DatabricksWorkspaceOptions>();
|
|
80
|
+
const sharedSkillFilesystems = new Map<string, Promise<FileSystem>>();
|
|
82
81
|
|
|
83
82
|
/* -------------------------------- types -------------------------------- */
|
|
84
83
|
|
|
@@ -174,16 +173,10 @@ type WorkspaceMountResolver = (
|
|
|
174
173
|
|
|
175
174
|
/**
|
|
176
175
|
* Sandbox selection for {@link databricksWorkspace}. Monty is the default;
|
|
177
|
-
* command execution can be disabled or replaced with
|
|
178
|
-
* Mastra provider/resolver.
|
|
176
|
+
* command execution can be disabled or replaced with any Mastra provider/resolver.
|
|
179
177
|
*/
|
|
180
178
|
export type WorkspaceSandboxSelection =
|
|
181
|
-
|
|
|
182
|
-
| "databricks"
|
|
183
|
-
| "monty"
|
|
184
|
-
| DatabricksWorkspaceSandboxOptions
|
|
185
|
-
| WorkspaceSandbox
|
|
186
|
-
| WorkspaceSandboxResolver;
|
|
179
|
+
false | true | "monty" | WorkspaceSandbox | WorkspaceSandboxResolver;
|
|
187
180
|
|
|
188
181
|
/** Native Mastra workspace options plus Databricks path shortcuts. */
|
|
189
182
|
export interface DatabricksWorkspaceOptions extends Omit<
|
|
@@ -208,9 +201,8 @@ export interface DatabricksWorkspaceOptions extends Omit<
|
|
|
208
201
|
/** AppKit plugin context used to discover optional sibling capabilities. */
|
|
209
202
|
pluginContext?: pluginRegistry.PluginContextLike;
|
|
210
203
|
/**
|
|
211
|
-
* Command sandbox. Defaults to Monty. Pass `false` to disable it,
|
|
212
|
-
*
|
|
213
|
-
* or an explicit Mastra sandbox/provider resolver.
|
|
204
|
+
* Command sandbox. Defaults to Monty. Pass `false` to disable it, or an
|
|
205
|
+
* explicit Mastra sandbox/provider resolver for a remote transport.
|
|
214
206
|
*/
|
|
215
207
|
sandbox?: WorkspaceSandboxSelection;
|
|
216
208
|
/** Add user-scoped `/tmp` only when no configured Databricks path mounts writable. */
|
|
@@ -418,49 +410,9 @@ function resolveWorkspaceSandbox(
|
|
|
418
410
|
): WorkspaceSandbox | WorkspaceSandboxResolver | undefined {
|
|
419
411
|
const configured = selection ?? "monty";
|
|
420
412
|
if (configured === false) return undefined;
|
|
421
|
-
if (configured === "monty") return new MontySandbox();
|
|
413
|
+
if (configured === true || configured === "monty") return new MontySandbox();
|
|
422
414
|
if (typeof configured === "function" || isSandbox(configured)) return configured;
|
|
423
|
-
|
|
424
|
-
const options: DatabricksWorkspaceSandboxOptions =
|
|
425
|
-
configured === "databricks" ? { provider: "databricks" } : configured;
|
|
426
|
-
return ({ requestContext }) => {
|
|
427
|
-
const user = requestContext.get(MASTRA_USER_KEY) as User | undefined;
|
|
428
|
-
if (!user) {
|
|
429
|
-
throw ConfigurationError.resourceNotFound(
|
|
430
|
-
"Databricks sandbox user context",
|
|
431
|
-
"Invoke command tools from an agent turn served by the Mastra plugin.",
|
|
432
|
-
);
|
|
433
|
-
}
|
|
434
|
-
const configuredId =
|
|
435
|
-
typeof options.sandboxId === "function"
|
|
436
|
-
? options.sandboxId({ requestContext })
|
|
437
|
-
: options.sandboxId;
|
|
438
|
-
const sandboxId = configuredId ?? defaultSandboxId(workspaceId, user.id);
|
|
439
|
-
const client =
|
|
440
|
-
typeof options.client === "function"
|
|
441
|
-
? options.client({ requestContext })
|
|
442
|
-
: (options.client ?? (user.executionContext.client as WorkspaceClient));
|
|
443
|
-
const {
|
|
444
|
-
provider: _provider,
|
|
445
|
-
sandboxId: _sandboxId,
|
|
446
|
-
client: _client,
|
|
447
|
-
...sandboxOptions
|
|
448
|
-
} = options;
|
|
449
|
-
return new DatabricksSandbox({
|
|
450
|
-
...sandboxOptions,
|
|
451
|
-
client,
|
|
452
|
-
sandboxId,
|
|
453
|
-
displayName: options.displayName ?? `Mastra ${workspaceName}`,
|
|
454
|
-
});
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
function defaultSandboxId(workspaceId: string, userId: string): string {
|
|
459
|
-
const digest = createHash("sha256")
|
|
460
|
-
.update(object.toStableKey({ workspaceId, userId }))
|
|
461
|
-
.digest("hex")
|
|
462
|
-
.slice(0, 32);
|
|
463
|
-
return `mastra-${digest}`;
|
|
415
|
+
throw new TypeError(`Unsupported workspace sandbox for ${workspaceId} (${workspaceName})`);
|
|
464
416
|
}
|
|
465
417
|
|
|
466
418
|
function isSandbox(value: unknown): value is WorkspaceSandbox {
|
|
@@ -471,10 +423,9 @@ function isSandbox(value: unknown): value is WorkspaceSandbox {
|
|
|
471
423
|
|
|
472
424
|
function sandboxName(selection: WorkspaceSandboxSelection | undefined): string {
|
|
473
425
|
if (selection === undefined || selection === false) return "disabled";
|
|
474
|
-
if (selection === "monty") return "monty";
|
|
475
|
-
if (selection === "databricks") return "databricks";
|
|
426
|
+
if (selection === true || selection === "monty") return "monty";
|
|
476
427
|
if (typeof selection === "function") return "resolver";
|
|
477
|
-
return
|
|
428
|
+
return selection.provider;
|
|
478
429
|
}
|
|
479
430
|
|
|
480
431
|
/**
|
|
@@ -844,25 +795,58 @@ function userTempFilesystem(
|
|
|
844
795
|
function localSkillMountResolvers(mounts: readonly LocalSkillMount[]): WorkspaceMountResolver[] {
|
|
845
796
|
const unique = new Map<string, LocalSkillMount>();
|
|
846
797
|
for (const entry of mounts) {
|
|
847
|
-
const
|
|
848
|
-
if (!
|
|
849
|
-
unique.set(`${entry.mountPath}\0${
|
|
798
|
+
const identity = "root" in entry ? entry.root.trim() : entry.filesystem.id;
|
|
799
|
+
if (!identity) continue;
|
|
800
|
+
unique.set(`${entry.mountPath}\0${identity}`, entry);
|
|
850
801
|
}
|
|
851
|
-
return [...unique.values()].map((
|
|
852
|
-
const mount = posixPath.normalizeRoot(mountPath);
|
|
853
|
-
const
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
skillPaths: [mount],
|
|
862
|
-
});
|
|
802
|
+
return [...unique.values()].map((entry) => {
|
|
803
|
+
const mount = posixPath.normalizeRoot(entry.mountPath);
|
|
804
|
+
const filesystem = inMemorySkillFilesystem(entry);
|
|
805
|
+
return async () => {
|
|
806
|
+
const source = await filesystem;
|
|
807
|
+
return {
|
|
808
|
+
mounts: { [mount]: filesystems(source, { readOnly: true }) },
|
|
809
|
+
skillPaths: [mount],
|
|
810
|
+
};
|
|
811
|
+
};
|
|
863
812
|
});
|
|
864
813
|
}
|
|
865
814
|
|
|
815
|
+
function inMemorySkillFilesystem(mount: LocalSkillMount): Promise<FileSystem> {
|
|
816
|
+
const key = "root" in mount ? `root:${mount.root}` : `filesystem:${mount.filesystem.id}`;
|
|
817
|
+
const existing = sharedSkillFilesystems.get(key);
|
|
818
|
+
if (existing) return existing;
|
|
819
|
+
const loaded = loadInMemorySkillFilesystem(mount).catch((error) => {
|
|
820
|
+
if (sharedSkillFilesystems.get(key) === loaded) sharedSkillFilesystems.delete(key);
|
|
821
|
+
throw error;
|
|
822
|
+
});
|
|
823
|
+
sharedSkillFilesystems.set(key, loaded);
|
|
824
|
+
return loaded;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
async function loadInMemorySkillFilesystem(mount: LocalSkillMount): Promise<FileSystem> {
|
|
828
|
+
if ("filesystem" in mount) {
|
|
829
|
+
await mount.filesystem.init();
|
|
830
|
+
return mount.filesystem;
|
|
831
|
+
}
|
|
832
|
+
const source = new LocalFileSystem({
|
|
833
|
+
root: mount.root,
|
|
834
|
+
readOnly: true,
|
|
835
|
+
createRoot: false,
|
|
836
|
+
});
|
|
837
|
+
await source.init();
|
|
838
|
+
const memory = new MemoryFileSystem({
|
|
839
|
+
id: `skills-${createHash("sha256").update(mount.root).digest("hex").slice(0, 16)}`,
|
|
840
|
+
root: "/",
|
|
841
|
+
});
|
|
842
|
+
await memory.init();
|
|
843
|
+
for await (const relative of find.findFiles("**/*", { cwd: mount.root, nodir: true })) {
|
|
844
|
+
await memory.writeFile(relative, await source.readFile(relative), { overwrite: true });
|
|
845
|
+
}
|
|
846
|
+
await source.close();
|
|
847
|
+
return memory;
|
|
848
|
+
}
|
|
849
|
+
|
|
866
850
|
/**
|
|
867
851
|
* Gate skill-folder mounts on the request's token.
|
|
868
852
|
*
|
|
@@ -912,7 +896,7 @@ async function databricksFilesystem(
|
|
|
912
896
|
logger.debug("databricks-mount:skipped", {
|
|
913
897
|
root,
|
|
914
898
|
readOnly,
|
|
915
|
-
error: errorUtils.
|
|
899
|
+
error: errorUtils.toError(err),
|
|
916
900
|
});
|
|
917
901
|
}
|
|
918
902
|
return undefined;
|
|
@@ -961,7 +945,7 @@ function verifyFirstFileSystemAccess<TFileSystem extends FileSystem>(
|
|
|
961
945
|
readCheck = undefined;
|
|
962
946
|
logger.debug("databricks-mount:read-check-failed", {
|
|
963
947
|
root,
|
|
964
|
-
error: errorUtils.
|
|
948
|
+
error: errorUtils.toError(error),
|
|
965
949
|
});
|
|
966
950
|
throw error;
|
|
967
951
|
}
|
|
@@ -992,7 +976,7 @@ function verifyFirstFileSystemAccess<TFileSystem extends FileSystem>(
|
|
|
992
976
|
if (!writeVerified) {
|
|
993
977
|
logger.debug("databricks-mount:write-check-failed", {
|
|
994
978
|
root,
|
|
995
|
-
error: errorUtils.
|
|
979
|
+
error: errorUtils.toError(error),
|
|
996
980
|
});
|
|
997
981
|
}
|
|
998
982
|
throw error;
|
|
@@ -1095,7 +1079,7 @@ async function resolveDistinctSkillPaths(
|
|
|
1095
1079
|
} catch (error) {
|
|
1096
1080
|
logger.debug("skill-path:skipped", {
|
|
1097
1081
|
path,
|
|
1098
|
-
error: errorUtils.
|
|
1082
|
+
error: errorUtils.toError(error),
|
|
1099
1083
|
});
|
|
1100
1084
|
}
|
|
1101
1085
|
}
|
package/src/writer.ts
CHANGED
package/lib/src/sandbox.d.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Databricks Sandbox adapter for Mastra workspaces.
|
|
3
|
-
*
|
|
4
|
-
* Implements Mastra's foreground command surface over the Databricks Sandbox
|
|
5
|
-
* REST API. Sandboxes are created lazily, retain their home directory across
|
|
6
|
-
* inactivity stops, and execute untrusted shell commands outside the App
|
|
7
|
-
* container.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
import type { WorkspaceClient } from "@databricks/appkit";
|
|
12
|
-
import type { RequestContext } from "@mastra/core/request-context";
|
|
13
|
-
import type { CommandResult, ExecuteCommandOptions, ProviderStatus, SandboxInfo, WorkspaceSandbox } from "@mastra/core/workspace";
|
|
14
|
-
import { type MontySandboxOptions } from "./monty-sandbox.ts";
|
|
15
|
-
/** Options for one Databricks-backed Mastra sandbox. */
|
|
16
|
-
export interface DatabricksSandboxOptions {
|
|
17
|
-
/** AppKit workspace client used for every sandbox API call. */
|
|
18
|
-
client: WorkspaceClient;
|
|
19
|
-
/** Resource id, with or without the `sandboxes/` prefix. */
|
|
20
|
-
sandboxId: string;
|
|
21
|
-
/** Human-readable Databricks label. */
|
|
22
|
-
displayName?: string;
|
|
23
|
-
/** Server-side idle timeout in protobuf duration form. Defaults to `900s`. */
|
|
24
|
-
inactivityTimeout?: string;
|
|
25
|
-
/** Maximum time to wait for the sandbox to become runnable. */
|
|
26
|
-
startupTimeoutMs?: number;
|
|
27
|
-
/** Default command timeout. Per-call `options.timeout` wins. */
|
|
28
|
-
commandTimeoutMs?: number;
|
|
29
|
-
/**
|
|
30
|
-
* Provider used only when Databricks Sandbox is definitively unavailable.
|
|
31
|
-
* Disabled by default. Pass `"monty"`, Monty options, or another Mastra
|
|
32
|
-
* sandbox to enable a fallback explicitly.
|
|
33
|
-
*/
|
|
34
|
-
fallback?: false | "monty" | MontySandboxOptions | WorkspaceSandbox;
|
|
35
|
-
}
|
|
36
|
-
/** Databricks options accepted by the higher-level workspace factory. */
|
|
37
|
-
export interface DatabricksWorkspaceSandboxOptions extends Omit<DatabricksSandboxOptions, "client" | "sandboxId"> {
|
|
38
|
-
/** Provider discriminator. Defaults to `databricks`. */
|
|
39
|
-
provider?: "databricks";
|
|
40
|
-
/**
|
|
41
|
-
* Credential source. Defaults to the active request's AppKit client, which
|
|
42
|
-
* uses OBO credentials when the turn runs in a user context.
|
|
43
|
-
*/
|
|
44
|
-
client?: WorkspaceClient | ((context: {
|
|
45
|
-
requestContext: RequestContext;
|
|
46
|
-
}) => WorkspaceClient);
|
|
47
|
-
/**
|
|
48
|
-
* Fixed id or per-request resolver. Omit to derive a stable, opaque id from
|
|
49
|
-
* the workspace and attributed user.
|
|
50
|
-
*/
|
|
51
|
-
sandboxId?: string | ((context: {
|
|
52
|
-
requestContext: RequestContext;
|
|
53
|
-
}) => string);
|
|
54
|
-
}
|
|
55
|
-
/** Mastra sandbox backed by Databricks serverless Sandbox compute. */
|
|
56
|
-
export declare class DatabricksSandbox implements WorkspaceSandbox {
|
|
57
|
-
readonly id: string;
|
|
58
|
-
readonly name: string;
|
|
59
|
-
status: ProviderStatus;
|
|
60
|
-
error?: string;
|
|
61
|
-
private readonly client;
|
|
62
|
-
private readonly displayName;
|
|
63
|
-
private readonly inactivityTimeout;
|
|
64
|
-
private readonly startupTimeoutMs;
|
|
65
|
-
private readonly commandTimeoutMs;
|
|
66
|
-
private readonly fallbackConfig;
|
|
67
|
-
private readonly createdAt;
|
|
68
|
-
private remoteCreatedAt?;
|
|
69
|
-
private lastUsedAt?;
|
|
70
|
-
private activeFallback?;
|
|
71
|
-
private fallbackPromise?;
|
|
72
|
-
private startPromise?;
|
|
73
|
-
constructor(options: DatabricksSandboxOptions);
|
|
74
|
-
get provider(): string;
|
|
75
|
-
/** Ensure the remote sandbox exists and has reached its running state. */
|
|
76
|
-
start(): Promise<void>;
|
|
77
|
-
private startWithSignal;
|
|
78
|
-
private performStart;
|
|
79
|
-
/** Databricks home persistence is not a cloneable Mastra checkpoint. */
|
|
80
|
-
snapshot(): Promise<void>;
|
|
81
|
-
get supportsCheckpoints(): boolean;
|
|
82
|
-
/** Stop compute while preserving the sandbox home directory. */
|
|
83
|
-
stop(): Promise<void>;
|
|
84
|
-
/** Permanently delete the sandbox and its persisted home directory. */
|
|
85
|
-
destroy(): Promise<void>;
|
|
86
|
-
/** Execute one foreground shell command in the remote sandbox. */
|
|
87
|
-
executeCommand(command: string, args?: string[], options?: ExecuteCommandOptions): Promise<CommandResult>;
|
|
88
|
-
/** Activate the configured fallback once across concurrent command failures. */
|
|
89
|
-
private activateFallback;
|
|
90
|
-
/** Start and publish the configured fallback after rechecking active state. */
|
|
91
|
-
private startFallback;
|
|
92
|
-
/** Execute through the active fallback or return an unsupported result. */
|
|
93
|
-
private executeFallback;
|
|
94
|
-
/** Whether the adapter currently knows the remote sandbox to be running. */
|
|
95
|
-
isReady(): Promise<boolean>;
|
|
96
|
-
/** Report Mastra-facing sandbox metadata. */
|
|
97
|
-
getInfo(): Promise<SandboxInfo>;
|
|
98
|
-
/** Explain the Databricks execution boundary to the agent. */
|
|
99
|
-
getInstructions(): string;
|
|
100
|
-
private get resourcePath();
|
|
101
|
-
private getOrCreate;
|
|
102
|
-
private get;
|
|
103
|
-
private mutate;
|
|
104
|
-
private waitForState;
|
|
105
|
-
private rememberCreatedAt;
|
|
106
|
-
private request;
|
|
107
|
-
}
|