zidane 4.1.7 → 4.1.9

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.
Files changed (59) hide show
  1. package/dist/{index-bgh-k8Mv.d.ts → agent-CMIhYhDz.d.ts} +2032 -1993
  2. package/dist/agent-CMIhYhDz.d.ts.map +1 -0
  3. package/dist/chat.d.ts +7 -6
  4. package/dist/chat.d.ts.map +1 -1
  5. package/dist/chat.js +2 -2
  6. package/dist/contexts.d.ts +1 -1
  7. package/dist/{index-BB4kuRh3.d.ts → index-CXVvqTQj.d.ts} +1 -1
  8. package/dist/{index-BB4kuRh3.d.ts.map → index-CXVvqTQj.d.ts.map} +1 -1
  9. package/dist/{index-Ds5YpvfZ.d.ts → index-D6Dd6Kc0.d.ts} +3 -3
  10. package/dist/{index-Ds5YpvfZ.d.ts.map → index-D6Dd6Kc0.d.ts.map} +1 -1
  11. package/dist/{index-DRoG_udt.d.ts → index-DAaKyadO.d.ts} +2 -2
  12. package/dist/{index-DRoG_udt.d.ts.map → index-DAaKyadO.d.ts.map} +1 -1
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.js +6 -6
  15. package/dist/{interpolate-CukJwP2G.js → interpolate-BydkV1eT.js} +3 -1
  16. package/dist/interpolate-BydkV1eT.js.map +1 -0
  17. package/dist/{mcp-8wClKY-3.js → mcp-Dw-fRPVk.js} +61 -65
  18. package/dist/mcp-Dw-fRPVk.js.map +1 -0
  19. package/dist/mcp.d.ts +1 -1
  20. package/dist/mcp.js +1 -1
  21. package/dist/{presets-BzkJDW1K.js → presets-4zCJzCYw.js} +2 -2
  22. package/dist/{presets-BzkJDW1K.js.map → presets-4zCJzCYw.js.map} +1 -1
  23. package/dist/presets.d.ts +1 -1
  24. package/dist/presets.js +1 -1
  25. package/dist/providers.d.ts +1 -1
  26. package/dist/session/sqlite.d.ts +13 -2
  27. package/dist/session/sqlite.d.ts.map +1 -1
  28. package/dist/session/sqlite.js +70 -27
  29. package/dist/session/sqlite.js.map +1 -1
  30. package/dist/{session-Cn68UASv.js → session-B1RN0uoi.js} +42 -30
  31. package/dist/{session-Cn68UASv.js.map → session-B1RN0uoi.js.map} +1 -1
  32. package/dist/session.d.ts +1 -1
  33. package/dist/session.js +1 -1
  34. package/dist/skills.d.ts +2 -2
  35. package/dist/skills.js +1 -1
  36. package/dist/{stats-BT9l57RS.js → stats-DZIsGqzu.js} +15 -5
  37. package/dist/stats-DZIsGqzu.js.map +1 -0
  38. package/dist/{theme-BlXO6yHe.d.ts → theme-Caf4AvTO.d.ts} +147 -13
  39. package/dist/theme-Caf4AvTO.d.ts.map +1 -0
  40. package/dist/{theme-context-MungM3SY.js → theme-context-DQM2lx4U.js} +212 -72
  41. package/dist/theme-context-DQM2lx4U.js.map +1 -0
  42. package/dist/{tools-C8kDot0H.js → tools-BdQENveS.js} +409 -312
  43. package/dist/tools-BdQENveS.js.map +1 -0
  44. package/dist/tools.d.ts +2 -2
  45. package/dist/tools.js +1 -1
  46. package/dist/tui.d.ts +64 -7
  47. package/dist/tui.d.ts.map +1 -1
  48. package/dist/tui.js +481 -143
  49. package/dist/tui.js.map +1 -1
  50. package/dist/types.d.ts +3 -3
  51. package/dist/types.js +1 -1
  52. package/package.json +6 -1
  53. package/dist/index-bgh-k8Mv.d.ts.map +0 -1
  54. package/dist/interpolate-CukJwP2G.js.map +0 -1
  55. package/dist/mcp-8wClKY-3.js.map +0 -1
  56. package/dist/stats-BT9l57RS.js.map +0 -1
  57. package/dist/theme-BlXO6yHe.d.ts.map +0 -1
  58. package/dist/theme-context-MungM3SY.js.map +0 -1
  59. 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-8wClKY-3.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-CukJwP2G.js";
6
- import { n as formatTokenUsage, t as flattenTurns } from "./stats-BT9l57RS.js";
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-BydkV1eT.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
- ctx.turns.push({
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
- const { result } = await executeSingleTool(ctx, call, turnId);
1155
- results.push(result);
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",
@@ -1967,338 +2027,359 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
1967
2027
  const lastTurn = session.turns.at(-1);
1968
2028
  if (lastTurn && lastTurn.role !== "user") throw new Error("cannot resume without prompt: last session turn must be a user message");
1969
2029
  }
2030
+ let externalAbortListener;
2031
+ const externalSignal = options.signal;
1970
2032
  running = true;
1971
- abortController = new AbortController();
1972
- const runId = `run_${++runCounter}`;
1973
- 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") : "";
1974
- session?.startRun(runId, promptLabel, {
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
2033
+ try {
2034
+ abortController = new AbortController();
2035
+ const runId = `run_${++runCounter}`;
2036
+ 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") : "";
2037
+ session?.startRun(runId, promptLabel, {
2038
+ ...options.parentRunId ? { parentRunId: options.parentRunId } : {},
2039
+ depth: typeof options.depth === "number" ? options.depth : 0
1984
2040
  });
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));
2041
+ if (session) {
2042
+ await session.updateStatus("running");
2043
+ await hooks.callHook("session:start", {
2044
+ sessionId: session.id,
2045
+ runId,
2046
+ prompt: promptLabel
2047
+ });
2005
2048
  }
2006
- }
2007
- if (!executionHandle) executionHandle = await executionContext.spawn();
2008
- if (allMcpServers.length > 0 && !mcpConnection) await warmup();
2009
- if (!skillsDisabled && skillsConfig && !resolvedSkills) {
2010
- const bundle = await resolveSkills(skillsConfig);
2011
- resolvedSkills = bundle.skills;
2012
- skillsCleanup = bundle.cleanup;
2013
- await hooks.callHook("skills:resolve", { skills: resolvedSkills });
2014
- const skillsToolRegistered = skillsConfig?.tool !== false && resolvedSkills.length > 0;
2015
- const catalogCtx = {
2016
- catalog: buildCatalog(resolvedSkills, { skillsToolRegistered }),
2017
- skills: resolvedSkills
2018
- };
2019
- await hooks.callHook("skills:catalog", catalogCtx);
2020
- skillsCatalog = catalogCtx.catalog;
2021
- }
2022
- if (resolvedSkills && session && session.turns.length > 0 && skillActivationState.active().length === 0) {
2023
- const skillsByName = new Map(resolvedSkills.map((s) => [s.name, s]));
2024
- for (const turn of session.turns) {
2025
- if (turn.role !== "assistant") continue;
2026
- for (const block of turn.content) {
2027
- if (block.type !== "tool_call" || block.name !== "skills_use") continue;
2028
- const skillName = block.input?.name;
2029
- if (!skillName) continue;
2030
- const skill = skillsByName.get(skillName);
2031
- if (!skill) continue;
2032
- if (skillActivationState.activate(skill, "resume") === "ok") await hooks.callHook("skills:activate", {
2033
- skill,
2034
- via: "resume"
2049
+ if (externalSignal) if (externalSignal.aborted) abortController.abort();
2050
+ else {
2051
+ externalAbortListener = () => abortController?.abort();
2052
+ externalSignal.addEventListener("abort", externalAbortListener, { once: true });
2053
+ }
2054
+ idlePromise = new Promise((resolve) => {
2055
+ idleResolve = resolve;
2056
+ });
2057
+ const childrenStats = [];
2058
+ const unregisterSpawnHook = hooks.hook("spawn:complete", (ctx) => {
2059
+ childrenStats.push(ctx);
2060
+ });
2061
+ const perRunUnregisters = [];
2062
+ if (options.hooks) for (const [event, handler] of Object.entries(options.hooks)) {
2063
+ if (!isKnownHookEvent(event)) throw new Error(`Unknown hook event "${event}" passed to run(). See AgentHooks for valid events.`);
2064
+ const handlerList = Array.isArray(handler) ? handler : [handler];
2065
+ for (const fn of handlerList) {
2066
+ if (typeof fn !== "function") continue;
2067
+ perRunUnregisters.push(hooks.hook(event, fn));
2068
+ }
2069
+ }
2070
+ if (!executionHandle) executionHandle = await executionContext.spawn();
2071
+ if (allMcpServers.length > 0 && !mcpConnection) await warmup();
2072
+ if (!skillsDisabled && skillsConfig && !resolvedSkills) {
2073
+ const bundle = await resolveSkills(skillsConfig);
2074
+ resolvedSkills = bundle.skills;
2075
+ skillsCleanup = bundle.cleanup;
2076
+ await hooks.callHook("skills:resolve", { skills: resolvedSkills });
2077
+ const skillsToolRegistered = skillsConfig?.tool !== false && resolvedSkills.length > 0;
2078
+ const catalogCtx = {
2079
+ catalog: buildCatalog(resolvedSkills, { skillsToolRegistered }),
2080
+ skills: resolvedSkills
2081
+ };
2082
+ await hooks.callHook("skills:catalog", catalogCtx);
2083
+ skillsCatalog = catalogCtx.catalog;
2084
+ }
2085
+ if (resolvedSkills && session && session.turns.length > 0 && skillActivationState.active().length === 0) {
2086
+ const skillsByName = new Map(resolvedSkills.map((s) => [s.name, s]));
2087
+ for (const turn of session.turns) {
2088
+ if (turn.role !== "assistant") continue;
2089
+ for (const block of turn.content) {
2090
+ if (block.type !== "tool_call" || block.name !== "skills_use") continue;
2091
+ const skillName = block.input?.name;
2092
+ if (!skillName) continue;
2093
+ const skill = skillsByName.get(skillName);
2094
+ if (!skill) continue;
2095
+ if (skillActivationState.activate(skill, "resume") === "ok") await hooks.callHook("skills:activate", {
2096
+ skill,
2097
+ via: "resume"
2098
+ });
2099
+ }
2100
+ }
2101
+ }
2102
+ const thinking = options.thinking ?? "off";
2103
+ const model = options.model ?? provider.meta.defaultModel;
2104
+ const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior);
2105
+ const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch } = resolvedBehavior;
2106
+ let system = options.system || agentSystem || "You are a helpful assistant.";
2107
+ if (skillsCatalog) system = `${system}\n\n${skillsCatalog}`;
2108
+ const runBaseTools = options.tools !== void 0 ? options.tools : mcpConnection ? {
2109
+ ...sourceTools,
2110
+ ...mcpConnection.tools
2111
+ } : sourceTools;
2112
+ const mcpToolNames = options.tools === void 0 && mcpConnection ? new Set(Object.keys(mcpConnection.tools)) : /* @__PURE__ */ new Set();
2113
+ const mergedWithSkills = options.tools === void 0 && !!resolvedSkills && resolvedSkills.length > 0 && skillsConfig?.tool !== false ? {
2114
+ skills_use: createSkillsUseTool({
2115
+ catalog: resolvedSkills,
2116
+ state: skillActivationState,
2117
+ hooks
2118
+ }),
2119
+ skills_read: createSkillsReadTool({
2120
+ catalog: resolvedSkills,
2121
+ state: skillActivationState
2122
+ }),
2123
+ skills_run_script: createSkillsRunScriptTool({
2124
+ catalog: resolvedSkills,
2125
+ state: skillActivationState,
2126
+ scriptTimeoutMs: skillsConfig?.scriptTimeoutMs
2127
+ }),
2128
+ ...runBaseTools
2129
+ } : runBaseTools;
2130
+ const toolsPreSearch = {};
2131
+ for (const tool of Object.values(mergedWithSkills)) toolsPreSearch[tool.spec.name] = tool;
2132
+ const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, toolAliases);
2133
+ const unlocked = new Set(disclosure.eagerCanonicalNames);
2134
+ const hostDefinedToolSearch = !!toolsPreSearch.tool_search;
2135
+ const shouldInjectToolSearch = disclosure.lazyEntries.length > 0 && toolSearch?.tool !== false && !hostDefinedToolSearch;
2136
+ let tools = toolsPreSearch;
2137
+ if (shouldInjectToolSearch) {
2138
+ const toolSearchTool = createToolSearchTool({
2139
+ catalog: disclosure.lazyEntries,
2140
+ unlocked,
2141
+ ...toolSearch?.limit !== void 0 ? { defaultLimit: toolSearch.limit } : {}
2142
+ });
2143
+ tools = {
2144
+ ...toolsPreSearch,
2145
+ [toolSearchTool.spec.name]: toolSearchTool
2146
+ };
2147
+ unlocked.add(toolSearchTool.spec.name);
2148
+ }
2149
+ const discoveryToolName = shouldInjectToolSearch ? "tool_search" : hostDefinedToolSearch ? toolAliases?.tool_search ?? "tool_search" : null;
2150
+ if (disclosure.lazyEntries.length > 0) system = `${system}\n\n${buildSearchableCatalog(disclosure.lazyEntries, { discoveryToolName })}`;
2151
+ const aliasMaps = buildAliasMaps(toolAliases, Object.keys(tools));
2152
+ function buildFormattedTools() {
2153
+ const specs = [];
2154
+ for (const t of Object.values(tools)) {
2155
+ if (!unlocked.has(t.spec.name)) continue;
2156
+ specs.push({
2157
+ name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,
2158
+ description: t.spec.description || "",
2159
+ inputSchema: t.spec.inputSchema
2035
2160
  });
2036
2161
  }
2162
+ return specs.length > 0 ? provider.formatTools(specs) : [];
2037
2163
  }
2038
- }
2039
- const thinking = options.thinking ?? "off";
2040
- const model = options.model ?? provider.meta.defaultModel;
2041
- const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior);
2042
- const { toolExecution, maxTurns, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch } = resolvedBehavior;
2043
- let system = options.system || agentSystem || "You are a helpful assistant.";
2044
- if (skillsCatalog) system = `${system}\n\n${skillsCatalog}`;
2045
- const runBaseTools = options.tools !== void 0 ? options.tools : mcpConnection ? {
2046
- ...sourceTools,
2047
- ...mcpConnection.tools
2048
- } : sourceTools;
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 } : {}
2079
- });
2080
- tools = {
2081
- ...toolsPreSearch,
2082
- [toolSearchTool.spec.name]: toolSearchTool
2083
- };
2084
- unlocked.add(toolSearchTool.spec.name);
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
2164
+ const formattedTools = buildFormattedTools();
2165
+ const turns = [];
2166
+ const isResume = session && session.turns.length > 0 && (session.runs.length > 0 || !options.prompt) && !options.parentRunId;
2167
+ if (isResume) {
2168
+ const childRunIds = new Set(session.runs.filter((r) => (r.depth ?? 0) > 0).map((r) => r.id));
2169
+ const resumed = childRunIds.size === 0 ? session.turns : session.turns.filter((t) => !t.runId || !childRunIds.has(t.runId));
2170
+ turns.push(...resumed);
2171
+ }
2172
+ const runTurnStart = turns.length;
2173
+ if (options.system) await hooks.callHook("system:before", { system: options.system });
2174
+ const promptParts = canonicalizePrompt(options.prompt);
2175
+ if (promptParts) {
2176
+ const promptMsg = buildPromptMessage(provider, promptParts);
2177
+ turns.push({
2178
+ id: crypto.randomUUID(),
2179
+ runId,
2180
+ role: promptMsg.role,
2181
+ content: promptMsg.content,
2182
+ createdAt: Date.now()
2098
2183
  });
2099
2184
  }
2100
- return specs.length > 0 ? provider.formatTools(specs) : [];
2101
- }
2102
- const formattedTools = buildFormattedTools();
2103
- const turns = [];
2104
- const isResume = session && session.turns.length > 0 && (session.runs.length > 0 || !options.prompt) && !options.parentRunId;
2105
- if (isResume) {
2106
- const childRunIds = new Set(session.runs.filter((r) => (r.depth ?? 0) > 0).map((r) => r.id));
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()
2121
- });
2122
- }
2123
- conversationTurns = turns;
2124
- let lastPersistedTurnCount = isResume ? session.turns.length : 0;
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
2133
- });
2134
- }
2135
- const unregisterSessionSync = session ? hooks.hook("turn:after", async () => {
2136
- const newTurns = turns.slice(lastPersistedTurnCount);
2137
- if (newTurns.length > 0) {
2138
- await session.appendTurns(newTurns);
2185
+ conversationTurns = turns;
2186
+ let lastPersistedTurnCount = isResume ? session.turns.length : 0;
2187
+ if (session && turns.length > lastPersistedTurnCount) {
2188
+ const seededTurns = turns.slice(lastPersistedTurnCount);
2189
+ await session.appendTurns(seededTurns);
2139
2190
  lastPersistedTurnCount = turns.length;
2140
2191
  await hooks.callHook("session:turns", {
2141
2192
  sessionId: session.id,
2142
- turns: newTurns,
2193
+ turns: seededTurns,
2143
2194
  count: turns.length
2144
2195
  });
2145
2196
  }
2146
- }) : void 0;
2147
- async function flushTurns() {
2148
- if (!session) return;
2149
- const remaining = turns.slice(lastPersistedTurnCount);
2150
- if (remaining.length > 0) {
2151
- await session.appendTurns(remaining);
2197
+ const persistPendingTurns = async () => {
2198
+ if (!session) return;
2199
+ const newTurns = turns.slice(lastPersistedTurnCount);
2200
+ if (newTurns.length === 0) return;
2201
+ await session.appendTurns(newTurns);
2152
2202
  lastPersistedTurnCount = turns.length;
2153
2203
  await hooks.callHook("session:turns", {
2154
2204
  sessionId: session.id,
2155
- turns: remaining,
2205
+ turns: newTurns,
2156
2206
  count: turns.length
2157
2207
  });
2208
+ };
2209
+ const unregisterTurnSync = session ? hooks.hook("turn:after", persistPendingTurns) : void 0;
2210
+ const unregisterToolResultsSync = session ? hooks.hook("tool-results:after", persistPendingTurns) : void 0;
2211
+ async function flushTurns(opts = {}) {
2212
+ if (!session) return;
2213
+ if (opts.failureFallback) synthesizeMissingToolResults(turns, await session.generateTurnId?.() ?? crypto.randomUUID(), runId, provider);
2214
+ const remaining = turns.slice(lastPersistedTurnCount);
2215
+ if (remaining.length > 0) {
2216
+ await session.appendTurns(remaining);
2217
+ lastPersistedTurnCount = turns.length;
2218
+ await hooks.callHook("session:turns", {
2219
+ sessionId: session.id,
2220
+ turns: remaining,
2221
+ count: turns.length
2222
+ });
2223
+ }
2158
2224
  }
2159
- }
2160
- async function deactivateAllSkills() {
2161
- for (const record of skillActivationState.clear()) await hooks.callHook("skills:deactivate", {
2162
- skill: record.skill,
2163
- reason: "run-end"
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;
2225
+ async function deactivateAllSkills() {
2226
+ for (const record of skillActivationState.clear()) await hooks.callHook("skills:deactivate", {
2227
+ skill: record.skill,
2228
+ reason: "run-end"
2229
+ });
2238
2230
  }
2239
- const cumulativeCost = parentTurnCost + childrenCost;
2240
- const finalStats = {
2241
- ...stats,
2242
- totalIn: stats.totalIn + childrenIn,
2243
- totalOut: stats.totalOut + childrenOut,
2244
- totalCacheRead: stats.totalCacheRead + childrenCacheRead,
2245
- totalCacheCreation: stats.totalCacheCreation + childrenCacheCreation,
2246
- ...cumulativeCost > 0 ? { cost: cumulativeCost } : {},
2247
- children: childrenStats.length > 0 ? childrenStats : void 0
2248
- };
2249
- await flushTurns();
2250
- if (abortController.signal.aborted) {
2251
- session?.abortRun(runId);
2252
- await finalizeSession("aborted");
2253
- await hooks.callHook("agent:done", finalStats);
2254
- return finalStats;
2231
+ async function finalizeSession(status) {
2232
+ if (!session) return;
2233
+ const run = session.runs.find((r) => r.id === runId);
2234
+ if (run) await session.updateRun(run);
2235
+ await session.updateStatus(status === "aborted" ? "idle" : status);
2236
+ await hooks.callHook("session:end", {
2237
+ sessionId: session.id,
2238
+ runId,
2239
+ status,
2240
+ turnRange: [runTurnStart, turns.length - 1]
2241
+ });
2255
2242
  }
2256
- session?.completeRun(runId, {
2257
- turns: stats.turns,
2258
- tokensIn: stats.totalIn,
2259
- tokensOut: stats.totalOut,
2260
- turnUsage: stats.turnUsage,
2261
- cost: parentTurnCost > 0 ? parentTurnCost : void 0
2262
- });
2263
- await finalizeSession("completed");
2264
- await hooks.callHook("agent:done", finalStats);
2265
- return finalStats;
2266
- } catch (err) {
2267
- await flushTurns();
2268
- if (abortController.signal.aborted) {
2269
- session?.abortRun(runId);
2270
- await finalizeSession("aborted");
2271
- const stats = {
2272
- totalIn: 0,
2273
- totalOut: 0,
2274
- totalCacheRead: 0,
2275
- totalCacheCreation: 0,
2276
- turns: 0,
2277
- elapsed: 0
2243
+ const uninstallAllowedToolsGate = installAllowedToolsGate(hooks, skillActivationState);
2244
+ const uninstallToolBudgets = installToolBudgetsGate(hooks, () => toolBudgets, (msg) => steeringQueue.push(msg));
2245
+ const uninstallDedupTools = installDedupToolsGate(hooks, () => dedupTools, () => session ?? void 0);
2246
+ const uninstallLazyDisclosureGate = installLazyDisclosureGate(hooks, disclosure.lazyCanonicalNames, unlocked, discoveryToolName);
2247
+ const runStartMs = Date.now();
2248
+ const runDepth = typeof options.depth === "number" ? options.depth : 0;
2249
+ try {
2250
+ const stats = await runLoop({
2251
+ provider,
2252
+ hooks,
2253
+ agentName,
2254
+ agentSystem,
2255
+ agentTools: sourceTools,
2256
+ agentToolAliases: toolAliases,
2257
+ agentMcpServers: mcpServers,
2258
+ agentSkills,
2259
+ agentBehavior: resolvedBehavior,
2260
+ tools,
2261
+ formattedTools,
2262
+ rebuildFormattedTools: disclosure.lazyEntries.length > 0 ? buildFormattedTools : void 0,
2263
+ aliasMaps,
2264
+ model,
2265
+ system,
2266
+ thinking,
2267
+ toolExecution,
2268
+ signal: abortController.signal,
2269
+ execution: executionContext,
2270
+ handle: executionHandle,
2271
+ steeringQueue,
2272
+ followUpQueue,
2273
+ turns,
2274
+ runId,
2275
+ generateTurnId: () => session?.generateTurnId() ?? crypto.randomUUID(),
2276
+ maxTurns,
2277
+ maxTokens,
2278
+ ...session ? { session } : {},
2279
+ depth: runDepth,
2280
+ thinkingBudget,
2281
+ schema,
2282
+ cache,
2283
+ toolOutputBudget,
2284
+ compactStrategy,
2285
+ compactThreshold,
2286
+ compactKeepTurns,
2287
+ ...elideStaleReads !== void 0 ? { elideStaleReads } : {},
2288
+ ...thinkingDecay !== void 0 ? { thinkingDecay } : {},
2289
+ runStartMs,
2290
+ runToolCounts: {}
2291
+ });
2292
+ const parentTurnCost = stats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0) ?? 0;
2293
+ let childrenIn = 0;
2294
+ let childrenOut = 0;
2295
+ let childrenCost = 0;
2296
+ let childrenCacheRead = 0;
2297
+ let childrenCacheCreation = 0;
2298
+ for (const c of childrenStats) {
2299
+ childrenIn += c.stats.totalIn;
2300
+ childrenOut += c.stats.totalOut;
2301
+ childrenCost += c.stats.cost ?? 0;
2302
+ childrenCacheRead += c.stats.totalCacheRead;
2303
+ childrenCacheCreation += c.stats.totalCacheCreation;
2304
+ }
2305
+ const cumulativeCost = parentTurnCost + childrenCost;
2306
+ const finalStats = {
2307
+ ...stats,
2308
+ totalIn: stats.totalIn + childrenIn,
2309
+ totalOut: stats.totalOut + childrenOut,
2310
+ totalCacheRead: stats.totalCacheRead + childrenCacheRead,
2311
+ totalCacheCreation: stats.totalCacheCreation + childrenCacheCreation,
2312
+ ...cumulativeCost > 0 ? { cost: cumulativeCost } : {},
2313
+ children: childrenStats.length > 0 ? childrenStats : void 0
2278
2314
  };
2279
- await hooks.callHook("agent:done", stats);
2280
- return stats;
2315
+ await flushTurns();
2316
+ if (abortController.signal.aborted) {
2317
+ session?.abortRun(runId, {
2318
+ turns: stats.turns,
2319
+ tokensIn: stats.totalIn,
2320
+ tokensOut: stats.totalOut,
2321
+ turnUsage: stats.turnUsage,
2322
+ cost: parentTurnCost > 0 ? parentTurnCost : void 0
2323
+ });
2324
+ await finalizeSession("aborted");
2325
+ await hooks.callHook("agent:done", finalStats);
2326
+ return finalStats;
2327
+ }
2328
+ session?.completeRun(runId, {
2329
+ turns: stats.turns,
2330
+ tokensIn: stats.totalIn,
2331
+ tokensOut: stats.totalOut,
2332
+ turnUsage: stats.turnUsage,
2333
+ cost: parentTurnCost > 0 ? parentTurnCost : void 0
2334
+ });
2335
+ await finalizeSession("completed");
2336
+ await hooks.callHook("agent:done", finalStats);
2337
+ return finalStats;
2338
+ } catch (err) {
2339
+ await flushTurns({ failureFallback: true });
2340
+ if (abortController.signal.aborted) {
2341
+ session?.abortRun(runId);
2342
+ await finalizeSession("aborted");
2343
+ const stats = {
2344
+ totalIn: 0,
2345
+ totalOut: 0,
2346
+ totalCacheRead: 0,
2347
+ totalCacheCreation: 0,
2348
+ turns: 0,
2349
+ elapsed: 0
2350
+ };
2351
+ await hooks.callHook("agent:done", stats);
2352
+ return stats;
2353
+ }
2354
+ const message = err instanceof Error ? err.message : String(err);
2355
+ session?.errorRun(runId, message);
2356
+ await finalizeSession("error");
2357
+ throw err;
2358
+ } finally {
2359
+ await deactivateAllSkills();
2360
+ uninstallAllowedToolsGate();
2361
+ uninstallDedupTools();
2362
+ uninstallToolBudgets();
2363
+ uninstallLazyDisclosureGate();
2364
+ unregisterSpawnHook();
2365
+ unregisterTurnSync?.();
2366
+ unregisterToolResultsSync?.();
2367
+ for (const unregister of perRunUnregisters) unregister();
2368
+ running = false;
2369
+ abortController = void 0;
2370
+ steeringQueue.length = 0;
2371
+ followUpQueue.length = 0;
2372
+ idleResolve?.();
2373
+ idlePromise = void 0;
2374
+ idleResolve = void 0;
2281
2375
  }
2282
- const message = err instanceof Error ? err.message : String(err);
2283
- session?.errorRun(runId, message);
2284
- await finalizeSession("error");
2285
- throw err;
2286
2376
  } finally {
2287
- await deactivateAllSkills();
2288
- uninstallAllowedToolsGate();
2289
- uninstallDedupTools();
2290
- uninstallToolBudgets();
2291
- uninstallLazyDisclosureGate();
2292
- unregisterSpawnHook();
2293
- unregisterSessionSync?.();
2294
- for (const unregister of perRunUnregisters) unregister();
2295
2377
  running = false;
2296
2378
  abortController = void 0;
2297
- steeringQueue.length = 0;
2298
- followUpQueue.length = 0;
2299
2379
  idleResolve?.();
2300
2380
  idlePromise = void 0;
2301
2381
  idleResolve = void 0;
2382
+ if (externalSignal && externalAbortListener) externalSignal.removeEventListener("abort", externalAbortListener);
2302
2383
  }
2303
2384
  }
2304
2385
  function abort() {
@@ -3701,17 +3782,33 @@ var SpawnTimeoutError = class extends Error {
3701
3782
  * Called before `agent.run()` starts, torn down in a finally block — so
3702
3783
  * nothing leaks even if the child throws mid-run.
3703
3784
  */
3785
+ /**
3786
+ * Surface a thrown observational-bubble listener without killing the
3787
+ * process. Observational events (`child:stream:text`, `child:tool:after`,
3788
+ * `child:turn:after`, …) are fire-and-forget — a rejected promise here
3789
+ * has no caller. Without this handler, a buggy parent listener bubbles
3790
+ * up to an unhandled-rejection, and Node/Bun under
3791
+ * `--unhandled-rejections=strict` terminates the host.
3792
+ *
3793
+ * Gated on `ZIDANE_DEBUG` so production logs stay quiet; debug builds
3794
+ * still get the tagged line.
3795
+ */
3796
+ function swallowBubbleError(eventName, err) {
3797
+ if (!process.env.ZIDANE_DEBUG) return;
3798
+ const message = err instanceof Error ? err.stack ?? err.message : String(err);
3799
+ process.stderr.write(`[zidane/spawn] parent listener for "${eventName}" rejected: ${message}\n`);
3800
+ }
3704
3801
  function bubbleHooks(childHooks, parentHooks, childId, depth) {
3705
3802
  const unregisters = [];
3706
3803
  const fire = parentHooks.callHook;
3707
3804
  for (const evt of BUBBLED_EVENTS) {
3708
3805
  const parentEvt = CHILD_EVENT_NAME[evt];
3709
3806
  const unregister = childHooks.hook(evt, (ctx) => {
3710
- fire(parentEvt, {
3807
+ Promise.resolve(fire(parentEvt, {
3711
3808
  ...ctx,
3712
3809
  childId,
3713
3810
  depth
3714
- });
3811
+ })).catch((err) => swallowBubbleError(parentEvt, err));
3715
3812
  });
3716
3813
  unregisters.push(unregister);
3717
3814
  }
@@ -3731,7 +3828,7 @@ function bubbleHooks(childHooks, parentHooks, childId, depth) {
3731
3828
  for (const evt of BUBBLED_EVENTS) {
3732
3829
  const parentEvt = CHILD_EVENT_NAME[evt];
3733
3830
  unregisters.push(chainHook(parentEvt, (ctx) => {
3734
- fire(parentEvt, ctx);
3831
+ Promise.resolve(fire(parentEvt, ctx)).catch((err) => swallowBubbleError(parentEvt, err));
3735
3832
  }));
3736
3833
  }
3737
3834
  for (const evt of BUBBLED_GATE_EVENTS) {
@@ -3988,4 +4085,4 @@ const writeFile$1 = {
3988
4085
  //#endregion
3989
4086
  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
4087
 
3991
- //# sourceMappingURL=tools-C8kDot0H.js.map
4088
+ //# sourceMappingURL=tools-BdQENveS.js.map