@langchain/quickjs 0.5.0 → 0.5.1
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/dist/index.cjs +189 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +189 -114
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,6 +6,8 @@ import { shouldInterruptAfterDeadline } from "quickjs-emscripten";
|
|
|
6
6
|
import { newQuickJSAsyncWASMModuleFromVariant } from "quickjs-emscripten-core";
|
|
7
7
|
import { compile } from "json-schema-to-typescript";
|
|
8
8
|
import { toJsonSchema } from "@langchain/core/utils/json_schema";
|
|
9
|
+
import { isCommand } from "@langchain/langgraph";
|
|
10
|
+
import { BaseMessage } from "@langchain/core/messages";
|
|
9
11
|
import { Parser } from "acorn";
|
|
10
12
|
import { tsPlugin } from "@sveltejs/acorn-typescript";
|
|
11
13
|
import { walk } from "estree-walker";
|
|
@@ -95,6 +97,59 @@ async function toolToTypeSignature(name, description, jsonSchema) {
|
|
|
95
97
|
`;
|
|
96
98
|
}
|
|
97
99
|
//#endregion
|
|
100
|
+
//#region src/coerce.ts
|
|
101
|
+
/**
|
|
102
|
+
* Coercion of tool / subagent return values for the QuickJS bridge.
|
|
103
|
+
*
|
|
104
|
+
* The deepagents `task` tool resolves to a LangGraph `Command` whose payload
|
|
105
|
+
* carries the subagent's final message(s) under `update.messages`; some tools
|
|
106
|
+
* return a `ToolMessage` or a list of messages. The interpreter bridges need
|
|
107
|
+
* the underlying output, not the envelope, so this unwraps those shapes to the
|
|
108
|
+
* content the model actually cares about.
|
|
109
|
+
*/
|
|
110
|
+
/**
|
|
111
|
+
* Return the trailing message content from a `Command`'s `update.messages`,
|
|
112
|
+
* scanning from the end for the last message that actually has content. Returns
|
|
113
|
+
* the command unchanged when it has no message-shaped payload.
|
|
114
|
+
*/
|
|
115
|
+
function extractCommandContent(command) {
|
|
116
|
+
const update = command.update;
|
|
117
|
+
const messages = update !== null && typeof update === "object" ? update.messages : void 0;
|
|
118
|
+
if (Array.isArray(messages)) for (let i = messages.length - 1; i >= 0; i--) {
|
|
119
|
+
const message = messages[i];
|
|
120
|
+
if (BaseMessage.isInstance(message) && message.content != null) return message.content;
|
|
121
|
+
}
|
|
122
|
+
return command;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Unwrap a LangChain `Command` / `ToolMessage` / message-list envelope to the
|
|
126
|
+
* underlying content. Non-envelope values (strings, content-block arrays, plain
|
|
127
|
+
* objects) are returned unchanged.
|
|
128
|
+
*
|
|
129
|
+
* @param value The raw value returned by a tool or subagent dispatch.
|
|
130
|
+
* @returns The unwrapped content, or `value` itself when it isn't an envelope.
|
|
131
|
+
*/
|
|
132
|
+
function unwrapToolEnvelope(value) {
|
|
133
|
+
if (typeof value === "string") return value;
|
|
134
|
+
if (isCommand(value)) {
|
|
135
|
+
const inner = extractCommandContent(value);
|
|
136
|
+
return inner === value ? value : unwrapToolEnvelope(inner);
|
|
137
|
+
}
|
|
138
|
+
if (BaseMessage.isInstance(value)) return unwrapToolEnvelope(value.content);
|
|
139
|
+
if (Array.isArray(value)) {
|
|
140
|
+
for (let i = value.length - 1; i >= 0; i--) {
|
|
141
|
+
const entry = value[i];
|
|
142
|
+
if (BaseMessage.isInstance(entry)) return unwrapToolEnvelope(entry.content);
|
|
143
|
+
if (isCommand(entry)) {
|
|
144
|
+
const inner = extractCommandContent(entry);
|
|
145
|
+
if (inner !== entry) return unwrapToolEnvelope(inner);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
return value;
|
|
151
|
+
}
|
|
152
|
+
//#endregion
|
|
98
153
|
//#region src/transform.ts
|
|
99
154
|
/**
|
|
100
155
|
* AST-based code transform pipeline for the REPL.
|
|
@@ -396,6 +451,7 @@ function getSharedModule() {
|
|
|
396
451
|
* @returns Plain string representation of the tool output.
|
|
397
452
|
*/
|
|
398
453
|
function extractToolText(result) {
|
|
454
|
+
result = unwrapToolEnvelope(result);
|
|
399
455
|
if (typeof result === "string") return result;
|
|
400
456
|
if (Array.isArray(result)) {
|
|
401
457
|
const texts = [];
|
|
@@ -490,7 +546,7 @@ var ReplSession = class ReplSession {
|
|
|
490
546
|
subagentQueue = null;
|
|
491
547
|
bridgeDispatchRef = null;
|
|
492
548
|
/** Allowed keys in the subagent input object. */
|
|
493
|
-
static SUBAGENT_ALLOWED_KEYS = new Set([
|
|
549
|
+
static SUBAGENT_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
494
550
|
"description",
|
|
495
551
|
"subagentType",
|
|
496
552
|
"responseSchema"
|
|
@@ -900,8 +956,10 @@ function renderSubagentPrompt(toolName) {
|
|
|
900
956
|
### Dispatching Subagents with \`task\`
|
|
901
957
|
|
|
902
958
|
\`task\` is your primitive for running configured subagents from inside the
|
|
903
|
-
JavaScript REPL.
|
|
904
|
-
|
|
959
|
+
JavaScript REPL. Your job here is to DISTRIBUTE work, not to do it yourself:
|
|
960
|
+
write JavaScript that fans work out to subagents and assembles their results.
|
|
961
|
+
You handle the orchestration - fan-out, filtering, deduplication, multi-stage
|
|
962
|
+
flow, and synthesis - in plain JavaScript.
|
|
905
963
|
|
|
906
964
|
#### The primitive
|
|
907
965
|
|
|
@@ -919,13 +977,19 @@ function renderSubagentPrompt(toolName) {
|
|
|
919
977
|
the configured subagent names.
|
|
920
978
|
|
|
921
979
|
\`description\` is the only prompt the subagent receives for this dispatch. Make
|
|
922
|
-
it complete:
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
the
|
|
980
|
+
it complete: the goal, the constraints, what to inspect, and the exact shape
|
|
981
|
+
or level of detail you expect back. Give context as locators — file paths and
|
|
982
|
+
symbol names — not as pasted file contents. If you already read a file while
|
|
983
|
+
exploring, still pass its path and let the subagent read it; do not paste back
|
|
984
|
+
what you read. Each dispatch is stateless from the caller's perspective; you
|
|
985
|
+
cannot send follow-up messages to the same subagent run.
|
|
926
986
|
|
|
927
|
-
\`responseSchema\` is optional
|
|
928
|
-
|
|
987
|
+
\`responseSchema\` is optional, but set it on any dispatch whose result feeds
|
|
988
|
+
later code. A deterministic, typed shape is what lets you compose the next
|
|
989
|
+
stage reliably — index it, sort it, compare fields, branch on it, merge it —
|
|
990
|
+
instead of parsing free-form text. This is what makes a whole workflow
|
|
991
|
+
composable as one script. When provided, the resolved value is already a typed
|
|
992
|
+
JavaScript value matching the schema; do not call \`JSON.parse\` unless the
|
|
929
993
|
subagent intentionally returned a JSON string. Dynamic schemas work for
|
|
930
994
|
declarative subagents; runnable-backed subagents reject dynamic schemas because
|
|
931
995
|
their runnable is already compiled.
|
|
@@ -946,9 +1010,12 @@ function renderSubagentPrompt(toolName) {
|
|
|
946
1010
|
dispatch result back onto its item. Multi-stage analysis means: run a pass,
|
|
947
1011
|
filter or regroup the array in JS, then run another pass over the survivors.
|
|
948
1012
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1013
|
+
You can run the whole workflow in one \`${toolName}\` call or split it across
|
|
1014
|
+
several — both are fine. A single end-to-end script (generate, compare, pick a
|
|
1015
|
+
winner; or review every item, then synthesize) is clean when you can write it
|
|
1016
|
+
in one go; splitting is also fine when you want to inspect results between
|
|
1017
|
+
stages. Either way, don't redo work across calls — reuse what is already in
|
|
1018
|
+
scope (see "Reuse what earlier evals left in scope" below).
|
|
952
1019
|
|
|
953
1020
|
#### Fan out with bounded concurrency
|
|
954
1021
|
|
|
@@ -957,13 +1024,15 @@ function renderSubagentPrompt(toolName) {
|
|
|
957
1024
|
enforces a hard per-REPL cap of 32 concurrent subagent calls.
|
|
958
1025
|
|
|
959
1026
|
\`\`\`javascript
|
|
1027
|
+
const files = ["/src/a.ts", "/src/b.ts", "/src/c.ts"]; // found while exploring
|
|
960
1028
|
const batchSize = 10;
|
|
961
1029
|
const reviewed = [];
|
|
962
|
-
for (let i = 0; i <
|
|
963
|
-
const batch =
|
|
964
|
-
reviewed.push(...(await Promise.all(batch.map(async (
|
|
1030
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
1031
|
+
const batch = files.slice(i, i + batchSize);
|
|
1032
|
+
reviewed.push(...(await Promise.all(batch.map(async (file) => {
|
|
965
1033
|
const result = await task({
|
|
966
|
-
description: "
|
|
1034
|
+
description: "Read " + file + " and review it for SQL injection. " +
|
|
1035
|
+
"Cite line numbers.",
|
|
967
1036
|
subagentType: "reviewer",
|
|
968
1037
|
responseSchema: {
|
|
969
1038
|
type: "object",
|
|
@@ -984,61 +1053,44 @@ function renderSubagentPrompt(toolName) {
|
|
|
984
1053
|
required: ["vulnerabilities"],
|
|
985
1054
|
},
|
|
986
1055
|
});
|
|
987
|
-
return {
|
|
1056
|
+
return { file, ...result };
|
|
988
1057
|
}))));
|
|
989
1058
|
}
|
|
990
1059
|
\`\`\`
|
|
991
1060
|
|
|
992
|
-
####
|
|
993
|
-
|
|
994
|
-
Use JavaScript in the parent REPL for deterministic orchestration: joining
|
|
995
|
-
arrays, deduping, sorting, filtering, grouping, batching, and merging results.
|
|
996
|
-
If the \`tools.*\` namespace is exposed, also use it to pre-read files or collect
|
|
997
|
-
shared data once, then pass only the relevant content to each subagent in
|
|
998
|
-
\`description\`.
|
|
1061
|
+
#### Explore with your own tools first, then distribute
|
|
999
1062
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1063
|
+
You already have your normal tools for reading, listing, globbing, and
|
|
1064
|
+
grepping files. Use them to explore and understand the task BEFORE you write
|
|
1065
|
+
the orchestration script. These are ordinary tool calls, separate from the
|
|
1066
|
+
\`${toolName}\` tool: read the data file, list or glob the directory, grep for
|
|
1067
|
+
what matters, then decide how to split the work.
|
|
1003
1068
|
|
|
1004
|
-
|
|
1069
|
+
Never write \`${toolName}\` code that spawns a subagent just to read or parse a
|
|
1070
|
+
file or list a directory. That is a deterministic step you do yourself with a
|
|
1071
|
+
direct tool call; spending a whole agent loop on it is wasteful.
|
|
1005
1072
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1073
|
+
Once you understand the shape of the work, you have creative freedom in how
|
|
1074
|
+
you split it:
|
|
1008
1075
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
.
|
|
1012
|
-
|
|
1076
|
+
- One dispatch per file or per record, when the items are already separate.
|
|
1077
|
+
- Chunk a large input yourself — read it, split it, optionally write a small
|
|
1078
|
+
input file per chunk — and dispatch one subagent per chunk.
|
|
1079
|
+
- A cheap classification pass first, then deeper dispatches only for the items
|
|
1080
|
+
that warrant them.
|
|
1013
1081
|
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}));
|
|
1082
|
+
Then write JavaScript in the \`${toolName}\` tool that distributes the heavy,
|
|
1083
|
+
agentic work to subagents with \`task()\`: analyzing file contents, exploring a
|
|
1084
|
+
codebase, making judgment calls, rewriting code, or synthesizing a report.
|
|
1018
1085
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
"File: " + it.file + "\\n\\n" +
|
|
1028
|
-
it.content,
|
|
1029
|
-
subagentType: "reviewer",
|
|
1030
|
-
responseSchema: {
|
|
1031
|
-
type: "object",
|
|
1032
|
-
properties: {
|
|
1033
|
-
findings: { type: "array", items: { type: "object" } },
|
|
1034
|
-
},
|
|
1035
|
-
required: ["findings"],
|
|
1036
|
-
},
|
|
1037
|
-
});
|
|
1038
|
-
return { ...it, ...finding };
|
|
1039
|
-
}))));
|
|
1040
|
-
}
|
|
1041
|
-
\`\`\`
|
|
1086
|
+
Hand each subagent a locator, not a payload. Subagents have their own file
|
|
1087
|
+
tools, so for anything that lives in a file — a file to review, rewrite, or
|
|
1088
|
+
audit — pass the path and let the subagent read it. Do NOT read a whole file
|
|
1089
|
+
just to paste its contents into the description; that bloats every dispatch
|
|
1090
|
+
and duplicates the file across them. Reserve inline content for small or
|
|
1091
|
+
derived data that has no path of its own: a single parsed record, or a chunk
|
|
1092
|
+
you split out of a larger input (write the chunk to its own file and pass that
|
|
1093
|
+
path if it is large). Assemble the results in JS.
|
|
1042
1094
|
|
|
1043
1095
|
#### Compose multiple stages
|
|
1044
1096
|
|
|
@@ -1047,67 +1099,89 @@ function renderSubagentPrompt(toolName) {
|
|
|
1047
1099
|
only for those items.
|
|
1048
1100
|
|
|
1049
1101
|
\`\`\`javascript
|
|
1050
|
-
const tagged =
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
});
|
|
1063
|
-
return { ...it, ...tag };
|
|
1064
|
-
}))));
|
|
1065
|
-
}
|
|
1102
|
+
const tagged = await Promise.all(files.map((file) =>
|
|
1103
|
+
task({
|
|
1104
|
+
description: "Read " + file + " and classify it as handler, util, " +
|
|
1105
|
+
"test, or config.",
|
|
1106
|
+
subagentType: "reviewer",
|
|
1107
|
+
responseSchema: {
|
|
1108
|
+
type: "object",
|
|
1109
|
+
properties: { kind: { type: "string" }, risky: { type: "boolean" } },
|
|
1110
|
+
required: ["kind", "risky"],
|
|
1111
|
+
},
|
|
1112
|
+
}).then((tag) => ({ file, ...tag }))
|
|
1113
|
+
));
|
|
1066
1114
|
|
|
1067
1115
|
const riskyHandlers = tagged.filter((it) => it.kind === "handler" && it.risky);
|
|
1068
|
-
const deepReviews =
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
subagentType: "reviewer",
|
|
1075
|
-
});
|
|
1076
|
-
return { ...it, review };
|
|
1077
|
-
}))));
|
|
1078
|
-
}
|
|
1116
|
+
const deepReviews = await Promise.all(riskyHandlers.map((it) =>
|
|
1117
|
+
task({
|
|
1118
|
+
description: "Deep security review of " + it.file + ". Cite line numbers.",
|
|
1119
|
+
subagentType: "reviewer",
|
|
1120
|
+
}).then((review) => ({ ...it, review }))
|
|
1121
|
+
));
|
|
1079
1122
|
\`\`\`
|
|
1080
1123
|
|
|
1081
|
-
####
|
|
1124
|
+
#### Return results via the last expression, not \`console.log\`
|
|
1125
|
+
|
|
1126
|
+
The value of the last expression in an \`${toolName}\` call (or a resolved
|
|
1127
|
+
top-level \`await\`) is returned to you as the result. Make that final
|
|
1128
|
+
expression the variable holding your result and read it from there.
|
|
1129
|
+
\`console.log\` is only for incidental debugging: its output is capped and
|
|
1130
|
+
truncated, while the returned value is not, so never \`console.log\` your
|
|
1131
|
+
actual results.
|
|
1132
|
+
|
|
1133
|
+
Keep large intermediate sets in JS variables and return only a compact
|
|
1134
|
+
summary or a small slice, not the entire dataset. To persist full output,
|
|
1135
|
+
have a subagent write it, or write it with your own file tool outside the
|
|
1136
|
+
\`${toolName}\` call.
|
|
1082
1137
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1138
|
+
#### Reuse what earlier evals left in scope
|
|
1139
|
+
|
|
1140
|
+
The REPL is persistent within a turn: every top-level variable, function, and
|
|
1141
|
+
class you declare is kept and is available in your next \`${toolName}\` call
|
|
1142
|
+
(each is hoisted to global scope). So if a later step needs something an
|
|
1143
|
+
earlier eval produced or bound, **reference that variable by name** — do not
|
|
1144
|
+
write a new literal that re-types data a previous eval already returned or
|
|
1145
|
+
computed.
|
|
1146
|
+
|
|
1147
|
+
If you catch yourself pasting a big array or object of values you produced in
|
|
1148
|
+
an earlier call, that is the tell: the variable is still in scope, so use it.
|
|
1149
|
+
Re-typing prior results as a fresh literal wastes tokens and drifts from what
|
|
1150
|
+
actually ran.
|
|
1085
1151
|
|
|
1086
1152
|
\`\`\`javascript
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
content: JSON.stringify(deepReviews),
|
|
1090
|
-
});
|
|
1091
|
-
\`\`\`
|
|
1153
|
+
// An earlier eval bound this:
|
|
1154
|
+
// const auditResults = await Promise.all(files.map(/* ...audit... */));
|
|
1092
1155
|
|
|
1093
|
-
|
|
1094
|
-
|
|
1156
|
+
// A later eval — reference it; do NOT paste the findings back in as a literal:
|
|
1157
|
+
const findings = auditResults.flatMap((r) =>
|
|
1158
|
+
r.findings.map((f) => ({ ...f, file: r.file }))
|
|
1159
|
+
);
|
|
1160
|
+
const verified = await Promise.all(findings.map((f) =>
|
|
1161
|
+
task({ description: "Verify this finding: " + f.evidence, subagentType: "verifier" })
|
|
1162
|
+
.then((v) => ({ ...f, ...v }))
|
|
1163
|
+
));
|
|
1164
|
+
\`\`\`
|
|
1095
1165
|
|
|
1096
|
-
####
|
|
1166
|
+
#### When the user asks for a "workflow"
|
|
1097
1167
|
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1168
|
+
If the user's request mentions running a "workflow" (or otherwise uses the
|
|
1169
|
+
word "workflow"), fan the work out to subagents rather than doing it all
|
|
1170
|
+
yourself. Explore with your own tools first as needed, then write JavaScript
|
|
1171
|
+
in the \`${toolName}\` tool that dispatches subagents with \`task()\` and
|
|
1172
|
+
assembles their results. The point is to distribute the heavy work in
|
|
1173
|
+
parallel, not to grind through it one tool call at a time.
|
|
1101
1174
|
`;
|
|
1102
1175
|
}
|
|
1103
1176
|
function renderReplSystemPrompt(opts) {
|
|
1177
|
+
const sideEffects = opts.hasPtc ? " External side effects from inside the REPL are reachable only via the `tools.*` namespace documented below." : " The REPL is pure computation; do any filesystem or other I/O with your normal tools, outside this tool.";
|
|
1104
1178
|
return dedent`
|
|
1105
1179
|
### Interpreter
|
|
1106
1180
|
|
|
1107
1181
|
An \`${opts.toolName}\` tool is available. It runs JavaScript in a persistent REPL.
|
|
1108
1182
|
- State (variables, functions) persists across tool calls within a single turn of conversation. They DO NOT persist across multiple turns.
|
|
1109
1183
|
- Top-level \`await\` works; Promises resolve before the call returns.
|
|
1110
|
-
- Runtime sandbox: no built-in filesystem, network, stdlib, or wall-clock APIs (\`fetch\`, \`require\`, \`fs\`, \`process\`, real \`Date.now()\` are unavailable or stubbed)
|
|
1184
|
+
- Runtime sandbox: no built-in filesystem, network, stdlib, or wall-clock APIs (\`fetch\`, \`require\`, \`fs\`, \`process\`, real \`Date.now()\` are unavailable or stubbed).${sideEffects}
|
|
1111
1185
|
- Timeout: ${opts.timeout}s per call. Memory: ${opts.memoryLimitMb} MB total.
|
|
1112
1186
|
- \`console.log\` output is captured and returned alongside the result.
|
|
1113
1187
|
`;
|
|
@@ -1170,11 +1244,6 @@ function createCodeInterpreterMiddleware(options = {}) {
|
|
|
1170
1244
|
const { ptc, memoryLimitBytes = DEFAULT_MEMORY_LIMIT, maxStackSizeBytes = DEFAULT_MAX_STACK_SIZE, executionTimeoutMs = DEFAULT_EXECUTION_TIMEOUT, systemPrompt: customSystemPrompt = null, maxPtcCalls = 256, maxResultChars = DEFAULT_MAX_RESULTS_CHARS, toolName = DEFAULT_TOOL_NAME, captureConsole = true, subagents = true } = options;
|
|
1171
1245
|
const maxSubagentConcurrency = subagents ? 32 : 0;
|
|
1172
1246
|
if (maxPtcCalls !== null && maxPtcCalls !== void 0 && maxPtcCalls < 1) throw new Error("`maxPtcCalls` must be >= 1 or null");
|
|
1173
|
-
const baseSystemPrompt = customSystemPrompt || renderReplSystemPrompt({
|
|
1174
|
-
toolName,
|
|
1175
|
-
timeout: executionTimeoutMs / 1e3,
|
|
1176
|
-
memoryLimitMb: Math.floor(memoryLimitBytes / (1024 * 1024))
|
|
1177
|
-
});
|
|
1178
1247
|
const middlewareId = crypto.randomUUID();
|
|
1179
1248
|
let cachedPtcPrompt = null;
|
|
1180
1249
|
let ptcTools = [];
|
|
@@ -1197,16 +1266,16 @@ function createCodeInterpreterMiddleware(options = {}) {
|
|
|
1197
1266
|
...hasSchema && { [SUBAGENT_RESPONSE_FORMAT_CONFIG_KEY]: input.responseSchema }
|
|
1198
1267
|
}
|
|
1199
1268
|
};
|
|
1200
|
-
const
|
|
1269
|
+
const content = unwrapToolEnvelope(await subagentTaskTool.invoke({
|
|
1201
1270
|
description: input.description,
|
|
1202
1271
|
subagent_type: input.subagentType
|
|
1203
|
-
}, toolConfig);
|
|
1204
|
-
if (hasSchema && typeof
|
|
1205
|
-
return JSON.parse(
|
|
1272
|
+
}, toolConfig));
|
|
1273
|
+
if (hasSchema && typeof content === "string") try {
|
|
1274
|
+
return JSON.parse(content);
|
|
1206
1275
|
} catch {
|
|
1207
|
-
return
|
|
1276
|
+
return content;
|
|
1208
1277
|
}
|
|
1209
|
-
return
|
|
1278
|
+
return content;
|
|
1210
1279
|
};
|
|
1211
1280
|
}
|
|
1212
1281
|
return createMiddleware({
|
|
@@ -1244,6 +1313,12 @@ function createCodeInterpreterMiddleware(options = {}) {
|
|
|
1244
1313
|
ptcTools = filterToolsForPtc(agentTools);
|
|
1245
1314
|
if (!taskTool && maxSubagentConcurrency > 0) taskTool = findTaskTool(agentTools);
|
|
1246
1315
|
if (ptcTools.length > 0 && !cachedPtcPrompt) cachedPtcPrompt = await generatePtcPrompt(ptcTools);
|
|
1316
|
+
const baseSystemPrompt = customSystemPrompt || renderReplSystemPrompt({
|
|
1317
|
+
toolName,
|
|
1318
|
+
timeout: executionTimeoutMs / 1e3,
|
|
1319
|
+
memoryLimitMb: Math.floor(memoryLimitBytes / (1024 * 1024)),
|
|
1320
|
+
hasPtc: ptcTools.length > 0
|
|
1321
|
+
});
|
|
1247
1322
|
const subagentPrompt = taskTool && maxSubagentConcurrency > 0 ? renderSubagentPrompt(toolName) : "";
|
|
1248
1323
|
const systemMessage = request.systemMessage.concat(baseSystemPrompt).concat(subagentPrompt).concat(cachedPtcPrompt || "");
|
|
1249
1324
|
return handler({
|