@dbx-tools/appkit-mastra 0.9.95 → 0.9.99

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/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.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",
37
+ "@dbx-tools/appkit": "^0.9.99",
38
+ "@dbx-tools/core": "^0.9.99",
39
+ "@dbx-tools/databricks": "^0.9.99",
40
+ "@dbx-tools/fs": "^0.9.99",
41
+ "@dbx-tools/genie": "^0.9.99",
42
+ "@dbx-tools/model": "^0.9.99",
43
+ "@dbx-tools/path": "^0.9.99",
44
+ "@dbx-tools/postgres": "^0.9.99",
45
+ "@dbx-tools/shared-core": "^0.9.99",
46
+ "@dbx-tools/shared-fs": "^0.9.99",
47
+ "@dbx-tools/shared-genie": "^0.9.99",
48
+ "@dbx-tools/shared-mastra": "^0.9.99",
49
+ "@dbx-tools/shared-model": "^0.9.99",
50
50
  "@mastra/ai-sdk": "1.10.5",
51
51
  "@mastra/core": "1.71.0",
52
52
  "@mastra/express": "1.5.15",
@@ -219,7 +219,7 @@
219
219
  "./package.json": "./package.json"
220
220
  }
221
221
  },
222
- "version": "0.9.95",
222
+ "version": "0.9.99",
223
223
  "types": "./lib/index.d.ts",
224
224
  "dbxToolsConfig": {
225
225
  "tags": [
package/src/agents.ts CHANGED
@@ -51,7 +51,7 @@ import { stripStaleChartsProcessor } from "./processors.ts";
51
51
  import { MASTRA_RESOLVED_MODEL_KEY } from "./serving.ts";
52
52
  import { TYPOGRAPHY_RULE } from "./style.ts";
53
53
  import { buildSummarizeTool } from "./summarize.ts";
54
- import { createWorkspace } from "./workspaces.ts";
54
+ import { bindDatabricksWorkspaceContext, databricksWorkspace } from "./workspaces.ts";
55
55
 
56
56
  /**
57
57
  * Tool record accepted by every Mastra `Agent.tools` field and by the
@@ -168,8 +168,8 @@ function deriveToolId(description: string): string {
168
168
  * ```
169
169
  *
170
170
  * Adds the package's default workspace when the definition omits one. That
171
- * workspace carries Databricks skill mounts and Databricks Sandbox command
172
- * execution. An explicit workspace remains the caller's complete override.
171
+ * workspace carries Databricks skill mounts and Monty command execution. An
172
+ * explicit workspace remains the caller's complete override.
173
173
  */
174
174
  export function createAgent<
175
175
  TRequestContext extends Record<string, unknown> | unknown = unknown,
@@ -177,7 +177,7 @@ export function createAgent<
177
177
  MastraAgentDefinition<TRequestContext>,
178
178
  >(def: TDefinition): TDefinition {
179
179
  if (def.workspace) return { ...def };
180
- const workspace = createWorkspace();
180
+ const workspace = databricksWorkspace();
181
181
  markDefaultWorkspace(workspace);
182
182
  return { ...def, workspace };
183
183
  }
@@ -338,7 +338,7 @@ export interface MastraAgentDefinition<
338
338
  /**
339
339
  * Mastra {@link Workspace} for this agent (filesystem, sandbox, or other
340
340
  * providers). Assistant skills from Databricks workspace paths are wired
341
- * via {@link createWorkspace}.
341
+ * via {@link databricksWorkspace}.
342
342
  */
343
343
  workspace?: Workspace | MastraAgentWorkspaceResolver;
344
344
  }
@@ -580,13 +580,15 @@ export async function buildAgents(opts: {
580
580
  context !== undefined) &&
581
581
  isDefaultWorkspace(workspace))
582
582
  ) {
583
- workspace = createWorkspace({
583
+ workspace = databricksWorkspace({
584
584
  extraSkillPaths,
585
585
  ...(config.workspaceTools !== undefined ? { tools: config.workspaceTools } : {}),
586
586
  pluginContext: context,
587
587
  sandbox: config.sandbox === true ? "databricks" : config.sandbox,
588
588
  });
589
589
  markDefaultWorkspace(workspace);
590
+ } else if (workspace) {
591
+ workspace = bindDatabricksWorkspaceContext(workspace, context);
590
592
  }
591
593
  const gated = approvalGatedToolIds(tools);
592
594
  if (gated.length > 0) approvalGatedByAgent.push({ agentId: id, toolIds: gated });
@@ -11,12 +11,13 @@
11
11
 
12
12
  import { configUtils } from "@dbx-tools/core";
13
13
  import { errorUtils, functionUtils, log } from "@dbx-tools/shared-core";
14
+ import { availableParallelism } from "node:os";
14
15
  import type {
15
16
  CommandResult,
16
17
  ExecuteCommandOptions,
17
18
  SandboxInfo,
18
- WorkspaceSandbox,
19
19
  } from "@mastra/core/workspace";
20
+ import { MastraSandbox, type ProviderStatus } from "@mastra/core/workspace";
20
21
  import type { CheckoutOptions, Monty, MontyCrashedError, MontySession } from "@pydantic/monty";
21
22
 
22
23
  const DEFAULT_COMMAND_TIMEOUT_MS = 30_000;
@@ -38,6 +39,11 @@ interface MontyContext {
38
39
  pool: MontyPool;
39
40
  }
40
41
 
42
+ /** @internal Size the shared worker pool from the host's available processors. */
43
+ export function montyMaxProcesses(parallelism: number = availableParallelism()): number {
44
+ return Math.max(4, Math.floor(parallelism) * 2);
45
+ }
46
+
41
47
  const montyContext = functionUtils.memoize(async (): Promise<MontyContext> => {
42
48
  const errors: Error[] = [];
43
49
  const targets = configUtils.boolean(undefined, "MONTY_FORCE_WASM")
@@ -47,12 +53,13 @@ const montyContext = functionUtils.memoize(async (): Promise<MontyContext> => {
47
53
  try {
48
54
  const module = await target.load();
49
55
  logger.debug(`${target.name} module available`);
56
+ const maxProcesses = montyMaxProcesses();
50
57
  const pool = await module.Monty.create({
51
58
  minProcesses: 1,
52
- maxProcesses: 4,
59
+ maxProcesses,
53
60
  requestTimeout: 35,
54
61
  });
55
- logger.debug(`${target.name} pool created`);
62
+ logger.debug(`${target.name} pool created`, { maxProcesses });
56
63
  return {
57
64
  crashedError: module.MontyCrashedError,
58
65
  pool,
@@ -82,12 +89,11 @@ export interface MontySandboxOptions {
82
89
  }
83
90
 
84
91
  /** Python-only, deny-by-default sandbox backed by Monty's selected worker pool. */
85
- export class MontySandbox implements WorkspaceSandbox {
92
+ export class MontySandbox extends MastraSandbox {
86
93
  readonly id: string;
87
94
  readonly name: string;
88
95
  readonly provider = "monty";
89
- status: WorkspaceSandbox["status"] = "pending";
90
- error?: string;
96
+ status: ProviderStatus = "pending";
91
97
 
92
98
  private readonly commandTimeoutMs: number;
93
99
  private readonly maxMemoryBytes: number;
@@ -96,8 +102,10 @@ export class MontySandbox implements WorkspaceSandbox {
96
102
  private lastUsedAt?: Date;
97
103
 
98
104
  constructor(options: MontySandboxOptions = {}) {
105
+ const name = options.name ?? "Pydantic Monty";
106
+ super({ name });
99
107
  this.id = options.id ?? "monty";
100
- this.name = options.name ?? "Pydantic Monty";
108
+ this.name = name;
101
109
  this.commandTimeoutMs = options.commandTimeoutMs ?? DEFAULT_COMMAND_TIMEOUT_MS;
102
110
  this.maxMemoryBytes = options.maxMemoryBytes ?? DEFAULT_MAX_MEMORY_BYTES;
103
111
  this.typeCheck = options.typeCheck ?? false;
@@ -105,33 +113,14 @@ export class MontySandbox implements WorkspaceSandbox {
105
113
 
106
114
  /** Warm the shared crash-isolated worker pool. */
107
115
  async start(): Promise<void> {
108
- if (this.status === "running") return;
109
- this.status = "starting";
110
- this.error = undefined;
111
- try {
112
- await montyContext();
113
- this.status = "running";
114
- } catch (caught) {
115
- this.status = "error";
116
- this.error = errorUtils.errorMessage(caught);
117
- throw caught;
118
- }
116
+ await montyContext();
119
117
  }
120
118
 
121
119
  /** The process-wide pool stays warm; this instance carries no open session. */
122
- async stop(): Promise<void> {
123
- this.status = "stopped";
124
- }
120
+ async stop(): Promise<void> {}
125
121
 
126
122
  /** The process-wide pool stays warm; each command closes its own checkout. */
127
- async destroy(): Promise<void> {
128
- this.status = "destroyed";
129
- }
130
-
131
- /** Monty sessions are ephemeral and do not provide persistent checkpoints. */
132
- async snapshot(): Promise<void> {}
133
-
134
- readonly supportsCheckpoints = false;
123
+ async destroy(): Promise<void> {}
135
124
 
136
125
  /** Execute Python source and map Monty output to Mastra's command result. */
137
126
  async executeCommand(
@@ -9,16 +9,7 @@ import { urlBuilder, type UrlBuilder } from "@dbx-tools/shared-core/net";
9
9
  import type { JSONSchema7 } from "json-schema";
10
10
  import { z } from "zod";
11
11
 
12
- const HTTP_METHODS = [
13
- "GET",
14
- "POST",
15
- "PUT",
16
- "PATCH",
17
- "DELETE",
18
- "OPTIONS",
19
- "HEAD",
20
- "TRACE",
21
- ] as const;
12
+ const HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD", "TRACE"] as const;
22
13
 
23
14
  const JsonObjectSchema = z
24
15
  .record(z.string(), z.unknown())
@@ -208,7 +199,7 @@ function operationUrl(document: OpenApiDocument, sourceUrl: URL | undefined, pat
208
199
  ? base.withPathAppend(path).toString()
209
200
  : `${server.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
210
201
  }
211
- return sourceUrl ? urlBuilder(sourceUrl)?.withPathReplace(path).toString() ?? path : path;
202
+ return sourceUrl ? (urlBuilder(sourceUrl)?.withPathReplace(path).toString() ?? path) : path;
212
203
  }
213
204
 
214
205
  function resolveReferences(
package/src/server.ts CHANGED
@@ -470,25 +470,27 @@ export function attachRoutePatchMiddleware(app: express.Express): void {
470
470
  * completed turn.
471
471
  */
472
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) {
473
+ app.use(
474
+ (error: unknown, req: express.Request, res: express.Response, next: express.NextFunction) => {
475
+ if (!isStaleMastraResumeError(error)) {
476
+ next(error);
477
+ return;
478
+ }
479
+ logger.warn("ignored stale mastra resume", {
480
+ path: req.path,
481
+ error: errorUtils.errorMessage(error),
482
+ });
483
+ if (res.headersSent) {
484
+ res.end();
485
+ return;
486
+ }
487
+ res.status(200);
488
+ res.setHeader("content-type", "text/event-stream; charset=utf-8");
489
+ res.setHeader("cache-control", "no-cache");
490
+ res.write(`data: ${JSON.stringify({ type: "start" })}\n\n`);
491
+ res.write(`data: ${JSON.stringify({ type: "finish" })}\n\n`);
492
+ res.write("data: [DONE]\n\n");
483
493
  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
+ },
495
+ );
494
496
  }
@@ -2,7 +2,7 @@
2
2
  * Where Databricks Assistant `SKILL.md` trees live.
3
3
  *
4
4
  * Two modules need these paths and must agree on them: `workspaces.ts` MOUNTS
5
- * them per request (see `DEFAULT_SKILL_FOLDERS`), and `remote-skills.ts`
5
+ * them per request (see `DEFAULT_DATABRICKS_WORKSPACE_PATHS`), and `remote-skills.ts`
6
6
  * WRITES provisioned skills into them at startup. They live here rather than being
7
7
  * spelled out in both, where a change to one would silently provision skills into a
8
8
  * tree the other never scanned.