@dbx-tools/appkit-mastra 0.9.108 → 0.9.111
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 +40 -14
- package/index.ts +5 -5
- package/lib/index.d.ts +5 -5
- package/lib/index.js +4 -4
- package/lib/src/agents.d.ts +8 -4
- package/lib/src/agents.js +139 -30
- package/lib/src/chat.js +4 -3
- package/lib/src/config.d.ts +21 -4
- package/lib/src/config.js +11 -3
- package/lib/src/memory.d.ts +8 -0
- package/lib/src/memory.js +24 -1
- package/lib/src/plugin.js +5 -5
- package/lib/src/remote-skills.d.ts +22 -9
- package/lib/src/remote-skills.js +54 -13
- package/lib/src/sandbox.d.ts +2 -1
- package/lib/src/sandbox.js +2 -2
- package/lib/src/workspaces.d.ts +14 -11
- package/lib/src/workspaces.js +31 -18
- package/package.json +17 -15
- package/src/agents.ts +182 -42
- package/src/chat.ts +9 -4
- package/src/config.ts +34 -6
- package/src/memory.ts +33 -0
- package/src/plugin.ts +4 -4
- package/src/remote-skills.ts +74 -16
- package/src/sandbox.ts +3 -2
- package/src/workspaces.ts +46 -25
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 {
|
|
42
|
-
import {
|
|
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
|
|
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 {
|
|
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
|
|
173
|
-
*
|
|
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
|
-
* `
|
|
211
|
+
* `extraSkillMounts` (a caller-supplied workspace is never touched).
|
|
190
212
|
*/
|
|
191
213
|
const defaultWorkspaces = new WeakSet<Workspace>();
|
|
192
214
|
|
|
@@ -464,6 +486,17 @@ export const DEFAULT_TOOL_WORKFLOW_INSTRUCTIONS = [
|
|
|
464
486
|
"Keep calls sequential when a later input depends on an earlier result or when calls mutate the same resource.",
|
|
465
487
|
].join("\n");
|
|
466
488
|
|
|
489
|
+
/** Hybrid routing guidance appended after Mastra's generated Code Mode contract. */
|
|
490
|
+
export const CODE_MODE_ROUTING_INSTRUCTIONS = [
|
|
491
|
+
"Tool routing:",
|
|
492
|
+
"The Code Mode contract above explains how to use execute_typescript when selected; it does not require using Code Mode for every tool call.",
|
|
493
|
+
"Call a directly exposed tool directly when one ordinary call is sufficient.",
|
|
494
|
+
"Call independent tools directly in parallel when their results do not require code-side transformation.",
|
|
495
|
+
"Keep dependent calls as direct sequential tool calls when code-side transformation is unnecessary.",
|
|
496
|
+
"Use execute_typescript when the user explicitly requests Code Mode or when code is useful for loops, filtering, joins, random selection, aggregation, arithmetic, dynamic fan-out, or keeping substantial intermediate results out of model context.",
|
|
497
|
+
"Do not wrap a single ordinary tool call in execute_typescript.",
|
|
498
|
+
].join("\n");
|
|
499
|
+
|
|
467
500
|
/**
|
|
468
501
|
* Style guardrails appended to every agent's `instructions` to curb
|
|
469
502
|
* common LLM-isms (em dashes, emojis, sycophantic openers, excessive
|
|
@@ -529,22 +562,119 @@ function appendDefaultInstructions(
|
|
|
529
562
|
function composeInstructions<TRequestContext extends Record<string, unknown> | unknown>(
|
|
530
563
|
agentInstructions: AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"],
|
|
531
564
|
style: string | null,
|
|
565
|
+
resolveCodeMode?: CodeModeResolver<TRequestContext>,
|
|
532
566
|
): AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"] {
|
|
533
|
-
|
|
534
|
-
|
|
567
|
+
const append = (instructions: AgentInstructions, codeModeInstructions?: string) => {
|
|
568
|
+
const composed = appendDefaultInstructions(instructions, style);
|
|
569
|
+
return codeModeInstructions
|
|
570
|
+
? appendInstructionBlock(
|
|
571
|
+
composed,
|
|
572
|
+
`${codeModeInstructions}\n\n${CODE_MODE_ROUTING_INSTRUCTIONS}`,
|
|
573
|
+
)
|
|
574
|
+
: composed;
|
|
575
|
+
};
|
|
576
|
+
if (typeof agentInstructions !== "function" && !resolveCodeMode) {
|
|
577
|
+
return append(agentInstructions) as AgentConfig<
|
|
535
578
|
string,
|
|
536
579
|
ToolsInput,
|
|
537
580
|
undefined,
|
|
538
581
|
TRequestContext
|
|
539
582
|
>["instructions"];
|
|
540
583
|
}
|
|
541
|
-
return (async (args) =>
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
>["instructions"];
|
|
584
|
+
return (async (args) => {
|
|
585
|
+
const [instructions, codeMode] = await Promise.all([
|
|
586
|
+
typeof agentInstructions === "function" ? agentInstructions(args) : agentInstructions,
|
|
587
|
+
resolveCodeMode?.(args),
|
|
588
|
+
]);
|
|
589
|
+
return append(instructions, codeMode?.instructions);
|
|
590
|
+
}) as AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"];
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/** Append one system instruction block while preserving Mastra's accepted shapes. */
|
|
594
|
+
function appendInstructionBlock(instructions: AgentInstructions, block: string): AgentInstructions {
|
|
595
|
+
if (typeof instructions === "string") return `${instructions.trimEnd()}\n\n${block}`;
|
|
596
|
+
if (Array.isArray(instructions)) {
|
|
597
|
+
if (instructions.every((instruction) => typeof instruction === "string")) {
|
|
598
|
+
return [...instructions, block] as AgentInstructions;
|
|
599
|
+
}
|
|
600
|
+
return [...instructions, { role: "system", content: block }] as AgentInstructions;
|
|
601
|
+
}
|
|
602
|
+
return [instructions, { role: "system", content: block }] as AgentInstructions;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/** Resolve one native Code Mode transport during plugin startup. */
|
|
606
|
+
function codeModeTransport(): Promise<CodeModeTransport> {
|
|
607
|
+
resolvedCodeModeTransport ??= (async () => {
|
|
608
|
+
if (!supportsIsolatedVmTransport()) {
|
|
609
|
+
codeModeLogger.info("transport selected", { provider: "quickjs" });
|
|
610
|
+
return new QuickJsCodeModeTransport();
|
|
611
|
+
}
|
|
612
|
+
try {
|
|
613
|
+
const { IsolatedVmCodeModeTransport } = await import("@mastra/isolated-vm");
|
|
614
|
+
const transport = new IsolatedVmCodeModeTransport();
|
|
615
|
+
codeModeLogger.info("transport selected", { provider: "isolated-vm" });
|
|
616
|
+
return transport;
|
|
617
|
+
} catch (caught) {
|
|
618
|
+
codeModeLogger.warn("isolated-vm unavailable; using QuickJS", {
|
|
619
|
+
error: errorUtils.errorMessage(caught),
|
|
620
|
+
});
|
|
621
|
+
return new QuickJsCodeModeTransport();
|
|
622
|
+
}
|
|
623
|
+
})();
|
|
624
|
+
return resolvedCodeModeTransport;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
type CodeModeResolver<TRequestContext extends Record<string, unknown> | unknown = unknown> = (
|
|
628
|
+
args: Parameters<
|
|
629
|
+
Exclude<
|
|
630
|
+
AgentConfig<string, ToolsInput, undefined, TRequestContext>["instructions"],
|
|
631
|
+
AgentInstructions
|
|
632
|
+
>
|
|
633
|
+
>[0],
|
|
634
|
+
) => Promise<ReturnType<typeof createCodeMode> | undefined>;
|
|
635
|
+
|
|
636
|
+
/** Build request-scoped native Code Mode over all executable context tools. */
|
|
637
|
+
async function buildCodeMode<TRequestContext extends Record<string, unknown> | unknown>(
|
|
638
|
+
config: MastraPluginConfig,
|
|
639
|
+
tools: MastraTools,
|
|
640
|
+
workspace: Workspace | undefined,
|
|
641
|
+
requestContext: RequestContext<TRequestContext>,
|
|
642
|
+
): Promise<ReturnType<typeof createCodeMode> | undefined> {
|
|
643
|
+
if (config.codeMode === false) return undefined;
|
|
644
|
+
const workspaceTools = workspace
|
|
645
|
+
? await createWorkspaceTools(workspace, { requestContext, workspace })
|
|
646
|
+
: {};
|
|
647
|
+
const contextTools = { ...tools, ...workspaceTools };
|
|
648
|
+
const executableTools = Object.fromEntries(
|
|
649
|
+
Object.entries(contextTools).filter(
|
|
650
|
+
([, tool]) =>
|
|
651
|
+
typeof tool === "object" &&
|
|
652
|
+
tool !== null &&
|
|
653
|
+
"execute" in tool &&
|
|
654
|
+
typeof tool.execute === "function",
|
|
655
|
+
),
|
|
656
|
+
) as ToolsInput;
|
|
657
|
+
if (Object.keys(executableTools).length === 0) return undefined;
|
|
658
|
+
const options = typeof config.codeMode === "object" ? config.codeMode : {};
|
|
659
|
+
const codeMode = createCodeMode(
|
|
660
|
+
{ tools: executableTools, ...options },
|
|
661
|
+
await codeModeTransport(),
|
|
662
|
+
);
|
|
663
|
+
if (!("mastra_workspace_read_file" in workspaceTools)) return codeMode;
|
|
664
|
+
return {
|
|
665
|
+
...codeMode,
|
|
666
|
+
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.`,
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/** Resolve Code Mode lazily so workspace and dynamic tool policy follow each request. */
|
|
671
|
+
function codeModeResolver<TRequestContext extends Record<string, unknown> | unknown>(
|
|
672
|
+
config: MastraPluginConfig,
|
|
673
|
+
tools: MastraTools,
|
|
674
|
+
workspace: Workspace | undefined,
|
|
675
|
+
): CodeModeResolver<TRequestContext> | undefined {
|
|
676
|
+
if (config.codeMode === false) return undefined;
|
|
677
|
+
return ({ requestContext }) => buildCodeMode(config, tools, workspace, requestContext);
|
|
548
678
|
}
|
|
549
679
|
|
|
550
680
|
/**
|
|
@@ -580,9 +710,9 @@ export async function buildAgents(opts: {
|
|
|
580
710
|
* startup) folded into every agent that uses the auto-created default
|
|
581
711
|
* workspace.
|
|
582
712
|
*/
|
|
583
|
-
|
|
713
|
+
extraSkillMounts?: DatabricksWorkspaceOptions["extraSkillMounts"];
|
|
584
714
|
}): Promise<BuiltAgents> {
|
|
585
|
-
const { config, context, memoryBuilder, log,
|
|
715
|
+
const { config, context, memoryBuilder, log, extraSkillMounts } = opts;
|
|
586
716
|
const definitions = resolveDefinitions(config);
|
|
587
717
|
const ids = Object.keys(definitions);
|
|
588
718
|
const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
|
|
@@ -592,8 +722,8 @@ export async function buildAgents(opts: {
|
|
|
592
722
|
// `render_data` for inline visualizations and `summarize` for
|
|
593
723
|
// offloading text condensing to the fast / small chat tier. The
|
|
594
724
|
// user can shadow either by including a same-named tool in their own
|
|
595
|
-
// `config.tools` or per-agent `tools`.
|
|
596
|
-
//
|
|
725
|
+
// `config.tools` or per-agent `tools`. Merge order is
|
|
726
|
+
// `system -> user-ambient -> per-agent`, last write wins.
|
|
597
727
|
const systemTools: MastraTools = {
|
|
598
728
|
render_data: buildRenderDataTool(config),
|
|
599
729
|
summarize: buildSummarizeTool(config),
|
|
@@ -615,18 +745,21 @@ export async function buildAgents(opts: {
|
|
|
615
745
|
const approvalGatedByAgent: Array<{ agentId: string; toolIds: string[] }> = [];
|
|
616
746
|
|
|
617
747
|
for (const [id, def] of Object.entries(definitions)) {
|
|
618
|
-
const
|
|
748
|
+
const userTools = await resolveUserTools(def.tools, plugins);
|
|
749
|
+
const tools = { ...ambientTools, ...userTools };
|
|
619
750
|
let workspace = resolveAgentWorkspace(def.workspace);
|
|
620
751
|
if (
|
|
621
752
|
(def.workspace === undefined && !workspace) ||
|
|
622
|
-
((
|
|
753
|
+
((extraSkillMounts?.length ||
|
|
623
754
|
config.sandbox !== undefined ||
|
|
755
|
+
config.workspaceFallbackToTmp !== undefined ||
|
|
624
756
|
config.workspaceTools !== undefined ||
|
|
625
757
|
context !== undefined) &&
|
|
626
758
|
isDefaultWorkspace(workspace))
|
|
627
759
|
) {
|
|
628
760
|
workspace = databricksWorkspace({
|
|
629
|
-
|
|
761
|
+
extraSkillMounts,
|
|
762
|
+
fallbackToTmp: config.workspaceFallbackToTmp,
|
|
630
763
|
...(config.workspaceTools !== undefined ? { tools: config.workspaceTools } : {}),
|
|
631
764
|
pluginContext: context,
|
|
632
765
|
sandbox: config.sandbox === true ? "databricks" : config.sandbox,
|
|
@@ -638,6 +771,7 @@ export async function buildAgents(opts: {
|
|
|
638
771
|
const gated = approvalGatedToolIds(tools);
|
|
639
772
|
if (gated.length > 0) approvalGatedByAgent.push({ agentId: id, toolIds: gated });
|
|
640
773
|
const memory = memoryBuilder?.forAgent(id, def);
|
|
774
|
+
const resolveCodeMode = codeModeResolver(config, tools, workspace);
|
|
641
775
|
const agent = new Agent({
|
|
642
776
|
id,
|
|
643
777
|
name: def.name ?? id,
|
|
@@ -646,17 +780,26 @@ export async function buildAgents(opts: {
|
|
|
646
780
|
// metadata. Fall back to a generated one when the definition
|
|
647
781
|
// omits it.
|
|
648
782
|
description: def.description?.trim() || defaultAgentDescription(def.name ?? id),
|
|
649
|
-
instructions: composeInstructions(def.instructions, style),
|
|
783
|
+
instructions: composeInstructions(def.instructions, style, resolveCodeMode),
|
|
650
784
|
...(def.requestContextSchema ? { requestContextSchema: def.requestContextSchema } : {}),
|
|
651
785
|
model: resolveModel(config, def.model),
|
|
652
|
-
defaultOptions: {
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
786
|
+
defaultOptions: ({ requestContext }) =>
|
|
787
|
+
withRequestMemoryScope(
|
|
788
|
+
{
|
|
789
|
+
maxSteps: config.agentMaxSteps ?? DEFAULT_AGENT_MAX_STEPS,
|
|
790
|
+
providerOptions: RESPONSES_PROVIDER_OPTIONS,
|
|
791
|
+
...(def.requireToolApproval !== undefined
|
|
792
|
+
? { requireToolApproval: def.requireToolApproval }
|
|
793
|
+
: {}),
|
|
794
|
+
},
|
|
795
|
+
memory ? requestContext : undefined,
|
|
796
|
+
),
|
|
797
|
+
tools: resolveCodeMode
|
|
798
|
+
? async (args) => {
|
|
799
|
+
const codeMode = await resolveCodeMode(args);
|
|
800
|
+
return codeMode ? { ...tools, [codeMode.tool.id]: codeMode.tool } : tools;
|
|
801
|
+
}
|
|
802
|
+
: tools,
|
|
660
803
|
...(memory ? { memory } : {}),
|
|
661
804
|
...(workspace ? { workspace } : {}),
|
|
662
805
|
inputProcessors: [...inputProcessors, ...workspaceSkillInputProcessors(workspace, config)],
|
|
@@ -679,7 +822,7 @@ export async function buildAgents(opts: {
|
|
|
679
822
|
name: def.name ?? id,
|
|
680
823
|
defaultModel:
|
|
681
824
|
defaultModel.kind === "configured" ? defaultModel.model : `<${defaultModel.kind}>`,
|
|
682
|
-
tools: Object.keys(tools),
|
|
825
|
+
tools: [...Object.keys(tools), ...(resolveCodeMode ? ["<dynamic-code-mode>"] : [])],
|
|
683
826
|
});
|
|
684
827
|
}
|
|
685
828
|
|
|
@@ -909,19 +1052,16 @@ function resolveModel(
|
|
|
909
1052
|
}
|
|
910
1053
|
|
|
911
1054
|
/**
|
|
912
|
-
* Resolve
|
|
913
|
-
*
|
|
914
|
-
*
|
|
915
|
-
* survives - the caller already knows which agent was registering.
|
|
1055
|
+
* Resolve only the tools explicitly supplied by one agent definition.
|
|
1056
|
+
* Callback errors propagate verbatim so the original stack survives - the
|
|
1057
|
+
* caller already knows which agent was registering.
|
|
916
1058
|
*/
|
|
917
|
-
async function
|
|
1059
|
+
async function resolveUserTools(
|
|
918
1060
|
defTools: AnyMastraAgentDefinition["tools"],
|
|
919
1061
|
plugins: MastraPlugins,
|
|
920
|
-
ambientTools: MastraTools,
|
|
921
1062
|
): Promise<MastraTools> {
|
|
922
|
-
if (!defTools) return {
|
|
923
|
-
|
|
924
|
-
return { ...ambientTools, ...resolved };
|
|
1063
|
+
if (!defTools) return {};
|
|
1064
|
+
return typeof defTools === "function" ? defTools(plugins) : defTools;
|
|
925
1065
|
}
|
|
926
1066
|
|
|
927
1067
|
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
|
-
|
|
67
|
+
params: withRequestMemoryScope(
|
|
68
|
+
{
|
|
69
|
+
...params,
|
|
70
|
+
requestContext,
|
|
71
|
+
...(abortSignal ? { abortSignal } : {}),
|
|
72
|
+
},
|
|
67
73
|
requestContext,
|
|
68
|
-
|
|
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
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
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. Defaults to Monty. `false`
|
|
238
|
+
* disables command execution; `true`, `"databricks"`, or an object
|
|
239
|
+
* selects/configures Databricks Sandbox. An agent with an explicit custom
|
|
240
|
+
* `workspace` keeps that 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
|
|
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
|
|
700
|
+
'Command sandbox for auto-created agent workspaces. Defaults to Monty. False disables command execution; 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
|
-
//
|
|
1114
|
-
// every default-workspace agent via `
|
|
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
|
-
|
|
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
|
-
|
|
1129
|
+
extraSkillMounts: provisioned.localSkillMounts,
|
|
1130
1130
|
});
|
|
1131
1131
|
|
|
1132
1132
|
// `mastra.server.apiRoutes` is only honored by Mastra's standalone
|