@dbx-tools/appkit-mastra 0.9.140 → 0.9.143
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 +62 -14
- package/index.ts +5 -2
- package/lib/index.d.ts +5 -2
- package/lib/index.js +4 -2
- package/lib/src/agents.js +151 -23
- package/lib/src/chat.d.ts +2 -1
- package/lib/src/chat.js +41 -3
- package/lib/src/config.d.ts +28 -7
- package/lib/src/config.js +8 -3
- package/lib/src/follow-up-suggestions.d.ts +51 -0
- package/lib/src/follow-up-suggestions.js +322 -0
- package/lib/src/genie.js +11 -1
- package/lib/src/plugin.js +6 -2
- package/lib/src/server.js +5 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +27 -18
- package/src/agents.ts +192 -25
- package/src/chat.ts +46 -2
- package/src/config.ts +38 -9
- package/src/follow-up-suggestions.ts +392 -0
- package/src/genie.ts +10 -0
- package/src/plugin.ts +5 -1
- package/src/server.ts +8 -0
package/src/agents.ts
CHANGED
|
@@ -45,10 +45,18 @@ import { createCodeMode, createTool } from "@mastra/core/tools";
|
|
|
45
45
|
import type { Workspace } from "@mastra/core/workspace";
|
|
46
46
|
import { createSkillTools, createWorkspaceTools } from "@mastra/core/workspace";
|
|
47
47
|
import type { PgVectorConfig, PostgresStoreConfig } from "@mastra/pg";
|
|
48
|
-
import { QuickJsCodeModeTransport } from "@mastra/quickjs";
|
|
49
48
|
|
|
50
49
|
import { buildRenderDataTool } from "./chart.ts";
|
|
51
|
-
import type {
|
|
50
|
+
import type {
|
|
51
|
+
MastraCodeModeConfig,
|
|
52
|
+
MastraCodeModeTransport,
|
|
53
|
+
MastraPluginConfig,
|
|
54
|
+
} from "./config.ts";
|
|
55
|
+
import {
|
|
56
|
+
buildFollowUpSuggestionsProcessor,
|
|
57
|
+
buildSuggestFollowUpsTool,
|
|
58
|
+
resolveFollowUpSuggestionsConfig,
|
|
59
|
+
} from "./follow-up-suggestions.ts";
|
|
52
60
|
import { buildGenieToolkitProvider, resolveGenieSpaces } from "./genie.ts";
|
|
53
61
|
import { withRequestMemoryScope, type MemoryBuilder } from "./memory.ts";
|
|
54
62
|
import { buildModel, RESPONSES_PROVIDER_OPTIONS } from "./model.ts";
|
|
@@ -64,7 +72,28 @@ import {
|
|
|
64
72
|
} from "./workspaces.ts";
|
|
65
73
|
|
|
66
74
|
const codeModeLogger = log.logger("mastra/code-mode");
|
|
67
|
-
|
|
75
|
+
const ISOLATED_VM_PACKAGE = "@mastra/isolated-vm";
|
|
76
|
+
const QUICKJS_PACKAGE = "@mastra/quickjs";
|
|
77
|
+
let isolatedVmDependency: Promise<typeof import("@mastra/isolated-vm")> | undefined;
|
|
78
|
+
let quickJsDependency: Promise<typeof import("@mastra/quickjs")> | undefined;
|
|
79
|
+
|
|
80
|
+
type NormalizedCodeModeConfig = MastraCodeModeConfig;
|
|
81
|
+
|
|
82
|
+
interface ResolvedCodeModeConfig {
|
|
83
|
+
readonly id?: string;
|
|
84
|
+
readonly timeout?: number;
|
|
85
|
+
readonly provider: Exclude<MastraCodeModeTransport, "auto">;
|
|
86
|
+
readonly transport: CodeModeTransport;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type CodeModeFailureCategory =
|
|
90
|
+
"unsupported-runtime" | "dependency-unavailable" | "construction-failed";
|
|
91
|
+
|
|
92
|
+
interface CodeModeFailure {
|
|
93
|
+
readonly category: CodeModeFailureCategory;
|
|
94
|
+
readonly error?: Error;
|
|
95
|
+
readonly provider: Exclude<MastraCodeModeTransport, "auto">;
|
|
96
|
+
}
|
|
68
97
|
|
|
69
98
|
/** Return whether this boot environment matches isolated-vm's supported app shape. */
|
|
70
99
|
function supportsIsolatedVmTransport(): boolean {
|
|
@@ -77,6 +106,36 @@ function supportsIsolatedVmTransport(): boolean {
|
|
|
77
106
|
return [...process.execArgv, ...nodeOptions].includes("--no-node-snapshot");
|
|
78
107
|
}
|
|
79
108
|
|
|
109
|
+
/** Return whether the current runtime satisfies QuickJS' published engine floor. */
|
|
110
|
+
function supportsQuickJsTransport(): boolean {
|
|
111
|
+
if (process.versions.bun) return true;
|
|
112
|
+
if (process.release.name !== "node") return false;
|
|
113
|
+
const [majorText, minorText] = process.versions.node.split(".");
|
|
114
|
+
const major = Number.parseInt(majorText ?? "", 10);
|
|
115
|
+
const minor = Number.parseInt(minorText ?? "", 10);
|
|
116
|
+
return (
|
|
117
|
+
Number.isFinite(major) &&
|
|
118
|
+
Number.isFinite(minor) &&
|
|
119
|
+
(major > 20 || (major === 20 && minor >= 19))
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Import the optional native transport at most once for this process. */
|
|
124
|
+
function loadIsolatedVmDependency(): Promise<typeof import("@mastra/isolated-vm")> {
|
|
125
|
+
isolatedVmDependency ??= import(/* @vite-ignore */ ISOLATED_VM_PACKAGE) as Promise<
|
|
126
|
+
typeof import("@mastra/isolated-vm")
|
|
127
|
+
>;
|
|
128
|
+
return isolatedVmDependency;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Import the optional portable transport at most once for this process. */
|
|
132
|
+
function loadQuickJsDependency(): Promise<typeof import("@mastra/quickjs")> {
|
|
133
|
+
quickJsDependency ??= import(/* @vite-ignore */ QUICKJS_PACKAGE) as Promise<
|
|
134
|
+
typeof import("@mastra/quickjs")
|
|
135
|
+
>;
|
|
136
|
+
return quickJsDependency;
|
|
137
|
+
}
|
|
138
|
+
|
|
80
139
|
/**
|
|
81
140
|
* Tool record accepted by every Mastra `Agent.tools` field and by the
|
|
82
141
|
* `tools(plugins)` callback on {@link MastraAgentDefinition}.
|
|
@@ -607,26 +666,125 @@ function appendInstructionBlock(instructions: AgentInstructions, block: string):
|
|
|
607
666
|
return [instructions, { role: "system", content: block }] as AgentInstructions;
|
|
608
667
|
}
|
|
609
668
|
|
|
610
|
-
/**
|
|
611
|
-
function
|
|
612
|
-
|
|
669
|
+
/** Normalize the public Code Mode shorthand into one startup configuration. */
|
|
670
|
+
function normalizeCodeModeConfig(
|
|
671
|
+
codeMode: MastraPluginConfig["codeMode"],
|
|
672
|
+
): NormalizedCodeModeConfig | undefined {
|
|
673
|
+
if (codeMode === undefined || codeMode === false) return undefined;
|
|
674
|
+
return typeof codeMode === "string" ? { transport: codeMode } : codeMode;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/** Try one optional Code Mode transport without applying fallback policy. */
|
|
678
|
+
async function tryCodeModeTransport(
|
|
679
|
+
provider: Exclude<MastraCodeModeTransport, "auto">,
|
|
680
|
+
): Promise<ResolvedCodeModeConfig | CodeModeFailure> {
|
|
681
|
+
if (provider === "isolated-vm") {
|
|
613
682
|
if (!supportsIsolatedVmTransport()) {
|
|
614
|
-
|
|
615
|
-
return new QuickJsCodeModeTransport();
|
|
683
|
+
return { category: "unsupported-runtime", provider };
|
|
616
684
|
}
|
|
685
|
+
let module: typeof import("@mastra/isolated-vm");
|
|
617
686
|
try {
|
|
618
|
-
|
|
619
|
-
const transport = new IsolatedVmCodeModeTransport();
|
|
620
|
-
codeModeLogger.info("transport selected", { provider: "isolated-vm" });
|
|
621
|
-
return transport;
|
|
687
|
+
module = await loadIsolatedVmDependency();
|
|
622
688
|
} catch (caught) {
|
|
623
|
-
|
|
689
|
+
return {
|
|
690
|
+
category: "dependency-unavailable",
|
|
624
691
|
error: errorUtils.toError(caught),
|
|
625
|
-
|
|
626
|
-
|
|
692
|
+
provider,
|
|
693
|
+
};
|
|
627
694
|
}
|
|
628
|
-
|
|
629
|
-
|
|
695
|
+
try {
|
|
696
|
+
return { provider, transport: new module.IsolatedVmCodeModeTransport() };
|
|
697
|
+
} catch (caught) {
|
|
698
|
+
return {
|
|
699
|
+
category: "construction-failed",
|
|
700
|
+
error: errorUtils.toError(caught),
|
|
701
|
+
provider,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (!supportsQuickJsTransport()) {
|
|
707
|
+
return { category: "unsupported-runtime", provider };
|
|
708
|
+
}
|
|
709
|
+
let module: typeof import("@mastra/quickjs");
|
|
710
|
+
try {
|
|
711
|
+
module = await loadQuickJsDependency();
|
|
712
|
+
} catch (caught) {
|
|
713
|
+
return {
|
|
714
|
+
category: "dependency-unavailable",
|
|
715
|
+
error: errorUtils.toError(caught),
|
|
716
|
+
provider,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
try {
|
|
720
|
+
return { provider, transport: new module.QuickJsCodeModeTransport() };
|
|
721
|
+
} catch (caught) {
|
|
722
|
+
return {
|
|
723
|
+
category: "construction-failed",
|
|
724
|
+
error: errorUtils.toError(caught),
|
|
725
|
+
provider,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function isCodeModeFailure(
|
|
731
|
+
result: ResolvedCodeModeConfig | CodeModeFailure,
|
|
732
|
+
): result is CodeModeFailure {
|
|
733
|
+
return "category" in result;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/** Produce the actionable startup error for an explicitly required transport. */
|
|
737
|
+
function requiredCodeModeError(failure: CodeModeFailure): ConfigurationError {
|
|
738
|
+
const runtime = process.versions.bun
|
|
739
|
+
? `Bun ${process.versions.bun}`
|
|
740
|
+
: `${process.release.name} ${process.versions.node}`;
|
|
741
|
+
const install = `bun add ${failure.provider === "isolated-vm" ? ISOLATED_VM_PACKAGE : QUICKJS_PACKAGE}`;
|
|
742
|
+
const reason =
|
|
743
|
+
failure.category === "unsupported-runtime"
|
|
744
|
+
? `is not supported by ${runtime}`
|
|
745
|
+
: failure.category === "dependency-unavailable"
|
|
746
|
+
? "could not be loaded"
|
|
747
|
+
: "could not be initialized";
|
|
748
|
+
return new ConfigurationError(
|
|
749
|
+
`mastra: codeMode transport "${failure.provider}" ${reason}. Install the optional transport with \`${install}\` and use a supported runtime.`,
|
|
750
|
+
failure.error ? { cause: failure.error } : undefined,
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
/** Resolve the configured optional transport once during plugin startup. */
|
|
755
|
+
async function resolveCodeModeConfig(
|
|
756
|
+
codeMode: MastraPluginConfig["codeMode"],
|
|
757
|
+
): Promise<ResolvedCodeModeConfig | undefined> {
|
|
758
|
+
const config = normalizeCodeModeConfig(codeMode);
|
|
759
|
+
if (!config) return undefined;
|
|
760
|
+
|
|
761
|
+
const providers: readonly Exclude<MastraCodeModeTransport, "auto">[] =
|
|
762
|
+
config.transport === "auto" ? ["isolated-vm", "quickjs"] : [config.transport];
|
|
763
|
+
const failures: CodeModeFailure[] = [];
|
|
764
|
+
for (const provider of providers) {
|
|
765
|
+
const result = await tryCodeModeTransport(provider);
|
|
766
|
+
if (!isCodeModeFailure(result)) {
|
|
767
|
+
codeModeLogger.info("transport selected", { provider });
|
|
768
|
+
return { ...result, id: config.id, timeout: config.timeout };
|
|
769
|
+
}
|
|
770
|
+
failures.push(result);
|
|
771
|
+
if (config.transport !== "auto") throw requiredCodeModeError(result);
|
|
772
|
+
const fields = {
|
|
773
|
+
category: result.category,
|
|
774
|
+
provider,
|
|
775
|
+
...(result.error ? { error: result.error } : {}),
|
|
776
|
+
};
|
|
777
|
+
if (result.category === "unsupported-runtime") {
|
|
778
|
+
codeModeLogger.info("automatic transport unsupported", fields);
|
|
779
|
+
} else {
|
|
780
|
+
codeModeLogger.warn("automatic transport unavailable", fields);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
codeModeLogger.info("automatic Code Mode disabled", {
|
|
785
|
+
reasons: failures.map(({ category, provider }) => ({ category, provider })),
|
|
786
|
+
});
|
|
787
|
+
return undefined;
|
|
630
788
|
}
|
|
631
789
|
|
|
632
790
|
type CodeModeResolver<TRequestContext extends Record<string, unknown> | unknown = unknown> = (
|
|
@@ -640,12 +798,11 @@ type CodeModeResolver<TRequestContext extends Record<string, unknown> | unknown
|
|
|
640
798
|
|
|
641
799
|
/** Build request-scoped native Code Mode over all executable context tools. */
|
|
642
800
|
async function buildCodeMode<TRequestContext extends Record<string, unknown> | unknown>(
|
|
643
|
-
config:
|
|
801
|
+
config: ResolvedCodeModeConfig,
|
|
644
802
|
tools: MastraTools,
|
|
645
803
|
workspace: Workspace | undefined,
|
|
646
804
|
requestContext: RequestContext<TRequestContext>,
|
|
647
805
|
): Promise<ReturnType<typeof createCodeMode> | undefined> {
|
|
648
|
-
if (config.codeMode === false) return undefined;
|
|
649
806
|
const workspaceTools = workspace
|
|
650
807
|
? await createWorkspaceTools(workspace, { requestContext, workspace })
|
|
651
808
|
: {};
|
|
@@ -660,10 +817,13 @@ async function buildCodeMode<TRequestContext extends Record<string, unknown> | u
|
|
|
660
817
|
),
|
|
661
818
|
) as ToolsInput;
|
|
662
819
|
if (Object.keys(executableTools).length === 0) return undefined;
|
|
663
|
-
const options = typeof config.codeMode === "object" ? config.codeMode : {};
|
|
664
820
|
const codeMode = createCodeMode(
|
|
665
|
-
{
|
|
666
|
-
|
|
821
|
+
{
|
|
822
|
+
tools: executableTools,
|
|
823
|
+
...(config.id !== undefined ? { id: config.id } : {}),
|
|
824
|
+
...(config.timeout !== undefined ? { timeout: config.timeout } : {}),
|
|
825
|
+
},
|
|
826
|
+
config.transport,
|
|
667
827
|
);
|
|
668
828
|
if (!("mastra_workspace_read_file" in workspaceTools)) return codeMode;
|
|
669
829
|
return {
|
|
@@ -674,11 +834,11 @@ async function buildCodeMode<TRequestContext extends Record<string, unknown> | u
|
|
|
674
834
|
|
|
675
835
|
/** Resolve Code Mode lazily so workspace and dynamic tool policy follow each request. */
|
|
676
836
|
function codeModeResolver<TRequestContext extends Record<string, unknown> | unknown>(
|
|
677
|
-
config:
|
|
837
|
+
config: ResolvedCodeModeConfig | undefined,
|
|
678
838
|
tools: MastraTools,
|
|
679
839
|
workspace: Workspace | undefined,
|
|
680
840
|
): CodeModeResolver<TRequestContext> | undefined {
|
|
681
|
-
if (config
|
|
841
|
+
if (!config) return undefined;
|
|
682
842
|
return ({ requestContext }) => buildCodeMode(config, tools, workspace, requestContext);
|
|
683
843
|
}
|
|
684
844
|
|
|
@@ -731,6 +891,7 @@ export async function buildAgents(opts: {
|
|
|
731
891
|
standardSkills = [],
|
|
732
892
|
excludedWorkspaceSkillNames = [],
|
|
733
893
|
} = opts;
|
|
894
|
+
const codeModeConfig = await resolveCodeModeConfig(config.codeMode);
|
|
734
895
|
const definitions = resolveDefinitions(config);
|
|
735
896
|
const ids = Object.keys(definitions);
|
|
736
897
|
const defaultAgentId = config.defaultAgent ?? ids[0] ?? FALLBACK_AGENT_ID;
|
|
@@ -742,9 +903,14 @@ export async function buildAgents(opts: {
|
|
|
742
903
|
// user can shadow either by including a same-named tool in their own
|
|
743
904
|
// `config.tools` or per-agent `tools`. Merge order is
|
|
744
905
|
// `system -> standard skills -> user-ambient -> per-agent`, last write wins.
|
|
906
|
+
const followUps = resolveFollowUpSuggestionsConfig(config.followUpSuggestions);
|
|
907
|
+
const followUpProcessor = buildFollowUpSuggestionsProcessor(config);
|
|
745
908
|
const systemTools: MastraTools = {
|
|
746
909
|
render_data: buildRenderDataTool(config),
|
|
747
910
|
summarize: buildSummarizeTool(config),
|
|
911
|
+
...(followUps?.exposeTool && followUps.mode !== "genie"
|
|
912
|
+
? { suggest_follow_ups: buildSuggestFollowUpsTool(config) }
|
|
913
|
+
: {}),
|
|
748
914
|
};
|
|
749
915
|
const standardSkillTools =
|
|
750
916
|
standardSkills.length > 0 ? createSkillTools(resolveAgentSkills([...standardSkills])) : {};
|
|
@@ -798,7 +964,7 @@ export async function buildAgents(opts: {
|
|
|
798
964
|
const gated = approvalGatedToolIds(tools);
|
|
799
965
|
if (gated.length > 0) approvalGatedByAgent.push({ agentId: id, toolIds: gated });
|
|
800
966
|
const memory = memoryBuilder?.forAgent(id, def);
|
|
801
|
-
const resolveCodeMode = codeModeResolver(
|
|
967
|
+
const resolveCodeMode = codeModeResolver(codeModeConfig, tools, workspace);
|
|
802
968
|
const agent = new Agent({
|
|
803
969
|
id,
|
|
804
970
|
name: def.name ?? id,
|
|
@@ -832,6 +998,7 @@ export async function buildAgents(opts: {
|
|
|
832
998
|
inputProcessors: [...inputProcessors, ...workspaceSkillInputProcessors(workspace, config)],
|
|
833
999
|
outputProcessors: [
|
|
834
1000
|
toolErrorLoggingProcessor(log),
|
|
1001
|
+
...(followUpProcessor ? [followUpProcessor] : []),
|
|
835
1002
|
...outputProcessorFactories.flatMap((factory) => {
|
|
836
1003
|
const processor = factory(id);
|
|
837
1004
|
return processor ? [processor] : [];
|
package/src/chat.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { errorUtils, log } from "@dbx-tools/shared-core";
|
|
7
|
+
import { errorUtils, log, object } from "@dbx-tools/shared-core";
|
|
8
8
|
import { routes } from "@dbx-tools/shared-mastra";
|
|
9
9
|
import {
|
|
10
10
|
isStaleMastraResumeError,
|
|
@@ -15,6 +15,14 @@ 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 type { MastraPluginConfig } from "./config.ts";
|
|
19
|
+
import {
|
|
20
|
+
buildFollowUpSuggestionsTransform,
|
|
21
|
+
FOLLOW_UP_NATIVE_QUESTIONS_KEY,
|
|
22
|
+
FOLLOW_UP_RUN_ID_KEY,
|
|
23
|
+
FOLLOW_UP_USER_TEXT_KEY,
|
|
24
|
+
resolveFollowUpSuggestionsConfig,
|
|
25
|
+
} from "./follow-up-suggestions.ts";
|
|
18
26
|
import { withRequestMemoryScope } from "./memory.ts";
|
|
19
27
|
|
|
20
28
|
const logger = log.logger("mastra/chat");
|
|
@@ -24,8 +32,31 @@ export function agentAbortSignal(agent: unknown, signal: AbortSignal): AbortSign
|
|
|
24
32
|
return isEventedAgent(agent) ? undefined : signal;
|
|
25
33
|
}
|
|
26
34
|
|
|
35
|
+
function latestUserText(value: unknown): string | undefined {
|
|
36
|
+
if (!Array.isArray(value)) return undefined;
|
|
37
|
+
for (let index = value.length - 1; index >= 0; index -= 1) {
|
|
38
|
+
const message = value[index];
|
|
39
|
+
if (!object.isRecord(message) || message.role !== "user") continue;
|
|
40
|
+
if (typeof message.content === "string" && message.content.trim()) {
|
|
41
|
+
return message.content.trim();
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(message.parts)) continue;
|
|
44
|
+
const text = message.parts
|
|
45
|
+
.flatMap((part) =>
|
|
46
|
+
object.isRecord(part) && part.type === "text" && typeof part.text === "string"
|
|
47
|
+
? [part.text]
|
|
48
|
+
: [],
|
|
49
|
+
)
|
|
50
|
+
.join("\n")
|
|
51
|
+
.trim();
|
|
52
|
+
if (text) return text;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
27
57
|
/** Register detached chat, durable observation, and explicit abort routes. */
|
|
28
|
-
export function agentChatRoutes() {
|
|
58
|
+
export function agentChatRoutes(config: MastraPluginConfig = {}) {
|
|
59
|
+
const followUps = resolveFollowUpSuggestionsConfig(config.followUpSuggestions);
|
|
29
60
|
const chatPath = `${routes.MASTRA_ROUTES.chat}/:agentId` as `${string}:agentId`;
|
|
30
61
|
const runPath =
|
|
31
62
|
`${routes.MASTRA_ROUTES.chat}/:agentId${routes.MASTRA_ROUTES.runs}/:runId` as `${string}:agentId${string}:runId`;
|
|
@@ -56,6 +87,12 @@ export function agentChatRoutes() {
|
|
|
56
87
|
}
|
|
57
88
|
const status = rawStatus as "draft" | "published" | undefined;
|
|
58
89
|
const abortSignal = agentAbortSignal(mastra.getAgentById(agentId), context.req.raw.signal);
|
|
90
|
+
const runId =
|
|
91
|
+
typeof params.runId === "string" && params.runId ? params.runId : crypto.randomUUID();
|
|
92
|
+
const userText = latestUserText(params.messages);
|
|
93
|
+
if (userText) requestContext.setRaw(FOLLOW_UP_USER_TEXT_KEY, userText);
|
|
94
|
+
requestContext.setRaw(FOLLOW_UP_NATIVE_QUESTIONS_KEY, []);
|
|
95
|
+
requestContext.setRaw(FOLLOW_UP_RUN_ID_KEY, runId);
|
|
59
96
|
const stream = await handleChatStream({
|
|
60
97
|
mastra,
|
|
61
98
|
agentId,
|
|
@@ -67,11 +104,15 @@ export function agentChatRoutes() {
|
|
|
67
104
|
params: withRequestMemoryScope(
|
|
68
105
|
{
|
|
69
106
|
...params,
|
|
107
|
+
runId,
|
|
70
108
|
requestContext,
|
|
71
109
|
...(abortSignal ? { abortSignal } : {}),
|
|
72
110
|
},
|
|
73
111
|
requestContext,
|
|
74
112
|
),
|
|
113
|
+
...(followUps && followUps.mode !== "genie"
|
|
114
|
+
? { experimentalTransform: buildFollowUpSuggestionsTransform(runId) }
|
|
115
|
+
: {}),
|
|
75
116
|
version: "v7",
|
|
76
117
|
sendReasoning: true,
|
|
77
118
|
sendSources: true,
|
|
@@ -97,6 +138,9 @@ export function agentChatRoutes() {
|
|
|
97
138
|
const observed = await agent.observe(runId);
|
|
98
139
|
const stream = toAISdkStream(observed.output, {
|
|
99
140
|
from: "agent",
|
|
141
|
+
...(followUps && followUps.mode !== "genie"
|
|
142
|
+
? { experimentalTransform: buildFollowUpSuggestionsTransform(runId) }
|
|
143
|
+
: {}),
|
|
100
144
|
version: "v7",
|
|
101
145
|
sendReasoning: true,
|
|
102
146
|
sendSources: true,
|
package/src/config.ts
CHANGED
|
@@ -166,8 +166,13 @@ export interface MastraWorkspaceSkillsConfig {
|
|
|
166
166
|
ttlMs?: number;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/** Native Mastra Code Mode execution transport. */
|
|
170
|
+
export type MastraCodeModeTransport = "auto" | "isolated-vm" | "quickjs";
|
|
171
|
+
|
|
169
172
|
/** Native Mastra Code Mode settings for sandboxed multi-tool orchestration. */
|
|
170
173
|
export interface MastraCodeModeConfig {
|
|
174
|
+
/** Code Mode execution transport. */
|
|
175
|
+
transport: MastraCodeModeTransport;
|
|
171
176
|
/** Generated orchestration tool id. Defaults to `execute_typescript`. */
|
|
172
177
|
id?: string;
|
|
173
178
|
/** Maximum orchestration program runtime in milliseconds. Defaults to 30 seconds. */
|
|
@@ -213,6 +218,18 @@ export interface MastraMcpConfig {
|
|
|
213
218
|
extraTools?: MastraTools;
|
|
214
219
|
}
|
|
215
220
|
|
|
221
|
+
/** Optional post-turn follow-up suggestion policy. */
|
|
222
|
+
export interface FollowUpSuggestionsConfig {
|
|
223
|
+
/** Native Genie only, ChatFast generated only, or automatic selection when true. */
|
|
224
|
+
mode: true | "generated" | "genie";
|
|
225
|
+
/** Maximum questions emitted for one turn. Defaults to 3, maximum 10. */
|
|
226
|
+
limit?: number;
|
|
227
|
+
/** Tail-generation timeout in milliseconds. */
|
|
228
|
+
timeoutMs?: number;
|
|
229
|
+
/** Also expose the generator as an explicitly callable agent tool. */
|
|
230
|
+
exposeTool?: boolean;
|
|
231
|
+
}
|
|
232
|
+
|
|
216
233
|
/** Configuration accepted by the Mastra AppKit plugin. */
|
|
217
234
|
export interface MastraPluginConfig extends BasePluginConfig {
|
|
218
235
|
/**
|
|
@@ -237,14 +254,14 @@ export interface MastraPluginConfig extends BasePluginConfig {
|
|
|
237
254
|
memory?: boolean | MastraMemoryConfig;
|
|
238
255
|
/**
|
|
239
256
|
* Expose executable tools available to the current request through native
|
|
240
|
-
* Mastra Code Mode. Defaults
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
257
|
+
* Mastra Code Mode. Defaults to `false`. `auto` selects an installed,
|
|
258
|
+
* runtime-supported optional transport during startup and leaves Code Mode
|
|
259
|
+
* disabled when none is available. Explicit transport values fail startup
|
|
260
|
+
* when their optional dependency or runtime support is unavailable. These
|
|
261
|
+
* transports do not execute through the workspace command sandbox; SSH is
|
|
262
|
+
* used only when an exposed SSH-backed tool is called.
|
|
246
263
|
*/
|
|
247
|
-
codeMode?:
|
|
264
|
+
codeMode?: false | MastraCodeModeTransport | MastraCodeModeConfig;
|
|
248
265
|
/**
|
|
249
266
|
* Sandbox for auto-created agent workspaces. Defaults to Monty. `false`
|
|
250
267
|
* disables command execution; `true` or `"monty"` selects Monty; an explicit
|
|
@@ -503,6 +520,12 @@ export interface MastraPluginConfig extends BasePluginConfig {
|
|
|
503
520
|
* to drill deep into a dataset within a single turn.
|
|
504
521
|
*/
|
|
505
522
|
agentMaxSteps?: number;
|
|
523
|
+
/**
|
|
524
|
+
* Optional post-turn follow-up questions. `true` selects sources
|
|
525
|
+
* automatically; `"generated"` or `"genie"` pins one source; `false` or
|
|
526
|
+
* omission disables follow-ups.
|
|
527
|
+
*/
|
|
528
|
+
followUpSuggestions?: false | true | "generated" | "genie" | FollowUpSuggestionsConfig;
|
|
506
529
|
/**
|
|
507
530
|
* Wire Mastra spans into AppKit's global OTel pipeline via
|
|
508
531
|
* `@mastra/otel-bridge`.
|
|
@@ -700,9 +723,10 @@ export const MASTRA_CONFIG_SCHEMA: ConfigSchema = {
|
|
|
700
723
|
"PgVector store for Mastra semantic recall. `true` captures the `lakebase` plugin's existing service-principal pool; an object opens a separately configured store. Auto-enabled when the `lakebase` plugin is registered.",
|
|
701
724
|
},
|
|
702
725
|
codeMode: {
|
|
703
|
-
type: ["boolean", "object"],
|
|
726
|
+
type: ["boolean", "string", "object"],
|
|
727
|
+
default: false,
|
|
704
728
|
description:
|
|
705
|
-
|
|
729
|
+
'Expose executable request tools through native Mastra Code Mode for TypeScript batching, aggregation, and arithmetic. Defaults to false. Use "auto" to select an installed supported optional transport or stay disabled, "isolated-vm" to require the native transport, "quickjs" to require the portable transport, or an object with transport plus id and timeout. Neither transport runs through the workspace command sandbox.',
|
|
706
730
|
},
|
|
707
731
|
sandbox: {
|
|
708
732
|
type: ["boolean", "string", "object"],
|
|
@@ -780,6 +804,11 @@ export const MASTRA_CONFIG_SCHEMA: ConfigSchema = {
|
|
|
780
804
|
description:
|
|
781
805
|
"Maximum LLM steps each agent gets per turn (a tool call and the final reply each consume one). Defaults to 25.",
|
|
782
806
|
},
|
|
807
|
+
followUpSuggestions: {
|
|
808
|
+
type: ["boolean", "string", "object"],
|
|
809
|
+
description:
|
|
810
|
+
'Optional post-turn follow-ups. True selects sources automatically; "generated" or "genie" pins one source; an object adds a limit, timeout, and optional tool exposure. Defaults off.',
|
|
811
|
+
},
|
|
783
812
|
stripStaleCharts: {
|
|
784
813
|
type: "boolean",
|
|
785
814
|
description:
|