@dbx-tools/appkit-mastra 0.9.106 → 0.9.110

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,29 +34,31 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@databricks/appkit": "0.81.0",
37
- "@dbx-tools/appkit": "^0.9.106",
38
- "@dbx-tools/core": "^0.9.106",
39
- "@dbx-tools/databricks": "^0.9.106",
40
- "@dbx-tools/fs": "^0.9.106",
41
- "@dbx-tools/genie": "^0.9.106",
42
- "@dbx-tools/model": "^0.9.106",
43
- "@dbx-tools/model-protocol": "^0.9.106",
44
- "@dbx-tools/path": "^0.9.106",
45
- "@dbx-tools/postgres": "^0.9.106",
46
- "@dbx-tools/shared-core": "^0.9.106",
47
- "@dbx-tools/shared-fs": "^0.9.106",
48
- "@dbx-tools/shared-genie": "^0.9.106",
49
- "@dbx-tools/shared-mastra": "^0.9.106",
50
- "@dbx-tools/shared-model": "^0.9.106",
37
+ "@dbx-tools/appkit": "^0.9.110",
38
+ "@dbx-tools/core": "^0.9.110",
39
+ "@dbx-tools/databricks": "^0.9.110",
40
+ "@dbx-tools/fs": "^0.9.110",
41
+ "@dbx-tools/genie": "^0.9.110",
42
+ "@dbx-tools/model": "^0.9.110",
43
+ "@dbx-tools/model-protocol": "^0.9.110",
44
+ "@dbx-tools/path": "^0.9.110",
45
+ "@dbx-tools/postgres": "^0.9.110",
46
+ "@dbx-tools/shared-core": "^0.9.110",
47
+ "@dbx-tools/shared-fs": "^0.9.110",
48
+ "@dbx-tools/shared-genie": "^0.9.110",
49
+ "@dbx-tools/shared-mastra": "^0.9.110",
50
+ "@dbx-tools/shared-model": "^0.9.110",
51
51
  "@mastra/ai-sdk": "1.10.5",
52
52
  "@mastra/core": "1.71.0",
53
53
  "@mastra/express": "1.5.15",
54
54
  "@mastra/fastembed": "1.3.2",
55
+ "@mastra/isolated-vm": "0.1.2",
55
56
  "@mastra/mcp": "2.1.0",
56
57
  "@mastra/memory": "1.32.1",
57
58
  "@mastra/observability": "1.18.1",
58
59
  "@mastra/otel-bridge": "1.5.11",
59
60
  "@mastra/pg": "1.27.1",
61
+ "@mastra/quickjs": "0.1.3",
60
62
  "@modelcontextprotocol/sdk": "^1.29.0",
61
63
  "@opentelemetry/api": "^1.9.1",
62
64
  "@opentelemetry/core": "2.11.0",
@@ -217,7 +219,7 @@
217
219
  "./package.json": "./package.json"
218
220
  }
219
221
  },
220
- "version": "0.9.106",
222
+ "version": "0.9.110",
221
223
  "types": "./lib/index.d.ts",
222
224
  "dbxToolsConfig": {
223
225
  "tags": [
package/src/agents.ts CHANGED
@@ -38,21 +38,42 @@ import { createEventedAgent } from "@mastra/core/agent/durable";
38
38
  import { SkillSearchProcessor } from "@mastra/core/processors";
39
39
  import type { OutputProcessor } from "@mastra/core/processors";
40
40
  import { MASTRA_RESOURCE_ID_KEY } from "@mastra/core/request-context";
41
- import type { Tool } from "@mastra/core/tools";
42
- import { createTool } from "@mastra/core/tools";
41
+ import type { RequestContext } from "@mastra/core/request-context";
42
+ import type { CodeModeTransport, Tool } from "@mastra/core/tools";
43
+ import { createCodeMode, createTool } from "@mastra/core/tools";
43
44
  import type { Workspace } from "@mastra/core/workspace";
45
+ import { createWorkspaceTools } from "@mastra/core/workspace";
44
46
  import type { PgVectorConfig, PostgresStoreConfig } from "@mastra/pg";
47
+ import { QuickJsCodeModeTransport } from "@mastra/quickjs";
45
48
 
46
49
  import { buildRenderDataTool } from "./chart.ts";
47
50
  import type { MastraPluginConfig } from "./config.ts";
48
51
  import { buildGenieToolkitProvider, resolveGenieSpaces } from "./genie.ts";
49
- import type { MemoryBuilder } from "./memory.ts";
52
+ import { withRequestMemoryScope, type MemoryBuilder } from "./memory.ts";
50
53
  import { buildModel, RESPONSES_PROVIDER_OPTIONS } from "./model.ts";
51
54
  import { stripStaleChartsProcessor } from "./processors.ts";
52
55
  import { MASTRA_RESOLVED_MODEL_KEY } from "./serving.ts";
53
56
  import { TYPOGRAPHY_RULE } from "./style.ts";
54
57
  import { buildSummarizeTool } from "./summarize.ts";
55
- import { bindDatabricksWorkspaceContext, databricksWorkspace } from "./workspaces.ts";
58
+ import {
59
+ bindDatabricksWorkspaceContext,
60
+ databricksWorkspace,
61
+ type DatabricksWorkspaceOptions,
62
+ } from "./workspaces.ts";
63
+
64
+ const codeModeLogger = log.logger("mastra/code-mode");
65
+ let resolvedCodeModeTransport: Promise<CodeModeTransport> | undefined;
66
+
67
+ /** Return whether this boot environment matches isolated-vm's supported app shape. */
68
+ function supportsIsolatedVmTransport(): boolean {
69
+ if (process.versions.bun || process.release.name !== "node" || process.platform !== "linux") {
70
+ return false;
71
+ }
72
+ const nodeMajor = Number.parseInt(process.versions.node.split(".")[0] ?? "", 10);
73
+ if (!Number.isFinite(nodeMajor) || nodeMajor < 20 || nodeMajor >= 25) return false;
74
+ const nodeOptions = process.env.NODE_OPTIONS?.split(/\s+/) ?? [];
75
+ return [...process.execArgv, ...nodeOptions].includes("--no-node-snapshot");
76
+ }
56
77
 
57
78
  /**
58
79
  * Tool record accepted by every Mastra `Agent.tools` field and by the
@@ -169,8 +190,9 @@ function deriveToolId(description: string): string {
169
190
  * ```
170
191
  *
171
192
  * Adds the package's default workspace when the definition omits one. That
172
- * workspace carries Databricks skill mounts and Monty command execution. An
173
- * explicit workspace remains the caller's complete override.
193
+ * workspace carries Databricks skill mounts while command execution stays
194
+ * disabled until a sandbox is selected explicitly. An explicit workspace
195
+ * remains the caller's complete override.
174
196
  */
175
197
  export function createAgent<
176
198
  TRequestContext extends Record<string, unknown> | unknown = unknown,
@@ -186,7 +208,7 @@ export function createAgent<
186
208
  /**
187
209
  * Brand for a {@link Workspace} that `createAgent` built with no caller
188
210
  * options, so {@link buildAgents} may rebuild it with startup-provisioned
189
- * `extraSkillPaths` (a caller-supplied workspace is never touched).
211
+ * `extraSkillMounts` (a caller-supplied workspace is never touched).
190
212
  */
191
213
  const defaultWorkspaces = new WeakSet<Workspace>();
192
214
 
@@ -529,22 +551,114 @@ function appendDefaultInstructions(
529
551
  function composeInstructions<TRequestContext extends Record<string, unknown> | unknown>(
530
552
  agentInstructions: AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"],
531
553
  style: string | null,
554
+ resolveCodeMode?: CodeModeResolver<TRequestContext>,
532
555
  ): AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"] {
533
- if (typeof agentInstructions !== "function") {
534
- return appendDefaultInstructions(agentInstructions, style) as AgentConfig<
556
+ const append = (instructions: AgentInstructions, codeModeInstructions?: string) => {
557
+ const composed = appendDefaultInstructions(instructions, style);
558
+ return codeModeInstructions ? appendInstructionBlock(composed, codeModeInstructions) : composed;
559
+ };
560
+ if (typeof agentInstructions !== "function" && !resolveCodeMode) {
561
+ return append(agentInstructions) as AgentConfig<
535
562
  string,
536
563
  ToolsInput,
537
564
  undefined,
538
565
  TRequestContext
539
566
  >["instructions"];
540
567
  }
541
- return (async (args) =>
542
- appendDefaultInstructions(await agentInstructions(args), style)) as AgentConfig<
543
- string,
544
- ToolsInput,
545
- undefined,
546
- TRequestContext
547
- >["instructions"];
568
+ return (async (args) => {
569
+ const [instructions, codeMode] = await Promise.all([
570
+ typeof agentInstructions === "function" ? agentInstructions(args) : agentInstructions,
571
+ resolveCodeMode?.(args),
572
+ ]);
573
+ return append(instructions, codeMode?.instructions);
574
+ }) as AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"];
575
+ }
576
+
577
+ /** Append one system instruction block while preserving Mastra's accepted shapes. */
578
+ function appendInstructionBlock(instructions: AgentInstructions, block: string): AgentInstructions {
579
+ if (typeof instructions === "string") return `${instructions.trimEnd()}\n\n${block}`;
580
+ if (Array.isArray(instructions)) {
581
+ if (instructions.every((instruction) => typeof instruction === "string")) {
582
+ return [...instructions, block] as AgentInstructions;
583
+ }
584
+ return [...instructions, { role: "system", content: block }] as AgentInstructions;
585
+ }
586
+ return [instructions, { role: "system", content: block }] as AgentInstructions;
587
+ }
588
+
589
+ /** Resolve one native Code Mode transport during plugin startup. */
590
+ function codeModeTransport(): Promise<CodeModeTransport> {
591
+ resolvedCodeModeTransport ??= (async () => {
592
+ if (!supportsIsolatedVmTransport()) {
593
+ codeModeLogger.info("transport selected", { provider: "quickjs" });
594
+ return new QuickJsCodeModeTransport();
595
+ }
596
+ try {
597
+ const { IsolatedVmCodeModeTransport } = await import("@mastra/isolated-vm");
598
+ const transport = new IsolatedVmCodeModeTransport();
599
+ codeModeLogger.info("transport selected", { provider: "isolated-vm" });
600
+ return transport;
601
+ } catch (caught) {
602
+ codeModeLogger.warn("isolated-vm unavailable; using QuickJS", {
603
+ error: errorUtils.errorMessage(caught),
604
+ });
605
+ return new QuickJsCodeModeTransport();
606
+ }
607
+ })();
608
+ return resolvedCodeModeTransport;
609
+ }
610
+
611
+ type CodeModeResolver<TRequestContext extends Record<string, unknown> | unknown = unknown> = (
612
+ args: Parameters<
613
+ Exclude<
614
+ AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"],
615
+ AgentInstructions
616
+ >
617
+ >[0],
618
+ ) => Promise<ReturnType<typeof createCodeMode> | undefined>;
619
+
620
+ /** Build request-scoped native Code Mode over all executable context tools. */
621
+ async function buildCodeMode<TRequestContext extends Record<string, unknown> | unknown>(
622
+ config: MastraPluginConfig,
623
+ tools: MastraTools,
624
+ workspace: Workspace | undefined,
625
+ requestContext: RequestContext<TRequestContext>,
626
+ ): Promise<ReturnType<typeof createCodeMode> | undefined> {
627
+ if (config.codeMode === false) return undefined;
628
+ const workspaceTools = workspace
629
+ ? await createWorkspaceTools(workspace, { requestContext, workspace })
630
+ : {};
631
+ const contextTools = { ...tools, ...workspaceTools };
632
+ const executableTools = Object.fromEntries(
633
+ Object.entries(contextTools).filter(
634
+ ([, tool]) =>
635
+ typeof tool === "object" &&
636
+ tool !== null &&
637
+ "execute" in tool &&
638
+ typeof tool.execute === "function",
639
+ ),
640
+ ) as ToolsInput;
641
+ if (Object.keys(executableTools).length === 0) return undefined;
642
+ const options = typeof config.codeMode === "object" ? config.codeMode : {};
643
+ const codeMode = createCodeMode(
644
+ { tools: executableTools, ...options },
645
+ await codeModeTransport(),
646
+ );
647
+ if (!("mastra_workspace_read_file" in workspaceTools)) return codeMode;
648
+ return {
649
+ ...codeMode,
650
+ instructions: `${codeMode.instructions}\n\nWorkspace file content note:\nText returned by external_mastra_workspace_read_file starts with one metadata line containing the path and size. Exclude that first line before calculating content character counts, hashes, or other content-only values.`,
651
+ };
652
+ }
653
+
654
+ /** Resolve Code Mode lazily so workspace and dynamic tool policy follow each request. */
655
+ function codeModeResolver<TRequestContext extends Record<string, unknown> | unknown>(
656
+ config: MastraPluginConfig,
657
+ tools: MastraTools,
658
+ workspace: Workspace | undefined,
659
+ ): CodeModeResolver<TRequestContext> | undefined {
660
+ if (config.codeMode === false) return undefined;
661
+ return ({ requestContext }) => buildCodeMode(config, tools, workspace, requestContext);
548
662
  }
549
663
 
550
664
  /**
@@ -580,9 +694,9 @@ export async function buildAgents(opts: {
580
694
  * startup) folded into every agent that uses the auto-created default
581
695
  * workspace.
582
696
  */
583
- extraSkillPaths?: string[];
697
+ extraSkillMounts?: DatabricksWorkspaceOptions["extraSkillMounts"];
584
698
  }): Promise<BuiltAgents> {
585
- const { config, context, memoryBuilder, log, extraSkillPaths } = opts;
699
+ const { config, context, memoryBuilder, log, extraSkillMounts } = opts;
586
700
  const definitions = resolveDefinitions(config);
587
701
  const ids = Object.keys(definitions);
588
702
  const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
@@ -592,8 +706,8 @@ export async function buildAgents(opts: {
592
706
  // `render_data` for inline visualizations and `summarize` for
593
707
  // offloading text condensing to the fast / small chat tier. The
594
708
  // user can shadow either by including a same-named tool in their own
595
- // `config.tools` or per-agent `tools`. Order in {@link resolveTools}
596
- // is `system -> user-ambient -> per-agent`, last write wins.
709
+ // `config.tools` or per-agent `tools`. Merge order is
710
+ // `system -> user-ambient -> per-agent`, last write wins.
597
711
  const systemTools: MastraTools = {
598
712
  render_data: buildRenderDataTool(config),
599
713
  summarize: buildSummarizeTool(config),
@@ -615,18 +729,21 @@ export async function buildAgents(opts: {
615
729
  const approvalGatedByAgent: Array<{ agentId: string; toolIds: string[] }> = [];
616
730
 
617
731
  for (const [id, def] of Object.entries(definitions)) {
618
- const tools = await resolveTools(def.tools, plugins, ambientTools);
732
+ const userTools = await resolveUserTools(def.tools, plugins);
733
+ const tools = { ...ambientTools, ...userTools };
619
734
  let workspace = resolveAgentWorkspace(def.workspace);
620
735
  if (
621
736
  (def.workspace === undefined && !workspace) ||
622
- ((extraSkillPaths?.length ||
737
+ ((extraSkillMounts?.length ||
623
738
  config.sandbox !== undefined ||
739
+ config.workspaceFallbackToTmp !== undefined ||
624
740
  config.workspaceTools !== undefined ||
625
741
  context !== undefined) &&
626
742
  isDefaultWorkspace(workspace))
627
743
  ) {
628
744
  workspace = databricksWorkspace({
629
- extraSkillPaths,
745
+ extraSkillMounts,
746
+ fallbackToTmp: config.workspaceFallbackToTmp,
630
747
  ...(config.workspaceTools !== undefined ? { tools: config.workspaceTools } : {}),
631
748
  pluginContext: context,
632
749
  sandbox: config.sandbox === true ? "databricks" : config.sandbox,
@@ -638,6 +755,7 @@ export async function buildAgents(opts: {
638
755
  const gated = approvalGatedToolIds(tools);
639
756
  if (gated.length > 0) approvalGatedByAgent.push({ agentId: id, toolIds: gated });
640
757
  const memory = memoryBuilder?.forAgent(id, def);
758
+ const resolveCodeMode = codeModeResolver(config, tools, workspace);
641
759
  const agent = new Agent({
642
760
  id,
643
761
  name: def.name ?? id,
@@ -646,17 +764,26 @@ export async function buildAgents(opts: {
646
764
  // metadata. Fall back to a generated one when the definition
647
765
  // omits it.
648
766
  description: def.description?.trim() || defaultAgentDescription(def.name ?? id),
649
- instructions: composeInstructions(def.instructions, style),
767
+ instructions: composeInstructions(def.instructions, style, resolveCodeMode),
650
768
  ...(def.requestContextSchema ? { requestContextSchema: def.requestContextSchema } : {}),
651
769
  model: resolveModel(config, def.model),
652
- defaultOptions: {
653
- maxSteps: config.agentMaxSteps ?? DEFAULT_AGENT_MAX_STEPS,
654
- providerOptions: RESPONSES_PROVIDER_OPTIONS,
655
- ...(def.requireToolApproval !== undefined
656
- ? { requireToolApproval: def.requireToolApproval }
657
- : {}),
658
- },
659
- tools,
770
+ defaultOptions: ({ requestContext }) =>
771
+ withRequestMemoryScope(
772
+ {
773
+ maxSteps: config.agentMaxSteps ?? DEFAULT_AGENT_MAX_STEPS,
774
+ providerOptions: RESPONSES_PROVIDER_OPTIONS,
775
+ ...(def.requireToolApproval !== undefined
776
+ ? { requireToolApproval: def.requireToolApproval }
777
+ : {}),
778
+ },
779
+ memory ? requestContext : undefined,
780
+ ),
781
+ tools: resolveCodeMode
782
+ ? async (args) => {
783
+ const codeMode = await resolveCodeMode(args);
784
+ return codeMode ? { ...tools, [codeMode.tool.id]: codeMode.tool } : tools;
785
+ }
786
+ : tools,
660
787
  ...(memory ? { memory } : {}),
661
788
  ...(workspace ? { workspace } : {}),
662
789
  inputProcessors: [...inputProcessors, ...workspaceSkillInputProcessors(workspace, config)],
@@ -679,7 +806,7 @@ export async function buildAgents(opts: {
679
806
  name: def.name ?? id,
680
807
  defaultModel:
681
808
  defaultModel.kind === "configured" ? defaultModel.model : `<${defaultModel.kind}>`,
682
- tools: Object.keys(tools),
809
+ tools: [...Object.keys(tools), ...(resolveCodeMode ? ["<dynamic-code-mode>"] : [])],
683
810
  });
684
811
  }
685
812
 
@@ -909,19 +1036,16 @@ function resolveModel(
909
1036
  }
910
1037
 
911
1038
  /**
912
- * Resolve a definition's `tools` field to a flat `MastraTools` record,
913
- * merging in plugin-level ambient tools (per-agent tools win on key
914
- * collision). Callback errors propagate verbatim so the original stack
915
- * survives - the caller already knows which agent was registering.
1039
+ * Resolve only the tools explicitly supplied by one agent definition.
1040
+ * Callback errors propagate verbatim so the original stack survives - the
1041
+ * caller already knows which agent was registering.
916
1042
  */
917
- async function resolveTools(
1043
+ async function resolveUserTools(
918
1044
  defTools: AnyMastraAgentDefinition["tools"],
919
1045
  plugins: MastraPlugins,
920
- ambientTools: MastraTools,
921
1046
  ): Promise<MastraTools> {
922
- if (!defTools) return { ...ambientTools };
923
- const resolved = typeof defTools === "function" ? await defTools(plugins) : defTools;
924
- return { ...ambientTools, ...resolved };
1047
+ if (!defTools) return {};
1048
+ return typeof defTools === "function" ? defTools(plugins) : defTools;
925
1049
  }
926
1050
 
927
1051
  function resolveAgentWorkspace(
package/src/chat.ts CHANGED
@@ -15,6 +15,8 @@ import { isEventedAgent } from "@mastra/core/agent/durable";
15
15
  import { registerApiRoute } from "@mastra/core/server";
16
16
  import { createUIMessageStreamResponse } from "ai";
17
17
 
18
+ import { withRequestMemoryScope } from "./memory.ts";
19
+
18
20
  const logger = log.logger("mastra/chat");
19
21
 
20
22
  /** Client request cancellation is detached only for evented background agents. */
@@ -62,11 +64,14 @@ export function agentChatRoutes() {
62
64
  : status
63
65
  ? { agentVersion: { status } }
64
66
  : {}),
65
- params: {
66
- ...params,
67
+ params: withRequestMemoryScope(
68
+ {
69
+ ...params,
70
+ requestContext,
71
+ ...(abortSignal ? { abortSignal } : {}),
72
+ },
67
73
  requestContext,
68
- ...(abortSignal ? { abortSignal } : {}),
69
- },
74
+ ),
70
75
  version: "v7",
71
76
  sendReasoning: true,
72
77
  sendSources: true,
package/src/config.ts CHANGED
@@ -158,6 +158,14 @@ export interface MastraWorkspaceSkillsConfig {
158
158
  ttlMs?: number;
159
159
  }
160
160
 
161
+ /** Native Mastra Code Mode settings for sandboxed multi-tool orchestration. */
162
+ export interface MastraCodeModeConfig {
163
+ /** Generated orchestration tool id. Defaults to `execute_typescript`. */
164
+ id?: string;
165
+ /** Maximum orchestration program runtime in milliseconds. Defaults to 30 seconds. */
166
+ timeout?: number;
167
+ }
168
+
161
169
  /**
162
170
  * Fine-grained control for the optional MCP server exposure
163
171
  * ({@link MastraPluginConfig.mcp}). Every field is optional; the object
@@ -218,12 +226,22 @@ export interface MastraPluginConfig extends BasePluginConfig {
218
226
  */
219
227
  memory?: boolean | MastraMemoryConfig;
220
228
  /**
221
- * Sandbox for auto-created agent workspaces. Defaults to Monty. `true`,
222
- * `"databricks"`, or an object selects/configures Databricks Sandbox, and
223
- * `false` disables workspace command execution. An agent with an explicit
224
- * custom `workspace` keeps that workspace and its sandbox.
229
+ * Expose executable tools from each agent definition through native Mastra
230
+ * Code Mode. Defaults on whenever the agent has executable tools. The plugin
231
+ * selects Mastra's isolated-vm transport once during startup and falls back
232
+ * to Mastra QuickJS when the native transport is unavailable. Set `false` to
233
+ * opt out.
234
+ */
235
+ codeMode?: boolean | MastraCodeModeConfig;
236
+ /**
237
+ * Sandbox for auto-created agent workspaces. Disabled by default. `"monty"`
238
+ * selects Monty; `true`, `"databricks"`, or an object selects/configures
239
+ * Databricks Sandbox. An agent with an explicit custom `workspace` keeps that
240
+ * workspace and its sandbox.
225
241
  */
226
242
  sandbox?: boolean | "databricks" | "monty" | DatabricksWorkspaceSandboxOptions;
243
+ /** Add user-scoped `/tmp` only when no configured workspace path mounts writable. */
244
+ workspaceFallbackToTmp?: boolean;
227
245
  /** Native Mastra workspace tool availability, approval, and hook configuration. */
228
246
  workspaceTools?: WorkspaceToolsConfig;
229
247
  /**
@@ -659,7 +677,7 @@ export const MASTRA_CONFIG_SCHEMA: ConfigSchema = {
659
677
  remoteSkills: {
660
678
  type: ["string", "array", "object"],
661
679
  description:
662
- 'Remote Agent-Skill sources provisioned at startup: "aitools" for Databricks\' own skill set (read from the public databricks/databricks-agent-skills repo, no CLI needed), a GitHub owner/repo, a git/GitLab URL, or a direct SKILL.md/archive URL. Non-aitools sources prefer the optional `skills` npm CLI, else a direct fetch; fails startup on error unless failOnError:false. Written to the Databricks user Assistant skills folder, or a local temp dir when no workspace is writable.',
680
+ 'Remote Agent-Skill sources provisioned at startup: "aitools" for Databricks\' own skill set (read from the public databricks/databricks-agent-skills repo, no CLI needed), a GitHub owner/repo, a git/GitLab URL, or a direct SKILL.md/archive URL. Non-aitools sources prefer the optional `skills` npm CLI, else a direct fetch; fails startup on error unless failOnError:false. Written to the Databricks user Assistant skills folder, or read-only local backing storage exposed at stable virtual workspace mounts.',
663
681
  },
664
682
  storage: {
665
683
  type: ["boolean", "object"],
@@ -671,10 +689,20 @@ export const MASTRA_CONFIG_SCHEMA: ConfigSchema = {
671
689
  description:
672
690
  "PgVector store for Mastra semantic recall. `true` reuses the `lakebase` plugin's pool, an object opens a dedicated store. Auto-enabled when the `lakebase` plugin is registered.",
673
691
  },
692
+ codeMode: {
693
+ type: ["boolean", "object"],
694
+ description:
695
+ "Expose all executable tools available to the current request, including native workspace tools, through dynamically generated Mastra Code Mode for sandboxed TypeScript batching, aggregation, and arithmetic. The plugin selects Mastra isolated-vm once during startup and falls back to Mastra QuickJS when native initialization is unavailable. False disables it.",
696
+ },
674
697
  sandbox: {
675
698
  type: ["boolean", "string", "object"],
676
699
  description:
677
- '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.',
700
+ 'Command sandbox for auto-created agent workspaces. Disabled by default. "monty" selects Monty; true, "databricks", or an object selects/configures Databricks Sandbox.',
701
+ },
702
+ workspaceFallbackToTmp: {
703
+ type: "boolean",
704
+ description:
705
+ "Add user-scoped /tmp to auto-created agent workspaces only when no configured Databricks path mounts writable. Defaults to false.",
678
706
  },
679
707
  workspaceSkills: {
680
708
  type: ["boolean", "object"],
package/src/memory.ts CHANGED
@@ -36,6 +36,12 @@ import { getUsernameWithApiLookup } from "@databricks/appkit";
36
36
  import { migration as appkitMigration } from "@dbx-tools/appkit";
37
37
  import { postgresConnectionOptions } from "@dbx-tools/postgres";
38
38
  import { hash, log } from "@dbx-tools/shared-core";
39
+ import type { AgentMemoryOption } from "@mastra/core/agent";
40
+ import {
41
+ MASTRA_RESOURCE_ID_KEY,
42
+ MASTRA_THREAD_ID_KEY,
43
+ type RequestContext,
44
+ } from "@mastra/core/request-context";
39
45
  import { fastembed } from "@mastra/fastembed";
40
46
  import { Memory } from "@mastra/memory";
41
47
  import { PgVector, PostgresStore } from "@mastra/pg";
@@ -48,6 +54,33 @@ import { summaryModel, TITLE_INSTRUCTIONS } from "./summarize.ts";
48
54
 
49
55
  const logger = log.logger("mastra/memory");
50
56
 
57
+ /** Resolve the trusted Mastra memory scope stamped by AppKit middleware. */
58
+ export function requestMemoryScope(
59
+ requestContext: Pick<RequestContext, "get"> | undefined,
60
+ ): AgentMemoryOption | undefined {
61
+ const threadId = requestContext?.get(MASTRA_THREAD_ID_KEY);
62
+ const resourceId = requestContext?.get(MASTRA_RESOURCE_ID_KEY);
63
+ if (typeof threadId !== "string" || typeof resourceId !== "string") return undefined;
64
+ return { thread: threadId, resource: resourceId };
65
+ }
66
+
67
+ /** Overlay trusted request memory identifiers onto Mastra execution options. */
68
+ export function withRequestMemoryScope<T extends object>(
69
+ options: T,
70
+ requestContext: Pick<RequestContext, "get"> | undefined,
71
+ ): T & { memory?: AgentMemoryOption } {
72
+ const scope = requestMemoryScope(requestContext);
73
+ if (!scope) return options;
74
+ const memory = (options as { memory?: AgentMemoryOption }).memory;
75
+ return {
76
+ ...options,
77
+ memory: {
78
+ ...memory,
79
+ ...scope,
80
+ },
81
+ };
82
+ }
83
+
51
84
  /**
52
85
  * Soften {@link PostgresStore.init} so a failed migration (e.g. Lakebase
53
86
  * `must be owner of table …` on `ALTER`) is logged once instead of rethrown
package/src/plugin.ts CHANGED
@@ -1110,14 +1110,14 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
1110
1110
  // Materialize any remote Agent-Skill sources ONCE at startup. Runs
1111
1111
  // outside a request scope, so it uses the app service principal's client
1112
1112
  // and defaults to the shared workspace Assistant skills tree; a source
1113
- // that lands on a local temp dir (no writable workspace) is folded into
1114
- // every default-workspace agent via `extraSkillPaths`.
1113
+ // backed by local temp storage (no writable workspace) is folded into
1114
+ // every default-workspace agent via `extraSkillMounts`.
1115
1115
  const provisioned = await provisionRemoteSkills(this.config.remoteSkills);
1116
1116
  if (provisioned.skillNames.length > 0) {
1117
1117
  this.logger.info("remote skills configured", {
1118
1118
  skills: provisioned.skillNames,
1119
1119
  databricksBasePath: provisioned.databricksBasePath,
1120
- localSkillPaths: provisioned.localSkillPaths.length,
1120
+ localSkillMounts: provisioned.localSkillMounts.length,
1121
1121
  });
1122
1122
  }
1123
1123
 
@@ -1126,7 +1126,7 @@ export class MastraPlugin extends Plugin<MastraPluginConfig> {
1126
1126
  context: this.context,
1127
1127
  memoryBuilder,
1128
1128
  log: this.logger,
1129
- extraSkillPaths: provisioned.localSkillPaths,
1129
+ extraSkillMounts: provisioned.localSkillMounts,
1130
1130
  });
1131
1131
 
1132
1132
  // `mastra.server.apiRoutes` is only honored by Mastra's standalone