zidane 4.1.8 → 5.0.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/README.md +11 -2
- package/dist/{index-bgh-k8Mv.d.ts → agent-JhicgLOV.d.ts} +2082 -1969
- package/dist/agent-JhicgLOV.d.ts.map +1 -0
- package/dist/chat.d.ts +340 -9
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/contexts.d.ts +1 -1
- package/dist/{index-DRoG_udt.d.ts → index-2yLUyTbc.d.ts} +34 -4
- package/dist/{index-DRoG_udt.d.ts.map → index-2yLUyTbc.d.ts.map} +1 -1
- package/dist/{index-BB4kuRh3.d.ts → index-CXVvqTQj.d.ts} +1 -1
- package/dist/{index-BB4kuRh3.d.ts.map → index-CXVvqTQj.d.ts.map} +1 -1
- package/dist/{index-Ds5YpvfZ.d.ts → index-t_W9i7Ql.d.ts} +9 -4
- package/dist/index-t_W9i7Ql.d.ts.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -6
- package/dist/{interpolate-CukJwP2G.js → interpolate-Ck970-61.js} +11 -2
- package/dist/interpolate-Ck970-61.js.map +1 -0
- package/dist/{mcp-8wClKY-3.js → mcp-Dw-fRPVk.js} +61 -65
- package/dist/mcp-Dw-fRPVk.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/presets-BRFH2qsQ.js +90 -0
- package/dist/presets-BRFH2qsQ.js.map +1 -0
- package/dist/presets.d.ts +3 -2
- package/dist/presets.js +2 -2
- package/dist/providers.d.ts +1 -1
- package/dist/session/sqlite.d.ts +13 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +96 -38
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-Cn68UASv.js → session-791hhrFa.js} +65 -30
- package/dist/session-791hhrFa.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -1
- package/dist/{stats-BT9l57RS.js → stats-DZIsGqzu.js} +15 -5
- package/dist/stats-DZIsGqzu.js.map +1 -0
- package/dist/theme-pJv47erq.d.ts +1202 -0
- package/dist/theme-pJv47erq.d.ts.map +1 -0
- package/dist/{tools-C8kDot0H.js → tools-CLazLRb4.js} +475 -318
- package/dist/tools-CLazLRb4.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/tui.d.ts +303 -18
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +3305 -509
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-5aQu4dJg.js +3587 -0
- package/dist/turn-operations-5aQu4dJg.js.map +1 -0
- package/dist/types.d.ts +3 -3
- package/dist/types.js +1 -1
- package/package.json +6 -1
- package/dist/index-Ds5YpvfZ.d.ts.map +0 -1
- package/dist/index-bgh-k8Mv.d.ts.map +0 -1
- package/dist/interpolate-CukJwP2G.js.map +0 -1
- package/dist/mcp-8wClKY-3.js.map +0 -1
- package/dist/presets-BzkJDW1K.js +0 -39
- package/dist/presets-BzkJDW1K.js.map +0 -1
- package/dist/session-Cn68UASv.js.map +0 -1
- package/dist/stats-BT9l57RS.js.map +0 -1
- package/dist/theme-BlXO6yHe.d.ts +0 -503
- package/dist/theme-BlXO6yHe.d.ts.map +0 -1
- package/dist/theme-context-MungM3SY.js +0 -1713
- package/dist/theme-context-MungM3SY.js.map +0 -1
- package/dist/tools-C8kDot0H.js.map +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as createProcessContext } from "./contexts-3Arvn7yR.js";
|
|
2
2
|
import { r as AgentProviderError, s as toTypedError, t as AgentAbortedError } from "./errors-D1lhd6mX.js";
|
|
3
3
|
import { t as toolOutputByteLength } from "./types-Bx_F8jet.js";
|
|
4
|
-
import { t as connectMcpServers } from "./mcp-
|
|
5
|
-
import { _ as validateResourcePath, b as createSkillActivationState, d as escapeXml, n as resolveSkills, p as installAllowedToolsGate, t as interpolateShellCommands, u as buildCatalog } from "./interpolate-
|
|
6
|
-
import { n as formatTokenUsage, t as flattenTurns } from "./stats-
|
|
4
|
+
import { t as connectMcpServers } from "./mcp-Dw-fRPVk.js";
|
|
5
|
+
import { _ as validateResourcePath, b as createSkillActivationState, d as escapeXml, n as resolveSkills, p as installAllowedToolsGate, t as interpolateShellCommands, u as buildCatalog } from "./interpolate-Ck970-61.js";
|
|
6
|
+
import { n as formatTokenUsage, t as flattenTurns } from "./stats-DZIsGqzu.js";
|
|
7
7
|
import { createHooks } from "hookable";
|
|
8
8
|
import { stat } from "node:fs/promises";
|
|
9
9
|
import { resolve } from "node:path";
|
|
@@ -892,12 +892,19 @@ async function executeTurn(ctx, turn) {
|
|
|
892
892
|
}
|
|
893
893
|
const toolResults = ctx.toolExecution === "parallel" ? await executeToolsParallel(ctx, canonicalToolCalls, turnId) : await executeToolsSequential(ctx, canonicalToolCalls, turnId);
|
|
894
894
|
const toolResultMsg = ctx.provider.toolResultsMessage(toolResults);
|
|
895
|
-
|
|
895
|
+
const toolResultsTurn = {
|
|
896
896
|
id: await ctx.generateTurnId(),
|
|
897
897
|
runId: ctx.runId,
|
|
898
898
|
role: toolResultMsg.role,
|
|
899
899
|
content: toolResultMsg.content,
|
|
900
900
|
createdAt: Date.now()
|
|
901
|
+
};
|
|
902
|
+
ctx.turns.push(toolResultsTurn);
|
|
903
|
+
await ctx.hooks.callHook("tool-results:after", {
|
|
904
|
+
turn,
|
|
905
|
+
turnId,
|
|
906
|
+
message: toolResultsTurn,
|
|
907
|
+
results: toolResults
|
|
901
908
|
});
|
|
902
909
|
if (typeof ctx.toolOutputBudget === "number" && ctx.toolOutputBudget > 0) {
|
|
903
910
|
const totalBytes = toolResults.reduce((sum, r) => sum + toolOutputByteLength(r.content), 0);
|
|
@@ -1151,8 +1158,21 @@ async function executeToolsSequential(ctx, toolCalls, turnId) {
|
|
|
1151
1158
|
});
|
|
1152
1159
|
return results;
|
|
1153
1160
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1161
|
+
try {
|
|
1162
|
+
const { result } = await executeSingleTool(ctx, call, turnId);
|
|
1163
|
+
results.push(result);
|
|
1164
|
+
} catch (err) {
|
|
1165
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1166
|
+
results.push({
|
|
1167
|
+
id: call.id,
|
|
1168
|
+
content: `Error: ${message}`
|
|
1169
|
+
});
|
|
1170
|
+
for (let j = i + 1; j < toolCalls.length; j++) results.push({
|
|
1171
|
+
id: toolCalls[j].id,
|
|
1172
|
+
content: "Skipped: previous tool call threw"
|
|
1173
|
+
});
|
|
1174
|
+
return results;
|
|
1175
|
+
}
|
|
1156
1176
|
}
|
|
1157
1177
|
return results;
|
|
1158
1178
|
}
|
|
@@ -1737,6 +1757,7 @@ const HOOK_EVENT_SET = new Set([
|
|
|
1737
1757
|
"system:before",
|
|
1738
1758
|
"turn:before",
|
|
1739
1759
|
"turn:after",
|
|
1760
|
+
"tool-results:after",
|
|
1740
1761
|
"stream:text",
|
|
1741
1762
|
"stream:end",
|
|
1742
1763
|
"stream:thinking",
|
|
@@ -1794,6 +1815,45 @@ const HOOK_EVENT_SET = new Set([
|
|
|
1794
1815
|
function isKnownHookEvent(event) {
|
|
1795
1816
|
return HOOK_EVENT_SET.has(event);
|
|
1796
1817
|
}
|
|
1818
|
+
/**
|
|
1819
|
+
* If the trailing assistant turn in `turns` carries `tool_call` blocks with
|
|
1820
|
+
* no matching `tool_result` in a following user turn, mutate `turns` in
|
|
1821
|
+
* place to append a synthetic tool-results turn that closes every dangling
|
|
1822
|
+
* tool_use id. Used by the error path of `agent.run` to prevent a thrown
|
|
1823
|
+
* loop from leaving the persisted session with an orphan tool_use — which
|
|
1824
|
+
* Anthropic rejects on resume.
|
|
1825
|
+
*
|
|
1826
|
+
* No-op when:
|
|
1827
|
+
* - The trailing turn isn't an assistant turn (already closed, or session
|
|
1828
|
+
* ends with the seeded user prompt).
|
|
1829
|
+
* - The assistant turn has no `tool_call` blocks.
|
|
1830
|
+
* - All tool_use ids are already answered by a tool_result somewhere later
|
|
1831
|
+
* in the conversation (defensive — shouldn't happen but cheap to check).
|
|
1832
|
+
*/
|
|
1833
|
+
function synthesizeMissingToolResults(turns, syntheticTurnId, runId, provider) {
|
|
1834
|
+
if (turns.length === 0) return;
|
|
1835
|
+
const last = turns[turns.length - 1];
|
|
1836
|
+
if (last.role !== "assistant") return;
|
|
1837
|
+
const pendingIds = [];
|
|
1838
|
+
for (const block of last.content) if (block.type === "tool_call") pendingIds.push(block.id);
|
|
1839
|
+
if (pendingIds.length === 0) return;
|
|
1840
|
+
const answered = /* @__PURE__ */ new Set();
|
|
1841
|
+
for (const turn of turns.slice(0, -1)) for (const block of turn.content) if (block.type === "tool_result") answered.add(block.callId);
|
|
1842
|
+
const dangling = pendingIds.filter((id) => !answered.has(id));
|
|
1843
|
+
if (dangling.length === 0) return;
|
|
1844
|
+
const results = dangling.map((id) => ({
|
|
1845
|
+
id,
|
|
1846
|
+
content: "Aborted: run failed before tool execution completed"
|
|
1847
|
+
}));
|
|
1848
|
+
const msg = provider.toolResultsMessage(results);
|
|
1849
|
+
turns.push({
|
|
1850
|
+
id: syntheticTurnId,
|
|
1851
|
+
runId,
|
|
1852
|
+
role: msg.role,
|
|
1853
|
+
content: msg.content,
|
|
1854
|
+
createdAt: Date.now()
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1797
1857
|
function resolveBehavior(agentBehavior, runBehavior) {
|
|
1798
1858
|
return {
|
|
1799
1859
|
toolExecution: runBehavior?.toolExecution ?? agentBehavior?.toolExecution ?? "parallel",
|
|
@@ -1936,10 +1996,43 @@ function installLazyDisclosureGate(hooks, lazyCanonicalNames, unlocked, discover
|
|
|
1936
1996
|
ctx.reason = discoveryToolName ? `Tool "${ctx.name}" is listed in <searchable_tools> but its schema has not been loaded. Call the \`${discoveryToolName}\` tool with names: ["${ctx.name}"] first, then re-issue the call.` : `Tool "${ctx.name}" is listed in <searchable_tools> but its schema has not been loaded.`;
|
|
1937
1997
|
});
|
|
1938
1998
|
}
|
|
1939
|
-
|
|
1999
|
+
/**
|
|
2000
|
+
* Pick the next safe value for `runCounter` so `run_${++counter}` mints
|
|
2001
|
+
* an id that doesn't collide with any runId already referenced by the
|
|
2002
|
+
* session — whether the runId lives in `session.runs` or only in
|
|
2003
|
+
* `session.turns[].runId`. The regex matches the canonical `run_<int>`
|
|
2004
|
+
* shape minted by this module; any caller-supplied custom id schemes
|
|
2005
|
+
* are ignored (they don't conflict with `run_N`).
|
|
2006
|
+
*
|
|
2007
|
+
* Returning 0 for a sessionless / clean session preserves the original
|
|
2008
|
+
* "first run is run_1" semantics.
|
|
2009
|
+
*/
|
|
2010
|
+
function initialRunCounter(session) {
|
|
2011
|
+
if (!session) return 0;
|
|
2012
|
+
let max = 0;
|
|
2013
|
+
const consider = (id) => {
|
|
2014
|
+
if (!id) return;
|
|
2015
|
+
const m = /^run_(\d+)$/.exec(id);
|
|
2016
|
+
if (!m) return;
|
|
2017
|
+
const n = Number.parseInt(m[1], 10);
|
|
2018
|
+
if (Number.isFinite(n) && n > max) max = n;
|
|
2019
|
+
};
|
|
2020
|
+
for (const r of session.runs) consider(r.id);
|
|
2021
|
+
for (const t of session.turns) consider(t.runId);
|
|
2022
|
+
return max;
|
|
2023
|
+
}
|
|
2024
|
+
function createAgent({ provider, name: agentName, system: agentSystem, tools: agentTools, toolAliases, behavior: agentBehavior, execution, mcpServers, session, skills: agentSkills, mcpConnector, eager, hooks: initialHooks }) {
|
|
1940
2025
|
const hooks = createHooks();
|
|
1941
2026
|
const executionContext = execution ?? createProcessContext();
|
|
1942
2027
|
const sourceTools = agentTools ?? {};
|
|
2028
|
+
if (initialHooks) for (const [event, handler] of Object.entries(initialHooks)) {
|
|
2029
|
+
if (!isKnownHookEvent(event)) throw new Error(`Unknown hook event "${event}" passed to createAgent(). See AgentHooks for valid events.`);
|
|
2030
|
+
const handlerList = Array.isArray(handler) ? handler : [handler];
|
|
2031
|
+
for (const fn of handlerList) {
|
|
2032
|
+
if (typeof fn !== "function") continue;
|
|
2033
|
+
hooks.hook(event, fn);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
1943
2036
|
let abortController;
|
|
1944
2037
|
let running = false;
|
|
1945
2038
|
let idleResolve;
|
|
@@ -1951,354 +2044,397 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
1951
2044
|
const steeringQueue = [];
|
|
1952
2045
|
const followUpQueue = [];
|
|
1953
2046
|
let conversationTurns = session?.turns.slice() ?? [];
|
|
1954
|
-
let runCounter = session
|
|
2047
|
+
let runCounter = initialRunCounter(session);
|
|
1955
2048
|
const skillsConfig = agentSkills;
|
|
1956
2049
|
const skillsEnabledValue = skillsConfig?.enabled;
|
|
1957
2050
|
const skillsDisabled = skillsEnabledValue === false || Array.isArray(skillsEnabledValue) && skillsEnabledValue.length === 0;
|
|
1958
2051
|
let resolvedSkills = null;
|
|
1959
2052
|
let skillsCatalog = null;
|
|
2053
|
+
let skillsResolvePromise = null;
|
|
1960
2054
|
let skillsCleanup = () => {};
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
...options.parentRunId ? { parentRunId: options.parentRunId } : {},
|
|
1976
|
-
depth: typeof options.depth === "number" ? options.depth : 0
|
|
1977
|
-
});
|
|
1978
|
-
if (session) {
|
|
1979
|
-
await session.updateStatus("running");
|
|
1980
|
-
await hooks.callHook("session:start", {
|
|
1981
|
-
sessionId: session.id,
|
|
1982
|
-
runId,
|
|
1983
|
-
prompt: promptLabel
|
|
1984
|
-
});
|
|
1985
|
-
}
|
|
1986
|
-
if (options.signal) if (options.signal.aborted) abortController.abort();
|
|
1987
|
-
else {
|
|
1988
|
-
const onExternalAbort = () => abortController?.abort();
|
|
1989
|
-
options.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
1990
|
-
}
|
|
1991
|
-
idlePromise = new Promise((resolve) => {
|
|
1992
|
-
idleResolve = resolve;
|
|
1993
|
-
});
|
|
1994
|
-
const childrenStats = [];
|
|
1995
|
-
const unregisterSpawnHook = hooks.hook("spawn:complete", (ctx) => {
|
|
1996
|
-
childrenStats.push(ctx);
|
|
1997
|
-
});
|
|
1998
|
-
const perRunUnregisters = [];
|
|
1999
|
-
if (options.hooks) for (const [event, handler] of Object.entries(options.hooks)) {
|
|
2000
|
-
if (!isKnownHookEvent(event)) throw new Error(`Unknown hook event "${event}" passed to run(). See AgentHooks for valid events.`);
|
|
2001
|
-
const handlerList = Array.isArray(handler) ? handler : [handler];
|
|
2002
|
-
for (const fn of handlerList) {
|
|
2003
|
-
if (typeof fn !== "function") continue;
|
|
2004
|
-
perRunUnregisters.push(hooks.hook(event, fn));
|
|
2005
|
-
}
|
|
2006
|
-
}
|
|
2007
|
-
if (!executionHandle) executionHandle = await executionContext.spawn();
|
|
2008
|
-
if (allMcpServers.length > 0 && !mcpConnection) await warmup();
|
|
2009
|
-
if (!skillsDisabled && skillsConfig && !resolvedSkills) {
|
|
2055
|
+
/**
|
|
2056
|
+
* Resolve skills once for the lifetime of the agent. Idempotent and
|
|
2057
|
+
* concurrency-safe; no-op when `skills` is disabled or omitted.
|
|
2058
|
+
*
|
|
2059
|
+
* Used by `run()` (lazy bootstrap), `warmup()` (eager bootstrap), and
|
|
2060
|
+
* `activateSkill()` (so the public API doesn't leak the timing of `run()`).
|
|
2061
|
+
* Fires `skills:resolve` (mutable `skills` array) and `skills:catalog`
|
|
2062
|
+
* (mutable `catalog`) in that order — exactly once per agent.
|
|
2063
|
+
*/
|
|
2064
|
+
async function ensureSkillsResolved() {
|
|
2065
|
+
if (skillsDisabled || !skillsConfig) return;
|
|
2066
|
+
if (resolvedSkills) return;
|
|
2067
|
+
if (skillsResolvePromise) return skillsResolvePromise;
|
|
2068
|
+
skillsResolvePromise = (async () => {
|
|
2010
2069
|
const bundle = await resolveSkills(skillsConfig);
|
|
2011
2070
|
resolvedSkills = bundle.skills;
|
|
2012
2071
|
skillsCleanup = bundle.cleanup;
|
|
2013
2072
|
await hooks.callHook("skills:resolve", { skills: resolvedSkills });
|
|
2014
|
-
const skillsToolRegistered = skillsConfig
|
|
2073
|
+
const skillsToolRegistered = skillsConfig.tool !== false && resolvedSkills.length > 0;
|
|
2015
2074
|
const catalogCtx = {
|
|
2016
2075
|
catalog: buildCatalog(resolvedSkills, { skillsToolRegistered }),
|
|
2017
2076
|
skills: resolvedSkills
|
|
2018
2077
|
};
|
|
2019
2078
|
await hooks.callHook("skills:catalog", catalogCtx);
|
|
2020
2079
|
skillsCatalog = catalogCtx.catalog;
|
|
2080
|
+
})();
|
|
2081
|
+
try {
|
|
2082
|
+
await skillsResolvePromise;
|
|
2083
|
+
} catch (err) {
|
|
2084
|
+
skillsResolvePromise = null;
|
|
2085
|
+
throw err;
|
|
2021
2086
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
if (!skill) continue;
|
|
2032
|
-
if (skillActivationState.activate(skill, "resume") === "ok") await hooks.callHook("skills:activate", {
|
|
2033
|
-
skill,
|
|
2034
|
-
via: "resume"
|
|
2035
|
-
});
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2087
|
+
}
|
|
2088
|
+
const skillActivationState = createSkillActivationState({ maxActive: skillsConfig?.maxActive });
|
|
2089
|
+
async function run(options) {
|
|
2090
|
+
if (running) throw new Error("Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().");
|
|
2091
|
+
const hasSessionTurns = session && session.turns.length > 0;
|
|
2092
|
+
if (!options.prompt && !hasSessionTurns) throw new Error("prompt is required when no session with existing turns is provided");
|
|
2093
|
+
if (!options.prompt && hasSessionTurns) {
|
|
2094
|
+
const lastTurn = session.turns.at(-1);
|
|
2095
|
+
if (lastTurn && lastTurn.role !== "user") throw new Error("cannot resume without prompt: last session turn must be a user message");
|
|
2038
2096
|
}
|
|
2039
|
-
|
|
2040
|
-
const
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
const mcpToolNames = options.tools === void 0 && mcpConnection ? new Set(Object.keys(mcpConnection.tools)) : /* @__PURE__ */ new Set();
|
|
2050
|
-
const mergedWithSkills = options.tools === void 0 && !!resolvedSkills && resolvedSkills.length > 0 && skillsConfig?.tool !== false ? {
|
|
2051
|
-
skills_use: createSkillsUseTool({
|
|
2052
|
-
catalog: resolvedSkills,
|
|
2053
|
-
state: skillActivationState,
|
|
2054
|
-
hooks
|
|
2055
|
-
}),
|
|
2056
|
-
skills_read: createSkillsReadTool({
|
|
2057
|
-
catalog: resolvedSkills,
|
|
2058
|
-
state: skillActivationState
|
|
2059
|
-
}),
|
|
2060
|
-
skills_run_script: createSkillsRunScriptTool({
|
|
2061
|
-
catalog: resolvedSkills,
|
|
2062
|
-
state: skillActivationState,
|
|
2063
|
-
scriptTimeoutMs: skillsConfig?.scriptTimeoutMs
|
|
2064
|
-
}),
|
|
2065
|
-
...runBaseTools
|
|
2066
|
-
} : runBaseTools;
|
|
2067
|
-
const toolsPreSearch = {};
|
|
2068
|
-
for (const tool of Object.values(mergedWithSkills)) toolsPreSearch[tool.spec.name] = tool;
|
|
2069
|
-
const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, toolAliases);
|
|
2070
|
-
const unlocked = new Set(disclosure.eagerCanonicalNames);
|
|
2071
|
-
const hostDefinedToolSearch = !!toolsPreSearch.tool_search;
|
|
2072
|
-
const shouldInjectToolSearch = disclosure.lazyEntries.length > 0 && toolSearch?.tool !== false && !hostDefinedToolSearch;
|
|
2073
|
-
let tools = toolsPreSearch;
|
|
2074
|
-
if (shouldInjectToolSearch) {
|
|
2075
|
-
const toolSearchTool = createToolSearchTool({
|
|
2076
|
-
catalog: disclosure.lazyEntries,
|
|
2077
|
-
unlocked,
|
|
2078
|
-
...toolSearch?.limit !== void 0 ? { defaultLimit: toolSearch.limit } : {}
|
|
2097
|
+
let externalAbortListener;
|
|
2098
|
+
const externalSignal = options.signal;
|
|
2099
|
+
running = true;
|
|
2100
|
+
try {
|
|
2101
|
+
abortController = new AbortController();
|
|
2102
|
+
const runId = `run_${++runCounter}`;
|
|
2103
|
+
const promptLabel = typeof options.prompt === "string" ? options.prompt : Array.isArray(options.prompt) ? options.prompt.filter((p) => p.type === "text").map((p) => p.text).join("\n") : "";
|
|
2104
|
+
session?.startRun(runId, promptLabel, {
|
|
2105
|
+
...options.parentRunId ? { parentRunId: options.parentRunId } : {},
|
|
2106
|
+
depth: typeof options.depth === "number" ? options.depth : 0
|
|
2079
2107
|
});
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
const discoveryToolName = shouldInjectToolSearch ? "tool_search" : hostDefinedToolSearch ? toolAliases?.tool_search ?? "tool_search" : null;
|
|
2087
|
-
if (disclosure.lazyEntries.length > 0) system = `${system}\n\n${buildSearchableCatalog(disclosure.lazyEntries, { discoveryToolName })}`;
|
|
2088
|
-
const aliasMaps = buildAliasMaps(toolAliases, Object.keys(tools));
|
|
2089
|
-
const uninstallLazyDisclosureGate = installLazyDisclosureGate(hooks, disclosure.lazyCanonicalNames, unlocked, discoveryToolName);
|
|
2090
|
-
function buildFormattedTools() {
|
|
2091
|
-
const specs = [];
|
|
2092
|
-
for (const t of Object.values(tools)) {
|
|
2093
|
-
if (!unlocked.has(t.spec.name)) continue;
|
|
2094
|
-
specs.push({
|
|
2095
|
-
name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,
|
|
2096
|
-
description: t.spec.description || "",
|
|
2097
|
-
inputSchema: t.spec.inputSchema
|
|
2108
|
+
if (session) {
|
|
2109
|
+
await session.updateStatus("running");
|
|
2110
|
+
await hooks.callHook("session:start", {
|
|
2111
|
+
sessionId: session.id,
|
|
2112
|
+
runId,
|
|
2113
|
+
prompt: promptLabel
|
|
2098
2114
|
});
|
|
2099
2115
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
const resumed = childRunIds.size === 0 ? session.turns : session.turns.filter((t) => !t.runId || !childRunIds.has(t.runId));
|
|
2108
|
-
turns.push(...resumed);
|
|
2109
|
-
}
|
|
2110
|
-
const runTurnStart = turns.length;
|
|
2111
|
-
if (options.system) await hooks.callHook("system:before", { system: options.system });
|
|
2112
|
-
const promptParts = canonicalizePrompt(options.prompt);
|
|
2113
|
-
if (promptParts) {
|
|
2114
|
-
const promptMsg = buildPromptMessage(provider, promptParts);
|
|
2115
|
-
turns.push({
|
|
2116
|
-
id: crypto.randomUUID(),
|
|
2117
|
-
runId,
|
|
2118
|
-
role: promptMsg.role,
|
|
2119
|
-
content: promptMsg.content,
|
|
2120
|
-
createdAt: Date.now()
|
|
2116
|
+
if (externalSignal) if (externalSignal.aborted) abortController.abort();
|
|
2117
|
+
else {
|
|
2118
|
+
externalAbortListener = () => abortController?.abort();
|
|
2119
|
+
externalSignal.addEventListener("abort", externalAbortListener, { once: true });
|
|
2120
|
+
}
|
|
2121
|
+
idlePromise = new Promise((resolve) => {
|
|
2122
|
+
idleResolve = resolve;
|
|
2121
2123
|
});
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
if (session && turns.length > lastPersistedTurnCount) {
|
|
2126
|
-
const seededTurns = turns.slice(lastPersistedTurnCount);
|
|
2127
|
-
await session.appendTurns(seededTurns);
|
|
2128
|
-
lastPersistedTurnCount = turns.length;
|
|
2129
|
-
await hooks.callHook("session:turns", {
|
|
2130
|
-
sessionId: session.id,
|
|
2131
|
-
turns: seededTurns,
|
|
2132
|
-
count: turns.length
|
|
2124
|
+
const childrenStats = [];
|
|
2125
|
+
const unregisterSpawnHook = hooks.hook("spawn:complete", (ctx) => {
|
|
2126
|
+
childrenStats.push(ctx);
|
|
2133
2127
|
});
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2128
|
+
const perRunUnregisters = [];
|
|
2129
|
+
if (options.hooks) for (const [event, handler] of Object.entries(options.hooks)) {
|
|
2130
|
+
if (!isKnownHookEvent(event)) throw new Error(`Unknown hook event "${event}" passed to run(). See AgentHooks for valid events.`);
|
|
2131
|
+
const handlerList = Array.isArray(handler) ? handler : [handler];
|
|
2132
|
+
for (const fn of handlerList) {
|
|
2133
|
+
if (typeof fn !== "function") continue;
|
|
2134
|
+
perRunUnregisters.push(hooks.hook(event, fn));
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
if (!executionHandle) executionHandle = await executionContext.spawn();
|
|
2138
|
+
if (allMcpServers.length > 0 && !mcpConnection) await warmup();
|
|
2139
|
+
await ensureSkillsResolved();
|
|
2140
|
+
if (resolvedSkills && session && session.turns.length > 0 && skillActivationState.active().length === 0) {
|
|
2141
|
+
const skillsByName = new Map(resolvedSkills.map((s) => [s.name, s]));
|
|
2142
|
+
for (const turn of session.turns) {
|
|
2143
|
+
if (turn.role !== "assistant") continue;
|
|
2144
|
+
for (const block of turn.content) {
|
|
2145
|
+
if (block.type !== "tool_call" || block.name !== "skills_use") continue;
|
|
2146
|
+
const skillName = block.input?.name;
|
|
2147
|
+
if (!skillName) continue;
|
|
2148
|
+
const skill = skillsByName.get(skillName);
|
|
2149
|
+
if (!skill) continue;
|
|
2150
|
+
if (skillActivationState.activate(skill, "resume") === "ok") await hooks.callHook("skills:activate", {
|
|
2151
|
+
skill,
|
|
2152
|
+
via: "resume"
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
const thinking = options.thinking ?? "off";
|
|
2158
|
+
const model = options.model ?? provider.meta.defaultModel;
|
|
2159
|
+
const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior);
|
|
2160
|
+
const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch } = resolvedBehavior;
|
|
2161
|
+
let system = options.system || agentSystem || "You are a helpful assistant.";
|
|
2162
|
+
if (skillsCatalog) system = `${system}\n\n${skillsCatalog}`;
|
|
2163
|
+
const runBaseTools = options.tools !== void 0 ? options.tools : mcpConnection ? {
|
|
2164
|
+
...sourceTools,
|
|
2165
|
+
...mcpConnection.tools
|
|
2166
|
+
} : sourceTools;
|
|
2167
|
+
const mcpToolNames = options.tools === void 0 && mcpConnection ? new Set(Object.keys(mcpConnection.tools)) : /* @__PURE__ */ new Set();
|
|
2168
|
+
const mergedWithSkills = options.tools === void 0 && !!resolvedSkills && resolvedSkills.length > 0 && skillsConfig?.tool !== false ? {
|
|
2169
|
+
skills_use: createSkillsUseTool({
|
|
2170
|
+
catalog: resolvedSkills,
|
|
2171
|
+
state: skillActivationState,
|
|
2172
|
+
hooks
|
|
2173
|
+
}),
|
|
2174
|
+
skills_read: createSkillsReadTool({
|
|
2175
|
+
catalog: resolvedSkills,
|
|
2176
|
+
state: skillActivationState
|
|
2177
|
+
}),
|
|
2178
|
+
skills_run_script: createSkillsRunScriptTool({
|
|
2179
|
+
catalog: resolvedSkills,
|
|
2180
|
+
state: skillActivationState,
|
|
2181
|
+
scriptTimeoutMs: skillsConfig?.scriptTimeoutMs
|
|
2182
|
+
}),
|
|
2183
|
+
...runBaseTools
|
|
2184
|
+
} : runBaseTools;
|
|
2185
|
+
const toolsPreSearch = {};
|
|
2186
|
+
for (const tool of Object.values(mergedWithSkills)) toolsPreSearch[tool.spec.name] = tool;
|
|
2187
|
+
const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, toolAliases);
|
|
2188
|
+
const unlocked = new Set(disclosure.eagerCanonicalNames);
|
|
2189
|
+
const hostDefinedToolSearch = !!toolsPreSearch.tool_search;
|
|
2190
|
+
const shouldInjectToolSearch = disclosure.lazyEntries.length > 0 && toolSearch?.tool !== false && !hostDefinedToolSearch;
|
|
2191
|
+
let tools = toolsPreSearch;
|
|
2192
|
+
if (shouldInjectToolSearch) {
|
|
2193
|
+
const toolSearchTool = createToolSearchTool({
|
|
2194
|
+
catalog: disclosure.lazyEntries,
|
|
2195
|
+
unlocked,
|
|
2196
|
+
...toolSearch?.limit !== void 0 ? { defaultLimit: toolSearch.limit } : {}
|
|
2197
|
+
});
|
|
2198
|
+
tools = {
|
|
2199
|
+
...toolsPreSearch,
|
|
2200
|
+
[toolSearchTool.spec.name]: toolSearchTool
|
|
2201
|
+
};
|
|
2202
|
+
unlocked.add(toolSearchTool.spec.name);
|
|
2203
|
+
}
|
|
2204
|
+
const discoveryToolName = shouldInjectToolSearch ? "tool_search" : hostDefinedToolSearch ? toolAliases?.tool_search ?? "tool_search" : null;
|
|
2205
|
+
if (disclosure.lazyEntries.length > 0) system = `${system}\n\n${buildSearchableCatalog(disclosure.lazyEntries, { discoveryToolName })}`;
|
|
2206
|
+
const aliasMaps = buildAliasMaps(toolAliases, Object.keys(tools));
|
|
2207
|
+
function buildFormattedTools() {
|
|
2208
|
+
const specs = [];
|
|
2209
|
+
for (const t of Object.values(tools)) {
|
|
2210
|
+
if (!unlocked.has(t.spec.name)) continue;
|
|
2211
|
+
specs.push({
|
|
2212
|
+
name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,
|
|
2213
|
+
description: t.spec.description || "",
|
|
2214
|
+
inputSchema: t.spec.inputSchema
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
return specs.length > 0 ? provider.formatTools(specs) : [];
|
|
2218
|
+
}
|
|
2219
|
+
const formattedTools = buildFormattedTools();
|
|
2220
|
+
const turns = [];
|
|
2221
|
+
const isResume = session && session.turns.length > 0 && (session.runs.length > 0 || !options.prompt) && !options.parentRunId;
|
|
2222
|
+
if (isResume) {
|
|
2223
|
+
const childRunIds = new Set(session.runs.filter((r) => (r.depth ?? 0) > 0).map((r) => r.id));
|
|
2224
|
+
const resumed = childRunIds.size === 0 ? session.turns : session.turns.filter((t) => !t.runId || !childRunIds.has(t.runId));
|
|
2225
|
+
turns.push(...resumed);
|
|
2226
|
+
}
|
|
2227
|
+
const runTurnStart = turns.length;
|
|
2228
|
+
if (options.system) await hooks.callHook("system:before", { system: options.system });
|
|
2229
|
+
const promptParts = canonicalizePrompt(options.prompt);
|
|
2230
|
+
if (promptParts) {
|
|
2231
|
+
const promptMsg = buildPromptMessage(provider, promptParts);
|
|
2232
|
+
turns.push({
|
|
2233
|
+
id: crypto.randomUUID(),
|
|
2234
|
+
runId,
|
|
2235
|
+
role: promptMsg.role,
|
|
2236
|
+
content: promptMsg.content,
|
|
2237
|
+
createdAt: Date.now()
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
conversationTurns = turns;
|
|
2241
|
+
let lastPersistedTurnCount = isResume ? session.turns.length : 0;
|
|
2242
|
+
if (session && turns.length > lastPersistedTurnCount) {
|
|
2243
|
+
const seededTurns = turns.slice(lastPersistedTurnCount);
|
|
2244
|
+
await session.appendTurns(seededTurns);
|
|
2139
2245
|
lastPersistedTurnCount = turns.length;
|
|
2140
2246
|
await hooks.callHook("session:turns", {
|
|
2141
2247
|
sessionId: session.id,
|
|
2142
|
-
turns:
|
|
2248
|
+
turns: seededTurns,
|
|
2143
2249
|
count: turns.length
|
|
2144
2250
|
});
|
|
2145
2251
|
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
await session.appendTurns(remaining);
|
|
2252
|
+
const persistPendingTurns = async () => {
|
|
2253
|
+
if (!session) return;
|
|
2254
|
+
const newTurns = turns.slice(lastPersistedTurnCount);
|
|
2255
|
+
if (newTurns.length === 0) return;
|
|
2256
|
+
await session.appendTurns(newTurns);
|
|
2152
2257
|
lastPersistedTurnCount = turns.length;
|
|
2153
2258
|
await hooks.callHook("session:turns", {
|
|
2154
2259
|
sessionId: session.id,
|
|
2155
|
-
turns:
|
|
2260
|
+
turns: newTurns,
|
|
2156
2261
|
count: turns.length
|
|
2157
2262
|
});
|
|
2263
|
+
};
|
|
2264
|
+
const unregisterTurnSync = session ? hooks.hook("turn:after", persistPendingTurns) : void 0;
|
|
2265
|
+
const unregisterToolResultsSync = session ? hooks.hook("tool-results:after", persistPendingTurns) : void 0;
|
|
2266
|
+
async function flushTurns(opts = {}) {
|
|
2267
|
+
if (!session) return;
|
|
2268
|
+
if (opts.failureFallback) synthesizeMissingToolResults(turns, await session.generateTurnId?.() ?? crypto.randomUUID(), runId, provider);
|
|
2269
|
+
const remaining = turns.slice(lastPersistedTurnCount);
|
|
2270
|
+
if (remaining.length > 0) {
|
|
2271
|
+
await session.appendTurns(remaining);
|
|
2272
|
+
lastPersistedTurnCount = turns.length;
|
|
2273
|
+
await hooks.callHook("session:turns", {
|
|
2274
|
+
sessionId: session.id,
|
|
2275
|
+
turns: remaining,
|
|
2276
|
+
count: turns.length
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2158
2279
|
}
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
});
|
|
2165
|
-
}
|
|
2166
|
-
async function finalizeSession(status) {
|
|
2167
|
-
if (!session) return;
|
|
2168
|
-
const run = session.runs.find((r) => r.id === runId);
|
|
2169
|
-
if (run) await session.updateRun(run);
|
|
2170
|
-
await session.updateStatus(status === "aborted" ? "idle" : status);
|
|
2171
|
-
await hooks.callHook("session:end", {
|
|
2172
|
-
sessionId: session.id,
|
|
2173
|
-
runId,
|
|
2174
|
-
status,
|
|
2175
|
-
turnRange: [runTurnStart, turns.length - 1]
|
|
2176
|
-
});
|
|
2177
|
-
}
|
|
2178
|
-
const uninstallAllowedToolsGate = installAllowedToolsGate(hooks, skillActivationState);
|
|
2179
|
-
const uninstallToolBudgets = installToolBudgetsGate(hooks, () => toolBudgets, (msg) => steeringQueue.push(msg));
|
|
2180
|
-
const uninstallDedupTools = installDedupToolsGate(hooks, () => dedupTools, () => session ?? void 0);
|
|
2181
|
-
const runStartMs = Date.now();
|
|
2182
|
-
const runDepth = typeof options.depth === "number" ? options.depth : 0;
|
|
2183
|
-
try {
|
|
2184
|
-
const stats = await runLoop({
|
|
2185
|
-
provider,
|
|
2186
|
-
hooks,
|
|
2187
|
-
agentName,
|
|
2188
|
-
agentSystem,
|
|
2189
|
-
agentTools: sourceTools,
|
|
2190
|
-
agentToolAliases: toolAliases,
|
|
2191
|
-
agentMcpServers: mcpServers,
|
|
2192
|
-
agentSkills,
|
|
2193
|
-
agentBehavior: resolvedBehavior,
|
|
2194
|
-
tools,
|
|
2195
|
-
formattedTools,
|
|
2196
|
-
rebuildFormattedTools: disclosure.lazyEntries.length > 0 ? buildFormattedTools : void 0,
|
|
2197
|
-
aliasMaps,
|
|
2198
|
-
model,
|
|
2199
|
-
system,
|
|
2200
|
-
thinking,
|
|
2201
|
-
toolExecution,
|
|
2202
|
-
signal: abortController.signal,
|
|
2203
|
-
execution: executionContext,
|
|
2204
|
-
handle: executionHandle,
|
|
2205
|
-
steeringQueue,
|
|
2206
|
-
followUpQueue,
|
|
2207
|
-
turns,
|
|
2208
|
-
runId,
|
|
2209
|
-
generateTurnId: () => session?.generateTurnId() ?? crypto.randomUUID(),
|
|
2210
|
-
maxTurns,
|
|
2211
|
-
maxTokens,
|
|
2212
|
-
...session ? { session } : {},
|
|
2213
|
-
depth: runDepth,
|
|
2214
|
-
thinkingBudget,
|
|
2215
|
-
schema,
|
|
2216
|
-
cache,
|
|
2217
|
-
toolOutputBudget,
|
|
2218
|
-
compactStrategy,
|
|
2219
|
-
compactThreshold,
|
|
2220
|
-
compactKeepTurns,
|
|
2221
|
-
...elideStaleReads !== void 0 ? { elideStaleReads } : {},
|
|
2222
|
-
...thinkingDecay !== void 0 ? { thinkingDecay } : {},
|
|
2223
|
-
runStartMs,
|
|
2224
|
-
runToolCounts: {}
|
|
2225
|
-
});
|
|
2226
|
-
const parentTurnCost = stats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0) ?? 0;
|
|
2227
|
-
let childrenIn = 0;
|
|
2228
|
-
let childrenOut = 0;
|
|
2229
|
-
let childrenCost = 0;
|
|
2230
|
-
let childrenCacheRead = 0;
|
|
2231
|
-
let childrenCacheCreation = 0;
|
|
2232
|
-
for (const c of childrenStats) {
|
|
2233
|
-
childrenIn += c.stats.totalIn;
|
|
2234
|
-
childrenOut += c.stats.totalOut;
|
|
2235
|
-
childrenCost += c.stats.cost ?? 0;
|
|
2236
|
-
childrenCacheRead += c.stats.totalCacheRead;
|
|
2237
|
-
childrenCacheCreation += c.stats.totalCacheCreation;
|
|
2280
|
+
async function deactivateAllSkills() {
|
|
2281
|
+
for (const record of skillActivationState.clear()) await hooks.callHook("skills:deactivate", {
|
|
2282
|
+
skill: record.skill,
|
|
2283
|
+
reason: "run-end"
|
|
2284
|
+
});
|
|
2238
2285
|
}
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
if (abortController.signal.aborted) {
|
|
2251
|
-
session?.abortRun(runId);
|
|
2252
|
-
await finalizeSession("aborted");
|
|
2253
|
-
await hooks.callHook("agent:done", finalStats);
|
|
2254
|
-
return finalStats;
|
|
2286
|
+
async function finalizeSession(status) {
|
|
2287
|
+
if (!session) return;
|
|
2288
|
+
const run = session.runs.find((r) => r.id === runId);
|
|
2289
|
+
if (run) await session.updateRun(run);
|
|
2290
|
+
await session.updateStatus(status === "aborted" ? "idle" : status);
|
|
2291
|
+
await hooks.callHook("session:end", {
|
|
2292
|
+
sessionId: session.id,
|
|
2293
|
+
runId,
|
|
2294
|
+
status,
|
|
2295
|
+
turnRange: [runTurnStart, turns.length - 1]
|
|
2296
|
+
});
|
|
2255
2297
|
}
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2298
|
+
const uninstallAllowedToolsGate = installAllowedToolsGate(hooks, skillActivationState);
|
|
2299
|
+
const uninstallToolBudgets = installToolBudgetsGate(hooks, () => toolBudgets, (msg) => steeringQueue.push(msg));
|
|
2300
|
+
const uninstallDedupTools = installDedupToolsGate(hooks, () => dedupTools, () => session ?? void 0);
|
|
2301
|
+
const uninstallLazyDisclosureGate = installLazyDisclosureGate(hooks, disclosure.lazyCanonicalNames, unlocked, discoveryToolName);
|
|
2302
|
+
const runStartMs = Date.now();
|
|
2303
|
+
const runDepth = typeof options.depth === "number" ? options.depth : 0;
|
|
2304
|
+
try {
|
|
2305
|
+
const stats = await runLoop({
|
|
2306
|
+
provider,
|
|
2307
|
+
hooks,
|
|
2308
|
+
agentName,
|
|
2309
|
+
agentSystem,
|
|
2310
|
+
agentTools: sourceTools,
|
|
2311
|
+
agentToolAliases: toolAliases,
|
|
2312
|
+
agentMcpServers: mcpServers,
|
|
2313
|
+
agentSkills,
|
|
2314
|
+
agentBehavior: resolvedBehavior,
|
|
2315
|
+
tools,
|
|
2316
|
+
formattedTools,
|
|
2317
|
+
rebuildFormattedTools: disclosure.lazyEntries.length > 0 ? buildFormattedTools : void 0,
|
|
2318
|
+
aliasMaps,
|
|
2319
|
+
model,
|
|
2320
|
+
system,
|
|
2321
|
+
thinking,
|
|
2322
|
+
toolExecution,
|
|
2323
|
+
signal: abortController.signal,
|
|
2324
|
+
execution: executionContext,
|
|
2325
|
+
handle: executionHandle,
|
|
2326
|
+
steeringQueue,
|
|
2327
|
+
followUpQueue,
|
|
2328
|
+
turns,
|
|
2329
|
+
runId,
|
|
2330
|
+
generateTurnId: () => session?.generateTurnId() ?? crypto.randomUUID(),
|
|
2331
|
+
maxTurns,
|
|
2332
|
+
maxTokens,
|
|
2333
|
+
...session ? { session } : {},
|
|
2334
|
+
depth: runDepth,
|
|
2335
|
+
thinkingBudget,
|
|
2336
|
+
schema,
|
|
2337
|
+
cache,
|
|
2338
|
+
toolOutputBudget,
|
|
2339
|
+
compactStrategy,
|
|
2340
|
+
compactThreshold,
|
|
2341
|
+
compactKeepTurns,
|
|
2342
|
+
...elideStaleReads !== void 0 ? { elideStaleReads } : {},
|
|
2343
|
+
...thinkingDecay !== void 0 ? { thinkingDecay } : {},
|
|
2344
|
+
runStartMs,
|
|
2345
|
+
runToolCounts: {}
|
|
2346
|
+
});
|
|
2347
|
+
const parentTurnCost = stats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0) ?? 0;
|
|
2348
|
+
let childrenIn = 0;
|
|
2349
|
+
let childrenOut = 0;
|
|
2350
|
+
let childrenCost = 0;
|
|
2351
|
+
let childrenCacheRead = 0;
|
|
2352
|
+
let childrenCacheCreation = 0;
|
|
2353
|
+
for (const c of childrenStats) {
|
|
2354
|
+
childrenIn += c.stats.totalIn;
|
|
2355
|
+
childrenOut += c.stats.totalOut;
|
|
2356
|
+
childrenCost += c.stats.cost ?? 0;
|
|
2357
|
+
childrenCacheRead += c.stats.totalCacheRead;
|
|
2358
|
+
childrenCacheCreation += c.stats.totalCacheCreation;
|
|
2359
|
+
}
|
|
2360
|
+
const cumulativeCost = parentTurnCost + childrenCost;
|
|
2361
|
+
const finalStats = {
|
|
2362
|
+
...stats,
|
|
2363
|
+
totalIn: stats.totalIn + childrenIn,
|
|
2364
|
+
totalOut: stats.totalOut + childrenOut,
|
|
2365
|
+
totalCacheRead: stats.totalCacheRead + childrenCacheRead,
|
|
2366
|
+
totalCacheCreation: stats.totalCacheCreation + childrenCacheCreation,
|
|
2367
|
+
...cumulativeCost > 0 ? { cost: cumulativeCost } : {},
|
|
2368
|
+
children: childrenStats.length > 0 ? childrenStats : void 0
|
|
2278
2369
|
};
|
|
2279
|
-
await
|
|
2280
|
-
|
|
2370
|
+
await flushTurns();
|
|
2371
|
+
if (abortController.signal.aborted) {
|
|
2372
|
+
session?.abortRun(runId, {
|
|
2373
|
+
turns: stats.turns,
|
|
2374
|
+
tokensIn: stats.totalIn,
|
|
2375
|
+
tokensOut: stats.totalOut,
|
|
2376
|
+
turnUsage: stats.turnUsage,
|
|
2377
|
+
cost: parentTurnCost > 0 ? parentTurnCost : void 0
|
|
2378
|
+
});
|
|
2379
|
+
await finalizeSession("aborted");
|
|
2380
|
+
await hooks.callHook("agent:done", finalStats);
|
|
2381
|
+
return finalStats;
|
|
2382
|
+
}
|
|
2383
|
+
session?.completeRun(runId, {
|
|
2384
|
+
turns: stats.turns,
|
|
2385
|
+
tokensIn: stats.totalIn,
|
|
2386
|
+
tokensOut: stats.totalOut,
|
|
2387
|
+
turnUsage: stats.turnUsage,
|
|
2388
|
+
cost: parentTurnCost > 0 ? parentTurnCost : void 0
|
|
2389
|
+
});
|
|
2390
|
+
await finalizeSession("completed");
|
|
2391
|
+
await hooks.callHook("agent:done", finalStats);
|
|
2392
|
+
return finalStats;
|
|
2393
|
+
} catch (err) {
|
|
2394
|
+
await flushTurns({ failureFallback: true });
|
|
2395
|
+
if (abortController.signal.aborted) {
|
|
2396
|
+
session?.abortRun(runId);
|
|
2397
|
+
await finalizeSession("aborted");
|
|
2398
|
+
const stats = {
|
|
2399
|
+
totalIn: 0,
|
|
2400
|
+
totalOut: 0,
|
|
2401
|
+
totalCacheRead: 0,
|
|
2402
|
+
totalCacheCreation: 0,
|
|
2403
|
+
turns: 0,
|
|
2404
|
+
elapsed: 0
|
|
2405
|
+
};
|
|
2406
|
+
await hooks.callHook("agent:done", stats);
|
|
2407
|
+
return stats;
|
|
2408
|
+
}
|
|
2409
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2410
|
+
session?.errorRun(runId, message);
|
|
2411
|
+
await finalizeSession("error");
|
|
2412
|
+
throw err;
|
|
2413
|
+
} finally {
|
|
2414
|
+
await deactivateAllSkills();
|
|
2415
|
+
uninstallAllowedToolsGate();
|
|
2416
|
+
uninstallDedupTools();
|
|
2417
|
+
uninstallToolBudgets();
|
|
2418
|
+
uninstallLazyDisclosureGate();
|
|
2419
|
+
unregisterSpawnHook();
|
|
2420
|
+
unregisterTurnSync?.();
|
|
2421
|
+
unregisterToolResultsSync?.();
|
|
2422
|
+
for (const unregister of perRunUnregisters) unregister();
|
|
2423
|
+
running = false;
|
|
2424
|
+
abortController = void 0;
|
|
2425
|
+
steeringQueue.length = 0;
|
|
2426
|
+
followUpQueue.length = 0;
|
|
2427
|
+
idleResolve?.();
|
|
2428
|
+
idlePromise = void 0;
|
|
2429
|
+
idleResolve = void 0;
|
|
2281
2430
|
}
|
|
2282
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2283
|
-
session?.errorRun(runId, message);
|
|
2284
|
-
await finalizeSession("error");
|
|
2285
|
-
throw err;
|
|
2286
2431
|
} finally {
|
|
2287
|
-
await deactivateAllSkills();
|
|
2288
|
-
uninstallAllowedToolsGate();
|
|
2289
|
-
uninstallDedupTools();
|
|
2290
|
-
uninstallToolBudgets();
|
|
2291
|
-
uninstallLazyDisclosureGate();
|
|
2292
|
-
unregisterSpawnHook();
|
|
2293
|
-
unregisterSessionSync?.();
|
|
2294
|
-
for (const unregister of perRunUnregisters) unregister();
|
|
2295
2432
|
running = false;
|
|
2296
2433
|
abortController = void 0;
|
|
2297
|
-
steeringQueue.length = 0;
|
|
2298
|
-
followUpQueue.length = 0;
|
|
2299
2434
|
idleResolve?.();
|
|
2300
2435
|
idlePromise = void 0;
|
|
2301
2436
|
idleResolve = void 0;
|
|
2437
|
+
if (externalSignal && externalAbortListener) externalSignal.removeEventListener("abort", externalAbortListener);
|
|
2302
2438
|
}
|
|
2303
2439
|
}
|
|
2304
2440
|
function abort() {
|
|
@@ -2325,7 +2461,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2325
2461
|
});
|
|
2326
2462
|
}
|
|
2327
2463
|
async function activateSkill(name) {
|
|
2328
|
-
|
|
2464
|
+
await ensureSkillsResolved();
|
|
2465
|
+
if (!resolvedSkills) throw new Error(`Cannot activate skill "${name}" — skills are disabled for this agent.`);
|
|
2329
2466
|
const skill = resolvedSkills.find((s) => s.name === name);
|
|
2330
2467
|
if (!skill) {
|
|
2331
2468
|
const available = resolvedSkills.map((s) => s.name).join(", ") || "<none>";
|
|
@@ -2371,8 +2508,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2371
2508
|
* retry — leaving a rejected promise cached would permanently poison future
|
|
2372
2509
|
* runs on the same agent.
|
|
2373
2510
|
*/
|
|
2374
|
-
async function
|
|
2375
|
-
if (destroyed) return;
|
|
2511
|
+
async function ensureMcpConnected() {
|
|
2376
2512
|
if (mcpConnection || allMcpServers.length === 0) return;
|
|
2377
2513
|
if (mcpWarmupPromise) return mcpWarmupPromise;
|
|
2378
2514
|
mcpWarmupPromise = (async () => {
|
|
@@ -2390,6 +2526,10 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2390
2526
|
throw err;
|
|
2391
2527
|
}
|
|
2392
2528
|
}
|
|
2529
|
+
async function warmup() {
|
|
2530
|
+
if (destroyed) return;
|
|
2531
|
+
await Promise.all([ensureMcpConnected(), ensureSkillsResolved()]);
|
|
2532
|
+
}
|
|
2393
2533
|
async function destroy() {
|
|
2394
2534
|
if (destroyed) return;
|
|
2395
2535
|
destroyed = true;
|
|
@@ -2407,7 +2547,8 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2407
2547
|
skillsCleanup();
|
|
2408
2548
|
skillsCleanup = () => {};
|
|
2409
2549
|
}
|
|
2410
|
-
|
|
2550
|
+
const eagerHasWork = allMcpServers.length > 0 || !skillsDisabled && !!skillsConfig;
|
|
2551
|
+
if (eager && eagerHasWork) warmup().catch(() => {});
|
|
2411
2552
|
return {
|
|
2412
2553
|
hooks,
|
|
2413
2554
|
run,
|
|
@@ -3701,17 +3842,33 @@ var SpawnTimeoutError = class extends Error {
|
|
|
3701
3842
|
* Called before `agent.run()` starts, torn down in a finally block — so
|
|
3702
3843
|
* nothing leaks even if the child throws mid-run.
|
|
3703
3844
|
*/
|
|
3845
|
+
/**
|
|
3846
|
+
* Surface a thrown observational-bubble listener without killing the
|
|
3847
|
+
* process. Observational events (`child:stream:text`, `child:tool:after`,
|
|
3848
|
+
* `child:turn:after`, …) are fire-and-forget — a rejected promise here
|
|
3849
|
+
* has no caller. Without this handler, a buggy parent listener bubbles
|
|
3850
|
+
* up to an unhandled-rejection, and Node/Bun under
|
|
3851
|
+
* `--unhandled-rejections=strict` terminates the host.
|
|
3852
|
+
*
|
|
3853
|
+
* Gated on `ZIDANE_DEBUG` so production logs stay quiet; debug builds
|
|
3854
|
+
* still get the tagged line.
|
|
3855
|
+
*/
|
|
3856
|
+
function swallowBubbleError(eventName, err) {
|
|
3857
|
+
if (!process.env.ZIDANE_DEBUG) return;
|
|
3858
|
+
const message = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
3859
|
+
process.stderr.write(`[zidane/spawn] parent listener for "${eventName}" rejected: ${message}\n`);
|
|
3860
|
+
}
|
|
3704
3861
|
function bubbleHooks(childHooks, parentHooks, childId, depth) {
|
|
3705
3862
|
const unregisters = [];
|
|
3706
3863
|
const fire = parentHooks.callHook;
|
|
3707
3864
|
for (const evt of BUBBLED_EVENTS) {
|
|
3708
3865
|
const parentEvt = CHILD_EVENT_NAME[evt];
|
|
3709
3866
|
const unregister = childHooks.hook(evt, (ctx) => {
|
|
3710
|
-
fire(parentEvt, {
|
|
3867
|
+
Promise.resolve(fire(parentEvt, {
|
|
3711
3868
|
...ctx,
|
|
3712
3869
|
childId,
|
|
3713
3870
|
depth
|
|
3714
|
-
});
|
|
3871
|
+
})).catch((err) => swallowBubbleError(parentEvt, err));
|
|
3715
3872
|
});
|
|
3716
3873
|
unregisters.push(unregister);
|
|
3717
3874
|
}
|
|
@@ -3731,7 +3888,7 @@ function bubbleHooks(childHooks, parentHooks, childId, depth) {
|
|
|
3731
3888
|
for (const evt of BUBBLED_EVENTS) {
|
|
3732
3889
|
const parentEvt = CHILD_EVENT_NAME[evt];
|
|
3733
3890
|
unregisters.push(chainHook(parentEvt, (ctx) => {
|
|
3734
|
-
fire(parentEvt, ctx);
|
|
3891
|
+
Promise.resolve(fire(parentEvt, ctx)).catch((err) => swallowBubbleError(parentEvt, err));
|
|
3735
3892
|
}));
|
|
3736
3893
|
}
|
|
3737
3894
|
for (const evt of BUBBLED_GATE_EVENTS) {
|
|
@@ -3988,4 +4145,4 @@ const writeFile$1 = {
|
|
|
3988
4145
|
//#endregion
|
|
3989
4146
|
export { multiEdit as a, grep as c, createAgent as d, createToolSearchTool as f, validateToolArgs as g, createSkillsReadTool as h, readFile$1 as i, glob as l, createSkillsRunScriptTool as m, createSpawnTool as n, listFiles as o, createSkillsUseTool as p, shell as r, createInteractionTool as s, writeFile$1 as t, edit as u };
|
|
3990
4147
|
|
|
3991
|
-
//# sourceMappingURL=tools-
|
|
4148
|
+
//# sourceMappingURL=tools-CLazLRb4.js.map
|