@sema-agent/core 1.397.0 → 1.398.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/dist/core/mcp.d.ts +17 -0
- package/dist/core/mcp.d.ts.map +1 -1
- package/dist/core/mcp.js +122 -71
- package/dist/core/mcp.js.map +1 -1
- package/dist/core/runner/prepare-task.d.ts.map +1 -1
- package/dist/core/runner/prepare-task.js +88 -16
- package/dist/core/runner/prepare-task.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -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 { Type } from "typebox";
|
|
12
13
|
import { brainToRuntime } from "../runtime.js";
|
|
13
14
|
import { MemoryEngine } from "../memory-engine/engine.js";
|
|
14
15
|
import { deriveControlPlaneDir, deriveProjectControlDir, deriveProjectMemoryDir, deriveRepoMemoryDir, drainMemoryAnnouncements, enqueueMemoryAnnouncement, lookupProjectIdHint, recordProjectIdHint, resolveMemoryEngineRoot } from "../memory-engine/layout.js";
|
|
@@ -933,7 +934,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
933
934
|
}
|
|
934
935
|
mcp = spec.mcp?.length
|
|
935
936
|
? await materializeMcpTools(spec.mcp, spec.principal, deps.onElicit, deps.mcpImageResizer)
|
|
936
|
-
: { tools: [], toolAxes: [], warnings: [], serverInstructions: [], instructionsDelta: { pendingAdds: [], pendingRemovals: [] }, droppedTools: [], statuses: [], dispose: async () => { } };
|
|
937
|
+
: { tools: [], toolAxes: [], warnings: [], serverInstructions: [], instructionsDelta: { pendingAdds: [], pendingRemovals: [] }, droppedTools: [], statuses: [], refresh: async () => [], dispose: async () => { } };
|
|
937
938
|
for (const w of mcp.warnings)
|
|
938
939
|
deps.onError?.(w, { phase: "mcp", sessionId });
|
|
939
940
|
for (const d of mcp.droppedTools) {
|
|
@@ -950,22 +951,83 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
950
951
|
}
|
|
951
952
|
}
|
|
952
953
|
tools.push(...mcp.tools.map((t) => mcpOffload(t)));
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
954
|
+
const rebuildHarnessToolsRef = {};
|
|
955
|
+
if (spec.mcp?.length) {
|
|
956
|
+
tools.push({
|
|
957
|
+
name: "RefreshMcpTools",
|
|
958
|
+
label: "RefreshMcpTools",
|
|
959
|
+
description: "Refresh the tool list of connected MCP servers. Never dials or re-dials connections — it only re-reads the tool list over the existing connection. The refreshed tools are available immediately; you can call them on your next step. Use when a server's expected tool is missing, or the tool list looks stale after a connection recovered. Omit `server` to refresh every connected server.",
|
|
960
|
+
parameters: Type.Object({
|
|
961
|
+
server: Type.Optional(Type.String({ description: "Name of a single MCP server to refresh; omit to refresh all connected servers." })),
|
|
962
|
+
}),
|
|
963
|
+
execute: async (_toolCallId, params) => {
|
|
964
|
+
const serverArg = params?.server;
|
|
965
|
+
const results = await mcp.refresh(typeof serverArg === "string" && serverArg.length > 0 ? serverArg : undefined);
|
|
966
|
+
const lines = [];
|
|
967
|
+
let changed = false;
|
|
968
|
+
for (const r of results) {
|
|
969
|
+
if (r.status !== "refreshed" || r.tools === undefined) {
|
|
970
|
+
lines.push(`${r.server}: ${r.status}${r.error !== undefined ? ` (${r.error})` : ""}`);
|
|
971
|
+
continue;
|
|
972
|
+
}
|
|
973
|
+
const excludedSet = new Set(toolFaceSnapshot.exclude ?? []);
|
|
974
|
+
const pushable = r.tools.filter((t) => !excludedSet.has(t.name));
|
|
975
|
+
const excludedNow = r.tools.filter((t) => excludedSet.has(t.name)).map((t) => t.name);
|
|
976
|
+
try {
|
|
977
|
+
foldMcpAxes((r.axes ?? []).filter((a) => !excludedSet.has(a.name)));
|
|
978
|
+
}
|
|
979
|
+
catch (foldErr) {
|
|
980
|
+
lines.push(`${r.server}: failed (${foldErr instanceof Error ? foldErr.message : String(foldErr)})`);
|
|
981
|
+
continue;
|
|
982
|
+
}
|
|
983
|
+
for (let i = tools.length - 1; i >= 0; i--) {
|
|
984
|
+
const t = tools[i];
|
|
985
|
+
if (t.name.startsWith(r.prefix)) {
|
|
986
|
+
toolEffects.delete(t.name);
|
|
987
|
+
tools.splice(i, 1);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
tools.push(...pushable.map((t) => mcpOffload(t)));
|
|
991
|
+
changed = true;
|
|
992
|
+
const detail = [];
|
|
993
|
+
const shownAdded = r.added.filter((n) => !excludedSet.has(n));
|
|
994
|
+
if (shownAdded.length > 0)
|
|
995
|
+
detail.push(`added: ${shownAdded.join(", ")}`);
|
|
996
|
+
if (r.removed.length > 0)
|
|
997
|
+
detail.push(`removed: ${r.removed.join(", ")}`);
|
|
998
|
+
if (excludedNow.length > 0)
|
|
999
|
+
detail.push(`excluded by deployment config (not mounted): ${excludedNow.join(", ")}`);
|
|
1000
|
+
if ((r.dropped?.length ?? 0) > 0)
|
|
1001
|
+
detail.push(`dropped (invalid schema): ${r.dropped.map((d) => d.tool).join(", ")}`);
|
|
1002
|
+
lines.push(`${r.server}: refreshed — ${pushable.length} tool${pushable.length === 1 ? "" : "s"}${detail.length > 0 ? ` (${detail.join("; ")})` : ""}`);
|
|
1003
|
+
}
|
|
1004
|
+
if (changed)
|
|
1005
|
+
await rebuildHarnessToolsRef.current?.();
|
|
1006
|
+
const text = lines.length === 0 ? "No connected MCP servers to refresh." : lines.join("\n");
|
|
1007
|
+
return { content: [{ type: "text", text }], details: { results }, terminate: false };
|
|
1008
|
+
},
|
|
1009
|
+
});
|
|
1010
|
+
toolEffects.set("RefreshMcpTools", "read");
|
|
1011
|
+
}
|
|
1012
|
+
const foldMcpAxes = (axes) => {
|
|
1013
|
+
for (const axis of axes) {
|
|
1014
|
+
if (axis.irreversibility === "always") {
|
|
1015
|
+
irreversibilityTier.set(axis.name, "always");
|
|
1016
|
+
irreversibleTools.add(axis.name);
|
|
1017
|
+
}
|
|
1018
|
+
if (axis.egress) {
|
|
1019
|
+
if (axis.effect !== undefined && axis.effect !== "write") {
|
|
1020
|
+
const e = new Error(`MCP 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".`);
|
|
1021
|
+
e.code = "config.egress_requires_write_effect";
|
|
1022
|
+
throw e;
|
|
1023
|
+
}
|
|
1024
|
+
egressTools.add(axis.name);
|
|
963
1025
|
}
|
|
964
|
-
|
|
1026
|
+
if (!toolEffects.has(axis.name))
|
|
1027
|
+
toolEffects.set(axis.name, axis.effect ?? "write");
|
|
965
1028
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
}
|
|
1029
|
+
};
|
|
1030
|
+
foldMcpAxes(mcp.toolAxes);
|
|
969
1031
|
const callCapOn = spec.limits?.callCapByDeadline !== false;
|
|
970
1032
|
const callCapRef = spec.limits?.timeoutSec &&
|
|
971
1033
|
spec.limits.timeoutSec > 0 &&
|
|
@@ -1814,6 +1876,15 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1814
1876
|
}
|
|
1815
1877
|
const activeTools = new Set();
|
|
1816
1878
|
const fpRef = {};
|
|
1879
|
+
if (rebuildHarnessToolsRef.current === undefined) {
|
|
1880
|
+
rebuildHarnessToolsRef.current = async () => {
|
|
1881
|
+
const list = [...tools];
|
|
1882
|
+
await harnessRef.current.setTools(list, list.map((t) => t.name));
|
|
1883
|
+
if (fpRef.current)
|
|
1884
|
+
fpRef.current.tools = toolsToFingerprintInputs(list);
|
|
1885
|
+
turnSnapshotRef.current?.refreshTools(toolsToFingerprintInputs(list));
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1817
1888
|
const turnSnapshotRef = {};
|
|
1818
1889
|
let harnessTools = tools;
|
|
1819
1890
|
let toolsDeltaRef;
|
|
@@ -1847,7 +1918,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1847
1918
|
const deltaRef = toolsDeltaRef;
|
|
1848
1919
|
const rematerialize = async (active) => {
|
|
1849
1920
|
const list = buildToolList(active);
|
|
1850
|
-
await harnessRef.current.setTools(list);
|
|
1921
|
+
await harnessRef.current.setTools(list, list.map((t) => t.name));
|
|
1851
1922
|
if (fpRef.current)
|
|
1852
1923
|
fpRef.current.tools = toolsToFingerprintInputs(list);
|
|
1853
1924
|
turnSnapshotRef.current?.refreshTools(toolsToFingerprintInputs(list));
|
|
@@ -1858,6 +1929,7 @@ export async function prepareTask(spec, deps, sessions, resume, _memorySelector,
|
|
|
1858
1929
|
}
|
|
1859
1930
|
}
|
|
1860
1931
|
};
|
|
1932
|
+
rebuildHarnessToolsRef.current = () => rematerialize(activeTools);
|
|
1861
1933
|
toolSearch = makeToolSearchTool({
|
|
1862
1934
|
registry,
|
|
1863
1935
|
active: activeTools,
|