@sema-agent/core 5.2.0 → 5.4.0
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/CHANGELOG.md +39 -0
- package/dist/brain/anthropic.js +12 -2
- package/dist/brain/media-degrade.d.ts +14 -0
- package/dist/brain/media-degrade.js +30 -0
- package/dist/brain/openai.js +9 -11
- package/dist/brain/timeout.d.ts +14 -0
- package/dist/brain/timeout.js +114 -0
- package/dist/core/a2a-task-state.d.ts +15 -0
- package/dist/core/a2a-task-state.js +68 -0
- package/dist/core/a2a.d.ts +42 -0
- package/dist/core/a2a.js +651 -0
- package/dist/core/checkpoint-store.d.ts +6 -1
- package/dist/core/checkpoint-store.js +3 -1
- package/dist/core/exec-output-tail.d.ts +0 -1
- package/dist/core/exec-output-tail.js +0 -6
- package/dist/core/mcp.d.ts +11 -4
- package/dist/core/mcp.js +11 -31
- package/dist/core/protocol-naming.d.ts +7 -0
- package/dist/core/protocol-naming.js +32 -0
- package/dist/core/protocol-table.d.ts +3 -1
- package/dist/core/protocol-table.js +37 -32
- package/dist/core/runner/prepare-task.d.ts +9 -0
- package/dist/core/runner/prepare-task.js +52 -15
- package/dist/core/runner/runtask.js +34 -4
- package/dist/core/runner/tool-disclosure.d.ts +1 -1
- package/dist/core/runner/tool-disclosure.js +1 -1
- package/dist/core/runner/turn-attachments.d.ts +1 -2
- package/dist/core/runner/turn-attachments.js +1 -12
- package/dist/core/store-contracts/background-agent-store-contract.d.ts +5 -0
- package/dist/core/store-contracts/background-agent-store-contract.js +213 -0
- package/dist/core/task-registry-agent.d.ts +14 -1
- package/dist/core/task-registry-agent.js +2 -2
- package/dist/core/types.d.ts +18 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +0 -1
- package/dist/engine/execution-env/node-execution-env.js +12 -30
- package/dist/index.d.ts +8 -3
- package/dist/index.js +6 -2
- package/dist/prompt-assembly/event-registry.js +1 -0
- package/dist/tools/fs/fs-read.js +5 -3
- package/dist/tools/fs/fs-shared.d.ts +1 -0
- package/dist/tools/fs/fs-shared.js +1 -0
- package/dist/tools/web.js +12 -4
- package/package.json +1 -1
|
@@ -30,4 +30,3 @@ export declare function sliceStreamIncrement(s: StreamCursorState, terminal: boo
|
|
|
30
30
|
droppedBeforeCursor: number;
|
|
31
31
|
};
|
|
32
32
|
export declare function markTruncated(text: string, droppedBytes: number): string;
|
|
33
|
-
export declare function markLiveSpoolRotations(text: string, liveRotations: number): string;
|
|
@@ -73,9 +73,3 @@ export function markTruncated(text, droppedBytes) {
|
|
|
73
73
|
? `[... ${droppedBytes} earlier byte(s) truncated; showing last ${Buffer.byteLength(text, "utf8")} ...]\n${text}`
|
|
74
74
|
: text;
|
|
75
75
|
}
|
|
76
|
-
export function markLiveSpoolRotations(text, liveRotations) {
|
|
77
|
-
if (liveRotations <= 0)
|
|
78
|
-
return text;
|
|
79
|
-
const note = `[spool reclaimed ${liveRotations} time(s) while the process was still writing; bytes appended during those windows may be missing beyond any counted truncation]`;
|
|
80
|
-
return text === "" ? note : `${text}${text.endsWith("\n") ? "" : "\n"}${note}`;
|
|
81
|
-
}
|
package/dist/core/mcp.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ProtocolId } from "./protocol-table.js";
|
|
1
2
|
import type { AgentTool } from "../internal/harness-types.js";
|
|
2
3
|
import type { ImageContent, TextContent } from "../internal/llm.js";
|
|
3
4
|
import { type McpImageResizer } from "./image-downsample.js";
|
|
@@ -69,14 +70,20 @@ export declare function mcpIdleTimeoutMs(kind: "stdio" | "http"): number;
|
|
|
69
70
|
export declare function describeMcpSpecErrorCode(code: unknown): string | undefined;
|
|
70
71
|
export declare function collapseMcpErrorPrefix(message: string): string;
|
|
71
72
|
export declare function networkErrorCode(err: unknown, depth?: number): string | undefined;
|
|
72
|
-
export
|
|
73
|
-
|
|
73
|
+
export interface HttpTransportFailure {
|
|
74
|
+
condition: string;
|
|
75
|
+
delivered: "no" | "unknown";
|
|
76
|
+
httpStatus?: number;
|
|
77
|
+
}
|
|
78
|
+
export declare function describeHttpTransportFailure(err: unknown): HttpTransportFailure | undefined;
|
|
79
|
+
export { normalizeNameSegment as normalizeMcpName, clampNameSegment } from "./protocol-naming.js";
|
|
74
80
|
export * from "./image-downsample.js";
|
|
75
81
|
export declare function inferCompactSchema(value: unknown, depth?: number): string;
|
|
76
|
-
export
|
|
82
|
+
export interface ProtocolHttpAuth {
|
|
77
83
|
headers?: Record<string, string>;
|
|
78
84
|
principalHeader?: string;
|
|
79
|
-
}
|
|
85
|
+
}
|
|
86
|
+
export declare function resolveProtocolHttpHeaders(protocol: ProtocolId, t: ProtocolHttpAuth, principal?: string): Record<string, string> | undefined;
|
|
80
87
|
interface McpContentItem {
|
|
81
88
|
type: string;
|
|
82
89
|
text?: string;
|
package/dist/core/mcp.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { MCP_NAMESPACE } from "./protocol-table.js";
|
|
2
|
+
import { mintNamespacePrefix, mintNamespacedToolName, normalizeNameSegment } from "./protocol-naming.js";
|
|
3
3
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4
4
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
5
5
|
import { StreamableHTTPClientTransport, StreamableHTTPError } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
@@ -12,7 +12,6 @@ import { sliceHeadSafe, sliceTailSafe } from "./surrogate-safe-slice.js";
|
|
|
12
12
|
import { truncateError } from "./tool-errors.js";
|
|
13
13
|
import { delimitUntrusted, inlineUntrusted, sanitizeUntrustedText } from "./untrusted-text.js";
|
|
14
14
|
import { validateJsonSchemaShape } from "./runner/strict-output-schema.js";
|
|
15
|
-
const NAME_SEP = "__";
|
|
16
15
|
export const MCP_PREFIX = MCP_NAMESPACE.prefix;
|
|
17
16
|
const MCP_OUTPUT_TOKENS_DEFAULT = 25_000;
|
|
18
17
|
const MCP_CHARS_PER_TOKEN = 4;
|
|
@@ -198,7 +197,7 @@ export function networkErrorCode(err, depth = 0) {
|
|
|
198
197
|
}
|
|
199
198
|
return networkErrorCode(err.cause, depth + 1);
|
|
200
199
|
}
|
|
201
|
-
function describeHttpTransportFailure(err) {
|
|
200
|
+
export function describeHttpTransportFailure(err) {
|
|
202
201
|
if (err instanceof McpError)
|
|
203
202
|
return undefined;
|
|
204
203
|
if (err instanceof StreamableHTTPError) {
|
|
@@ -297,19 +296,7 @@ function throwDeadServer(server, what) {
|
|
|
297
296
|
e.details = { server };
|
|
298
297
|
throw e;
|
|
299
298
|
}
|
|
300
|
-
export
|
|
301
|
-
const charset = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
302
|
-
return clampNameSegment(charset);
|
|
303
|
-
}
|
|
304
|
-
export function clampNameSegment(seg, max = 64) {
|
|
305
|
-
if (seg === "")
|
|
306
|
-
return "_";
|
|
307
|
-
if (seg.length <= max)
|
|
308
|
-
return seg;
|
|
309
|
-
const digest = createHash("sha256").update(seg).digest("hex").slice(0, 8);
|
|
310
|
-
const keep = max - digest.length - 1;
|
|
311
|
-
return keep > 0 ? `${seg.slice(0, keep)}_${digest}` : digest.slice(0, max);
|
|
312
|
-
}
|
|
299
|
+
export { normalizeNameSegment as normalizeMcpName, clampNameSegment } from "./protocol-naming.js";
|
|
313
300
|
export * from "./image-downsample.js";
|
|
314
301
|
const MCP_BLOB_DIR = join(tmpdir(), "sema-mcp-blobs");
|
|
315
302
|
function extensionForMime(mimeType) {
|
|
@@ -345,7 +332,7 @@ function extensionForMime(mimeType) {
|
|
|
345
332
|
async function persistMcpBlob(base64Data, mimeType, server) {
|
|
346
333
|
const bytes = Buffer.from(base64Data, "base64");
|
|
347
334
|
const ext = extensionForMime(mimeType);
|
|
348
|
-
const filePath = join(MCP_BLOB_DIR, `mcp-${
|
|
335
|
+
const filePath = join(MCP_BLOB_DIR, `mcp-${normalizeNameSegment(server ?? "server")}-blob-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.${ext}`);
|
|
349
336
|
try {
|
|
350
337
|
await mkdir(MCP_BLOB_DIR, { recursive: true, mode: 0o700 });
|
|
351
338
|
const st = await lstat(MCP_BLOB_DIR);
|
|
@@ -409,10 +396,10 @@ export function inferCompactSchema(value, depth = 2) {
|
|
|
409
396
|
}
|
|
410
397
|
return typeof value;
|
|
411
398
|
}
|
|
412
|
-
export function
|
|
399
|
+
export function resolveProtocolHttpHeaders(protocol, t, principal) {
|
|
413
400
|
if (t.principalHeader && principal !== undefined) {
|
|
414
401
|
if (/[\r\n]/.test(principal))
|
|
415
|
-
throw new Error(
|
|
402
|
+
throw new Error(`${protocol}: principal must not contain CR/LF (header injection guard)`);
|
|
416
403
|
return { ...t.headers, [t.principalHeader]: principal };
|
|
417
404
|
}
|
|
418
405
|
return t.headers;
|
|
@@ -426,7 +413,7 @@ function buildTransport(spec, principal) {
|
|
|
426
413
|
env: t.env,
|
|
427
414
|
});
|
|
428
415
|
}
|
|
429
|
-
const headers =
|
|
416
|
+
const headers = resolveProtocolHttpHeaders(MCP_NAMESPACE.id, t, principal);
|
|
430
417
|
return new StreamableHTTPClientTransport(new URL(t.url), {
|
|
431
418
|
requestInit: headers ? { headers } : undefined,
|
|
432
419
|
});
|
|
@@ -667,7 +654,7 @@ export async function materializeMcpTools(specs, principal, onElicit, imageResiz
|
|
|
667
654
|
droppedTools,
|
|
668
655
|
statuses,
|
|
669
656
|
refresh: async (server) => {
|
|
670
|
-
const prefixOf = (name) =>
|
|
657
|
+
const prefixOf = (name) => mintNamespacePrefix(MCP_NAMESPACE, name);
|
|
671
658
|
const targets = server !== undefined ? serverHandles.filter((h) => h.name === server) : serverHandles;
|
|
672
659
|
const results = [];
|
|
673
660
|
if (server !== undefined && targets.length === 0) {
|
|
@@ -1149,14 +1136,14 @@ function intakeListedTools(listed, spec, client, health, imageResizer) {
|
|
|
1149
1136
|
}
|
|
1150
1137
|
const normalized = normalizeMcpToolSchema(t.inputSchema);
|
|
1151
1138
|
let effectiveInputSchema = t.inputSchema;
|
|
1152
|
-
let effectiveDescription = t.description;
|
|
1139
|
+
let effectiveDescription = t.description !== undefined ? sanitizeUntrustedText(t.description) : undefined;
|
|
1153
1140
|
if (normalized.outcome === "drop") {
|
|
1154
1141
|
dropped.push({ tool: inlineUntrusted(t.name), reason: inlineUntrusted(normalized.reason, 240) });
|
|
1155
1142
|
continue;
|
|
1156
1143
|
}
|
|
1157
1144
|
if (normalized.outcome === "normalized") {
|
|
1158
1145
|
effectiveInputSchema = normalized.schema;
|
|
1159
|
-
effectiveDescription = normalized.note + (
|
|
1146
|
+
effectiveDescription = normalized.note + (effectiveDescription ? `\n\n${effectiveDescription}` : "");
|
|
1160
1147
|
}
|
|
1161
1148
|
const schemaProblem = mcpToolSchemaProblem(effectiveInputSchema);
|
|
1162
1149
|
if (schemaProblem !== undefined) {
|
|
@@ -1164,14 +1151,7 @@ function intakeListedTools(listed, spec, client, health, imageResizer) {
|
|
|
1164
1151
|
continue;
|
|
1165
1152
|
}
|
|
1166
1153
|
const remoteName = t.name;
|
|
1167
|
-
const namespacedName = (
|
|
1168
|
-
const TOOL_MIN = 16;
|
|
1169
|
-
const fixed = MCP_PREFIX.length + NAME_SEP.length;
|
|
1170
|
-
const serverBudget = Math.max(1, 64 - fixed - TOOL_MIN);
|
|
1171
|
-
const server = clampNameSegment(normalizeMcpName(spec.name), serverBudget);
|
|
1172
|
-
const prefix = `${MCP_PREFIX}${server}${NAME_SEP}`;
|
|
1173
|
-
return `${prefix}${clampNameSegment(normalizeMcpName(remoteName), Math.max(1, 64 - prefix.length))}`;
|
|
1174
|
-
})();
|
|
1154
|
+
const namespacedName = mintNamespacedToolName(MCP_NAMESPACE, spec.name, remoteName);
|
|
1175
1155
|
const hintAxis = mcpAxisFor(namespacedName, t.annotations);
|
|
1176
1156
|
const axis = applyCallerAxisOverride(namespacedName, hintAxis, spec.toolAxes?.[remoteName]);
|
|
1177
1157
|
if (axis)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProtocolNamespace } from "./protocol-table.js";
|
|
2
|
+
export declare const TOOL_NAME_MAX_CHARS = 64;
|
|
3
|
+
export declare const MINTED_TOOL_SEGMENT_MIN_CHARS = 16;
|
|
4
|
+
export declare function normalizeNameSegment(name: string): string;
|
|
5
|
+
export declare function clampNameSegment(seg: string, max?: number): string;
|
|
6
|
+
export declare function mintNamespacePrefix(ns: ProtocolNamespace, peer: string): string;
|
|
7
|
+
export declare function mintNamespacedToolName(ns: ProtocolNamespace, peer: string, tool: string): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const TOOL_NAME_MAX_CHARS = 64;
|
|
3
|
+
export const MINTED_TOOL_SEGMENT_MIN_CHARS = 16;
|
|
4
|
+
const SEGMENT_DIGEST_CHARS = 8;
|
|
5
|
+
const NAME_SEP = "__";
|
|
6
|
+
export function normalizeNameSegment(name) {
|
|
7
|
+
return clampNameSegment(name.replace(/[^a-zA-Z0-9_-]/g, "_"));
|
|
8
|
+
}
|
|
9
|
+
const SEGMENT_DIGEST_JOIN = "-";
|
|
10
|
+
export function clampNameSegment(seg, max = TOOL_NAME_MAX_CHARS) {
|
|
11
|
+
if (seg === "")
|
|
12
|
+
return "_";
|
|
13
|
+
if (seg.length <= max)
|
|
14
|
+
return seg;
|
|
15
|
+
const digest = createHash("sha256").update(seg).digest("hex").slice(0, SEGMENT_DIGEST_CHARS);
|
|
16
|
+
const keep = max - digest.length - SEGMENT_DIGEST_JOIN.length;
|
|
17
|
+
return keep > 0 ? `${seg.slice(0, keep)}${SEGMENT_DIGEST_JOIN}${digest}` : digest.slice(0, max);
|
|
18
|
+
}
|
|
19
|
+
function settlePeerSegment(clamped) {
|
|
20
|
+
const folded = clamped.replace(/_{2,}/g, "_").replace(/_+$/, "");
|
|
21
|
+
if (folded !== "")
|
|
22
|
+
return folded;
|
|
23
|
+
return createHash("sha256").update(clamped).digest("hex").slice(0, SEGMENT_DIGEST_CHARS);
|
|
24
|
+
}
|
|
25
|
+
export function mintNamespacePrefix(ns, peer) {
|
|
26
|
+
const peerBudget = Math.max(1, TOOL_NAME_MAX_CHARS - ns.prefix.length - NAME_SEP.length - MINTED_TOOL_SEGMENT_MIN_CHARS);
|
|
27
|
+
return `${ns.prefix}${settlePeerSegment(clampNameSegment(normalizeNameSegment(peer), peerBudget))}${NAME_SEP}`;
|
|
28
|
+
}
|
|
29
|
+
export function mintNamespacedToolName(ns, peer, tool) {
|
|
30
|
+
const prefix = mintNamespacePrefix(ns, peer);
|
|
31
|
+
return `${prefix}${clampNameSegment(normalizeNameSegment(tool), Math.max(1, TOOL_NAME_MAX_CHARS - prefix.length))}`;
|
|
32
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ProtocolId = "mcp";
|
|
1
|
+
export type ProtocolId = "mcp" | "a2a";
|
|
2
2
|
export interface ProtocolPeerTool {
|
|
3
3
|
peer: string;
|
|
4
4
|
tool: string;
|
|
@@ -11,7 +11,9 @@ export interface ProtocolNamespace<P extends string = string> {
|
|
|
11
11
|
displayGroupKey(name: string): string;
|
|
12
12
|
}
|
|
13
13
|
declare const MCP_PREFIX_NAME: "mcp__";
|
|
14
|
+
declare const A2A_PREFIX_NAME: "a2a__";
|
|
14
15
|
export declare const MCP_NAMESPACE: ProtocolNamespace<typeof MCP_PREFIX_NAME>;
|
|
16
|
+
export declare const A2A_NAMESPACE: ProtocolNamespace<typeof A2A_PREFIX_NAME>;
|
|
15
17
|
export declare const PROTOCOL_TABLE: readonly ProtocolNamespace[];
|
|
16
18
|
export declare function protocolOf(name: string): ProtocolNamespace | undefined;
|
|
17
19
|
export {};
|
|
@@ -1,37 +1,42 @@
|
|
|
1
1
|
const NAME_SEP = "__";
|
|
2
|
+
function makeProtocolNamespace(id, prefix) {
|
|
3
|
+
const parse = (name) => {
|
|
4
|
+
if (!name.startsWith(prefix))
|
|
5
|
+
return undefined;
|
|
6
|
+
const rest = name.slice(prefix.length);
|
|
7
|
+
const sep = rest.indexOf(NAME_SEP);
|
|
8
|
+
if (sep <= 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
const tool = rest.slice(sep + NAME_SEP.length);
|
|
11
|
+
if (tool.length === 0)
|
|
12
|
+
return undefined;
|
|
13
|
+
return { peer: rest.slice(0, sep), tool };
|
|
14
|
+
};
|
|
15
|
+
const makeName = (peer, tool) => {
|
|
16
|
+
if (peer.length === 0 || tool.length === 0) {
|
|
17
|
+
throw new Error(`protocol table (${id}): peer and tool must both be non-empty (got peer=${JSON.stringify(peer)}, tool=${JSON.stringify(tool)})`);
|
|
18
|
+
}
|
|
19
|
+
if (peer.includes(NAME_SEP)) {
|
|
20
|
+
throw new Error(`protocol table (${id}): peer must not contain the ${NAME_SEP} separator (got ${JSON.stringify(peer)}) — the composed name would parse back as a DIFFERENT peer`);
|
|
21
|
+
}
|
|
22
|
+
return `${prefix}${peer}${NAME_SEP}${tool}`;
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
id,
|
|
26
|
+
prefix,
|
|
27
|
+
makeName,
|
|
28
|
+
parse,
|
|
29
|
+
displayGroupKey: (name) => {
|
|
30
|
+
const p = parse(name);
|
|
31
|
+
return p === undefined ? name : `${prefix}${p.peer}${NAME_SEP}*`;
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
2
35
|
const MCP_PREFIX_NAME = `mcp${NAME_SEP}`;
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const sep = rest.indexOf(NAME_SEP);
|
|
8
|
-
if (sep <= 0)
|
|
9
|
-
return undefined;
|
|
10
|
-
const tool = rest.slice(sep + NAME_SEP.length);
|
|
11
|
-
if (tool.length === 0)
|
|
12
|
-
return undefined;
|
|
13
|
-
return { peer: rest.slice(0, sep), tool };
|
|
14
|
-
};
|
|
15
|
-
const makeMcpName = (peer, tool) => {
|
|
16
|
-
if (peer.length === 0 || tool.length === 0) {
|
|
17
|
-
throw new Error(`protocol table (mcp): peer and tool must both be non-empty (got peer=${JSON.stringify(peer)}, tool=${JSON.stringify(tool)})`);
|
|
18
|
-
}
|
|
19
|
-
if (peer.includes(NAME_SEP)) {
|
|
20
|
-
throw new Error(`protocol table (mcp): peer must not contain the ${NAME_SEP} separator (got ${JSON.stringify(peer)}) — the composed name would parse back as a DIFFERENT peer`);
|
|
21
|
-
}
|
|
22
|
-
return `${MCP_PREFIX_NAME}${peer}${NAME_SEP}${tool}`;
|
|
23
|
-
};
|
|
24
|
-
export const MCP_NAMESPACE = {
|
|
25
|
-
id: "mcp",
|
|
26
|
-
prefix: MCP_PREFIX_NAME,
|
|
27
|
-
makeName: makeMcpName,
|
|
28
|
-
parse: parseMcpName,
|
|
29
|
-
displayGroupKey: (name) => {
|
|
30
|
-
const p = parseMcpName(name);
|
|
31
|
-
return p === undefined ? name : `${MCP_PREFIX_NAME}${p.peer}${NAME_SEP}*`;
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
export const PROTOCOL_TABLE = [MCP_NAMESPACE];
|
|
36
|
+
const A2A_PREFIX_NAME = `a2a${NAME_SEP}`;
|
|
37
|
+
export const MCP_NAMESPACE = makeProtocolNamespace("mcp", MCP_PREFIX_NAME);
|
|
38
|
+
export const A2A_NAMESPACE = makeProtocolNamespace("a2a", A2A_PREFIX_NAME);
|
|
39
|
+
export const PROTOCOL_TABLE = [MCP_NAMESPACE, A2A_NAMESPACE];
|
|
35
40
|
export function protocolOf(name) {
|
|
36
41
|
return PROTOCOL_TABLE.find((ns) => name.startsWith(ns.prefix));
|
|
37
42
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AgentHarness, type ThinkingLevel } from "../../internal/harness.js";
|
|
2
2
|
import type { Model } from "../../internal/llm.js";
|
|
3
3
|
import { type MaterializedMcp } from "../mcp.js";
|
|
4
|
+
import { type MaterializedA2a } from "../a2a.js";
|
|
4
5
|
import type { HarvestReport, MemorySessionHandle } from "../memory-engine/types.js";
|
|
5
6
|
import { StoredSession } from "../session.js";
|
|
6
7
|
import type { SessionStore } from "../session.js";
|
|
@@ -10,11 +11,13 @@ import { type ActiveSkillFrame } from "./active-skill-scope.js";
|
|
|
10
11
|
import { type CutKillRegistry } from "./cut-kill.js";
|
|
11
12
|
import type { SessionPermissionRules } from "../session-policy-store.js";
|
|
12
13
|
import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-detector.js";
|
|
14
|
+
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
|
|
13
15
|
import { type OutputRef, type BlockedRef, type SkillListingEntry } from "./synthetic-tools.js";
|
|
14
16
|
import type { MemoryEngine } from "../memory-engine/engine.js";
|
|
15
17
|
import { type ToolManifestRow } from "../../prompt-assembly/tool-catalog.js";
|
|
16
18
|
import type { TaskNotificationPayload } from "../task-notification.js";
|
|
17
19
|
import { type CwdRef } from "../../tools/fs/index.js";
|
|
20
|
+
import { type WorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
18
21
|
import type { Runner } from "./runtask.js";
|
|
19
22
|
import { type CheckpointGate, type CheckpointState, type CheckpointToken, type ResourceLedger, type ResourceLimitReason } from "../checkpoint-store.js";
|
|
20
23
|
import type { ActiveWorktreeSession, AgentMessage, AgentTool, ExecutionEnv } from "../../internal/harness.js";
|
|
@@ -36,6 +39,7 @@ export interface Prepared {
|
|
|
36
39
|
thinking?: ThinkingLevel;
|
|
37
40
|
compModel?: Model;
|
|
38
41
|
mcp: MaterializedMcp;
|
|
42
|
+
a2a?: MaterializedA2a;
|
|
39
43
|
blockedRef: BlockedRef;
|
|
40
44
|
outputRef: OutputRef;
|
|
41
45
|
abortController: AbortController;
|
|
@@ -133,6 +137,7 @@ export interface Prepared {
|
|
|
133
137
|
callIssuedAtRef?: {
|
|
134
138
|
current?: number;
|
|
135
139
|
};
|
|
140
|
+
brainCallGuardrailRef: BrainCallGuardrailRef;
|
|
136
141
|
reviewRequestRef: {
|
|
137
142
|
pending?: {
|
|
138
143
|
reason?: string;
|
|
@@ -186,6 +191,10 @@ export interface Prepared {
|
|
|
186
191
|
path: string;
|
|
187
192
|
contentHash: string | null;
|
|
188
193
|
}>;
|
|
194
|
+
workflowSizeGuideline?: {
|
|
195
|
+
legGuideline: WorkflowSizeGuideline;
|
|
196
|
+
current: () => WorkflowSizeGuideline;
|
|
197
|
+
};
|
|
189
198
|
detectExternalChanges?: (maxFiles: number) => Promise<{
|
|
190
199
|
changed: Array<{
|
|
191
200
|
path: string;
|
|
@@ -9,6 +9,7 @@ import { buildAutoModePrompt, renderAutoModeAction, renderAutoModeWindow } from
|
|
|
9
9
|
import { resolveModel, resolveTaskModel, roleModelIfSet } from "../roles.js";
|
|
10
10
|
import { primaryActivityArg } from "../arg-summary.js";
|
|
11
11
|
import { materializeMcpTools } from "../mcp.js";
|
|
12
|
+
import { materializeA2aTools } from "../a2a.js";
|
|
12
13
|
import { Type } from "typebox";
|
|
13
14
|
import { brainToRuntime } from "../runtime.js";
|
|
14
15
|
import { StoredSession, isSessionConflict, hasSessionFork } from "../session.js";
|
|
@@ -28,9 +29,10 @@ import { cloneObserverInput, formatHookFeedback, runToolGate } from "../hooks.js
|
|
|
28
29
|
import { reconcileInterruptedSession } from "../session-reconcile.js";
|
|
29
30
|
import { CacheBreakDetector, toolsToFingerprintInputs } from "../cache-break-detector.js";
|
|
30
31
|
import { reservedCollisions, reservedFor } from "../../brain/request-params.js";
|
|
32
|
+
import { resolveBrainCallGuardrailMs, withBrainCallGuardrail } from "../../brain/timeout.js";
|
|
31
33
|
import { defineTool, isDefineToolProduct } from "../tools.js";
|
|
32
34
|
import { RETIRED_TOOL_NAMES } from "../tool-name-aliases.js";
|
|
33
|
-
import { protocolOf } from "../protocol-table.js";
|
|
35
|
+
import { protocolOf, PROTOCOL_TABLE } from "../protocol-table.js";
|
|
34
36
|
import { pathToUri } from "../lsp-protocol.js";
|
|
35
37
|
import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, createOffloadPersist, firstPartyOffloadPolicy, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, isVolatileOffloadStore, OFFLOAD_TOOL_NAME, createReadToolResultTool, withToolResultOffload, } from "../tool-result-store.js";
|
|
36
38
|
import { OUTPUT_TOOL_NAME, REPORT_FINDINGS_TOOL_NAME, SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createOutputTool, createReportBlockedTool, createReportFindingsTool, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
|
|
@@ -64,6 +66,7 @@ import { createSchedulerTools } from "../../tools/scheduler-tools.js";
|
|
|
64
66
|
import { createPresentPlanTool, createEnterPlanModeTool, PRESENT_PLAN_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME } from "../present-plan-tool.js";
|
|
65
67
|
import { isSelfOrchestrationActive, selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
|
|
66
68
|
import { createRunWorkflowTool, RUN_WORKFLOW_TOOL_NAME } from "../../orchestration/run-workflow-tool.js";
|
|
69
|
+
import { resolveWorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
67
70
|
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
68
71
|
import { resolveKey } from "../../tools/fs/safety.js";
|
|
69
72
|
import { BINDING_CHECKPOINT_VERSION, mintCheckpointToken, RESOURCE_CHECKPOINT_VERSION, WALLTIME_CHECKPOINT_VERSION, buildRiskDescriptor, debitLedger, remainingBudgetMicroUsd, } from "../checkpoint-store.js";
|
|
@@ -82,6 +85,7 @@ function sanitizedTtlMs(ttlMs) {
|
|
|
82
85
|
const ungatedWarnedShapes = new WeakMap();
|
|
83
86
|
const advisedPolicyNames = new WeakMap();
|
|
84
87
|
const ADVISED_KEYS_CAP = 64;
|
|
88
|
+
const NAMESPACED_NAME_SHAPES = PROTOCOL_TABLE.map((ns) => `${ns.prefix}<peer>__<tool>`).join(", ");
|
|
85
89
|
export const DEFAULT_IRREVERSIBLE_SCOPE = "irreversible";
|
|
86
90
|
export function checkpointScopeOf(spec) {
|
|
87
91
|
return spec.durableApproval?.scope || spec.principal || DEFAULT_IRREVERSIBLE_SCOPE;
|
|
@@ -233,6 +237,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
233
237
|
e.code = "config.empty_objective";
|
|
234
238
|
throw e;
|
|
235
239
|
}
|
|
240
|
+
const brainCallGuardrailRef = {};
|
|
241
|
+
const brainCallGuardrailMs = resolveBrainCallGuardrailMs(spec.limits?.brainCallGuardrailMs ?? deps.brainCallGuardrailMs);
|
|
236
242
|
if (spec.agents !== undefined && spec.agents.length > 0) {
|
|
237
243
|
const pool = spec.tools ?? [];
|
|
238
244
|
if (!pool.some((t) => typeof t.withAgents === "function")) {
|
|
@@ -261,7 +267,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
261
267
|
let shellGatedMonitor = false;
|
|
262
268
|
for (const t of spec.tools ?? []) {
|
|
263
269
|
if (t.name.includes("__")) {
|
|
264
|
-
const e = new Error(`Tool name "${t.name}" is invalid: "__" is reserved for the
|
|
270
|
+
const e = new Error(`Tool name "${t.name}" is invalid: "__" is reserved for the engine's protocol tool namespaces (${NAMESPACED_NAME_SHAPES}) and must not appear in a caller tool name.`);
|
|
265
271
|
e.code = "config.tool_name_invalid";
|
|
266
272
|
throw e;
|
|
267
273
|
}
|
|
@@ -479,7 +485,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
479
485
|
return maybeOffload(tool, policy);
|
|
480
486
|
return maybeOffload(tool, explicitGlobalThreshold === undefined ? policy : undefined);
|
|
481
487
|
};
|
|
482
|
-
const
|
|
488
|
+
const remoteToolOffload = (tool) => {
|
|
483
489
|
if (explicitGlobalThreshold !== undefined)
|
|
484
490
|
return maybeOffload(tool);
|
|
485
491
|
return maybeOffload(tool, { offloadThresholdChars: tool.mcpMaxResultSizeChars ?? 50_000 });
|
|
@@ -492,6 +498,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
492
498
|
}
|
|
493
499
|
let ownedEnv;
|
|
494
500
|
let mcp;
|
|
501
|
+
let a2a;
|
|
495
502
|
if (internals?.requestedCwd !== undefined && deps.executionEnvFactory === undefined) {
|
|
496
503
|
await settleTeardownLeg(() => forgetOnThrow(), "forgetOnThrow (cwd-unsupported leg)", (err) => deps.onError?.(err, { phase: "config", sessionId }));
|
|
497
504
|
const e = new Error(`Agent cwd "${internals.requestedCwd}" cannot take effect: this deployment has no executionEnvFactory (a static execution environment cannot be re-rooted per agent). Drop the cwd parameter or deploy a factory.`);
|
|
@@ -969,8 +976,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
969
976
|
`(per-principal entitlement governance, not a misconfiguration — the run_workflow tool is not mounted)`), { phase: "config", sessionId });
|
|
970
977
|
}
|
|
971
978
|
let workflowToolsActive = false;
|
|
979
|
+
let workflowSizeGuideline;
|
|
972
980
|
if (selfOrchestrationActive && runnerSelf && deps.workflowScriptRunner && deps.workflowGovernanceBaseline) {
|
|
973
981
|
workflowToolsActive = true;
|
|
982
|
+
const currentSizeGuideline = () => resolveWorkflowSizeGuideline(deps.workflowLimits?.sizeGuideline).size;
|
|
983
|
+
workflowSizeGuideline = { legGuideline: currentSizeGuideline(), current: currentSizeGuideline };
|
|
974
984
|
toolEffects.set(RUN_WORKFLOW_TOOL_NAME, "write");
|
|
975
985
|
tools.push(await createRunWorkflowTool({
|
|
976
986
|
runner: runnerSelf,
|
|
@@ -1093,7 +1103,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1093
1103
|
throw e;
|
|
1094
1104
|
}
|
|
1095
1105
|
}
|
|
1096
|
-
tools.push(...mcp.tools.map((t) =>
|
|
1106
|
+
tools.push(...mcp.tools.map((t) => remoteToolOffload(t)));
|
|
1097
1107
|
const rebuildHarnessToolsRef = {};
|
|
1098
1108
|
const toolCallGateArmedRef = { armed: false };
|
|
1099
1109
|
if (spec.mcp?.length) {
|
|
@@ -1121,7 +1131,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1121
1131
|
const pushable = r.tools.filter((t) => !excludedSet.has(t.name));
|
|
1122
1132
|
const excludedNow = r.tools.filter((t) => excludedSet.has(t.name)).map((t) => t.name);
|
|
1123
1133
|
try {
|
|
1124
|
-
|
|
1134
|
+
foldProtocolAxes((r.axes ?? []).filter((a) => !excludedSet.has(a.name)), "MCP");
|
|
1125
1135
|
}
|
|
1126
1136
|
catch (foldErr) {
|
|
1127
1137
|
lines.push(`${r.server}: failed (${foldErr instanceof Error ? foldErr.message : String(foldErr)})`);
|
|
@@ -1135,7 +1145,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1135
1145
|
tools.splice(i, 1);
|
|
1136
1146
|
}
|
|
1137
1147
|
}
|
|
1138
|
-
tools.push(...pushable.map((t) =>
|
|
1148
|
+
tools.push(...pushable.map((t) => remoteToolOffload(t)));
|
|
1139
1149
|
changed = true;
|
|
1140
1150
|
const detail = [];
|
|
1141
1151
|
const shownAdded = r.added.filter((n) => !excludedSet.has(n));
|
|
@@ -1165,7 +1175,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1165
1175
|
});
|
|
1166
1176
|
toolEffects.set("RefreshMcpTools", "read");
|
|
1167
1177
|
}
|
|
1168
|
-
const
|
|
1178
|
+
const foldProtocolAxes = (axes, protocolLabel) => {
|
|
1169
1179
|
for (const axis of axes) {
|
|
1170
1180
|
if (axis.irreversibility === "always") {
|
|
1171
1181
|
irreversibilityTier.set(axis.name, "always");
|
|
@@ -1173,7 +1183,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1173
1183
|
}
|
|
1174
1184
|
if (axis.egress) {
|
|
1175
1185
|
if (axis.effect !== undefined && axis.effect !== "write") {
|
|
1176
|
-
const e = new Error(
|
|
1186
|
+
const e = new Error(`${protocolLabel} tool "${axis.name}" resolves to egress:true with effect:"${axis.effect}" — an egress tool (external write) must have effect:"write". Clear egress (toolAxes egress:false) if it is a pure read, or set effect:"write".`);
|
|
1177
1187
|
e.code = "config.egress_requires_write_effect";
|
|
1178
1188
|
throw e;
|
|
1179
1189
|
}
|
|
@@ -1183,7 +1193,25 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1183
1193
|
toolEffects.set(axis.name, axis.effect ?? "write");
|
|
1184
1194
|
}
|
|
1185
1195
|
};
|
|
1186
|
-
|
|
1196
|
+
foldProtocolAxes(mcp.toolAxes, "MCP");
|
|
1197
|
+
a2a = spec.a2a?.length
|
|
1198
|
+
? await materializeA2aTools(spec.a2a, spec.principal, abortController.signal)
|
|
1199
|
+
: { tools: [], toolAxes: [], warnings: [], statuses: [], refresh: async () => [], dispose: async () => { } };
|
|
1200
|
+
for (const w of a2a.warnings)
|
|
1201
|
+
deps.onError?.(w, { phase: "a2a", sessionId });
|
|
1202
|
+
{
|
|
1203
|
+
const callerNames = new Set((spec.tools ?? []).flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
1204
|
+
const clash = a2a.tools.find((t) => callerNames.has(t.name));
|
|
1205
|
+
if (clash) {
|
|
1206
|
+
await a2a.dispose();
|
|
1207
|
+
await mcp.dispose();
|
|
1208
|
+
const e = new Error(`Tool name "${clash.name}" is reserved by an injected A2A tool — a caller tool of the same name would silently shadow it.`);
|
|
1209
|
+
e.code = "config.reserved_tool_name";
|
|
1210
|
+
throw e;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
tools.push(...a2a.tools.map((t) => remoteToolOffload(t)));
|
|
1214
|
+
foldProtocolAxes(a2a.toolAxes, "A2A");
|
|
1187
1215
|
const callCapOn = spec.limits?.callCapByDeadline !== false;
|
|
1188
1216
|
const callCapRef = spec.limits?.timeoutSec &&
|
|
1189
1217
|
spec.limits.timeoutSec > 0 &&
|
|
@@ -1861,11 +1889,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
1861
1889
|
}
|
|
1862
1890
|
}
|
|
1863
1891
|
const userToolNames = (spec.tools ?? []).map((t) => t.name);
|
|
1864
|
-
const
|
|
1892
|
+
const protocolToolNames = [...mcp.tools.map((t) => t.name), ...a2a.tools.map((t) => t.name)];
|
|
1865
1893
|
const deferred = classifyDeferred({
|
|
1866
1894
|
specs: spec.tools ?? [],
|
|
1867
|
-
|
|
1868
|
-
fullTools: tools.filter((t) => userToolNames.includes(t.name) ||
|
|
1895
|
+
protocolToolNames,
|
|
1896
|
+
fullTools: tools.filter((t) => userToolNames.includes(t.name) || protocolToolNames.includes(t.name)),
|
|
1869
1897
|
deferMode: deps.deferMode,
|
|
1870
1898
|
model,
|
|
1871
1899
|
deferNames: (toolFaceSnapshot.defer ?? []).filter((n) => tools.some((t) => t.name === n)),
|
|
@@ -2173,7 +2201,12 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2173
2201
|
systemPrompt,
|
|
2174
2202
|
...(assembled.systemBlocks ? { systemBlocks: assembled.systemBlocks } : {}),
|
|
2175
2203
|
getApiKeyAndHeaders: spec.getApiKeyAndHeaders,
|
|
2176
|
-
runtime: brainToRuntime(
|
|
2204
|
+
runtime: brainToRuntime(brainCallGuardrailMs === undefined
|
|
2205
|
+
? deps.brain
|
|
2206
|
+
: {
|
|
2207
|
+
...deps.brain,
|
|
2208
|
+
stream: withBrainCallGuardrail((m, c, o) => deps.brain.stream(m, c, o), brainCallGuardrailMs, brainCallGuardrailRef),
|
|
2209
|
+
}),
|
|
2177
2210
|
});
|
|
2178
2211
|
harnessRef.current = harness;
|
|
2179
2212
|
let releaseSignal = () => undefined;
|
|
@@ -2211,7 +2244,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
2211
2244
|
throw err;
|
|
2212
2245
|
}
|
|
2213
2246
|
if (n.includes("__") && protocolOf(n) === undefined) {
|
|
2214
|
-
const err = new Error(`tool policy ${kind}-list entry "${n}"
|
|
2247
|
+
const err = new Error(`tool policy ${kind}-list entry "${n}" carries the "__" namespace separator but no protocol prefix, and matches nothing in this run's roster — protocol tools are named ${NAMESPACED_NAME_SHAPES}, and legacy-name normalization was removed (RB-476-A), so this entry would silently guard nothing. Prefix the entry with the owning protocol's marker.`);
|
|
2215
2248
|
err.code = "config.legacy_tool_name";
|
|
2216
2249
|
throw err;
|
|
2217
2250
|
}
|
|
@@ -3504,12 +3537,16 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
3504
3537
|
: undefined;
|
|
3505
3538
|
overheadState.promptChars = systemPrompt.length;
|
|
3506
3539
|
const preparedHolder = {};
|
|
3507
|
-
const buildPrepared = () => ({ harness, session, sessionId, taskRootPath, model, thinking, compModel, mcp: mcp, blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), releaseSignal, cacheBreakDetector, cacheFingerprint, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), ownedEnv, suspendRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(callCapRef ? { callCapRef } : {}), ...(cutKills ? { cutKills } : {}), ...(callCapRef ? { callIssuedAtRef } : {}), suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, promptOverheadTokens, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
3540
|
+
const buildPrepared = () => ({ harness, session, sessionId, taskRootPath, model, thinking, compModel, mcp: mcp, ...(a2a !== undefined && a2a.tools.length > 0 ? { a2a } : {}), blockedRef, outputRef, abortController, conflictRef, blockedToolCalls, nestedStats, ...(rewindNotes.length > 0 ? { rewindNotes } : {}), cwdRef: handsCwdRef, ...(worktreeSessionRef !== undefined ? { worktreeSessionRef } : {}), ...(workspaceStateSettle !== undefined ? { workspaceStateSettle } : {}), denyNarrowingPolicy, ...(basePolicyForResumeEdit !== undefined ? { basePolicyForResumeEdit } : {}), releaseSignal, cacheBreakDetector, cacheFingerprint, promptManifest, epochDeclaredSections, activeTools, ...(deferred.size > 0 ? { deferredToolNames: deferred } : {}), ownedEnv, suspendRef, reviewRef, remoteEnvFailures, reviewRequestRef, suspendLoopRef, suspendForResource, ...(callCapRef ? { callCapRef } : {}), ...(cutKills ? { cutKills } : {}), ...(callCapRef ? { callIssuedAtRef } : {}), brainCallGuardrailRef, suspendForReview, resourceLedger: priorLedger, liveSpendRef, humanReviewRef, now, tools, toolEffects, promptOverheadTokens, readTaskFile, recentlyReadFiles, normalizeAttachmentPath, isDedupStubResult, ...(onCompactionApplied ? { onCompactionApplied } : {}), compactionReuseRef, trimPressureRef, ...(memoryEngineSession ? { memoryEngineSession } : {}), ...(subagentRetain ? { subagentRetain } : {}), ...(lspDiagnostics && nudgeLspOnEdit ? { lspDiagnostics: { registry: lspDiagnostics, nudge: nudgeLspOnEdit } } : {}), planModeRef, ...(dateChange ? { dateChange } : {}), ...(instructionSources ? { instructionSources } : {}), ...(workflowSizeGuideline ? { workflowSizeGuideline } : {}), ...(detectExternalChanges ? { detectExternalChanges } : {}), ...(toolsDeltaRef ? { toolsDeltaRef } : {}), ...(agentListing ? { agentListing } : {}), ...(skillsListing ? { skillsListing } : {}), announcedListingsRef, listBackgroundTasks, ...(turnSnapshotRef.current !== undefined ? { turnSnapshot: turnSnapshotRef.current } : {}), ...(centerCompactionCandidate !== undefined ? { centerCompactionCandidate } : {}) });
|
|
3508
3541
|
const prepared = buildPrepared();
|
|
3509
3542
|
preparedHolder.current = prepared;
|
|
3510
3543
|
return prepared;
|
|
3511
3544
|
}
|
|
3512
3545
|
catch (prepareErr) {
|
|
3546
|
+
if (a2a) {
|
|
3547
|
+
const a2aHandle = a2a;
|
|
3548
|
+
await settleTeardownLeg(() => a2aHandle.dispose(), "a2a.dispose (prepare-throw leg)", (e) => deps.onError?.(e, { phase: "config", sessionId }));
|
|
3549
|
+
}
|
|
3513
3550
|
if (mcp) {
|
|
3514
3551
|
const mcpHandle = mcp;
|
|
3515
3552
|
await settleTeardownLeg(() => mcpHandle.dispose(), "mcp.dispose (prepare-throw leg)", (e) => deps.onError?.(e, { phase: "config", sessionId }));
|