zidane 5.3.2 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -1
- package/dist/{agent-BXRCCHeq.d.ts → agent-DHQAsdj6.d.ts} +47 -15
- package/dist/agent-DHQAsdj6.d.ts.map +1 -0
- package/dist/chat.d.ts +4 -4
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +1 -1
- package/dist/{index-CT5_p-3P.d.ts → index-CHSaLab5.d.ts} +2 -2
- package/dist/{index-CT5_p-3P.d.ts.map → index-CHSaLab5.d.ts.map} +1 -1
- package/dist/{index-BPk8-Slm.d.ts → index-CrqFoaQA.d.ts} +12 -11
- package/dist/index-CrqFoaQA.d.ts.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/{login-DrBZ15G7.js → login-bK0EP8La.js} +2 -2
- package/dist/{login-DrBZ15G7.js.map → login-bK0EP8La.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{presets-0_IRJAYF.js → presets-M8f6lDnW.js} +2 -2
- package/dist/{presets-0_IRJAYF.js.map → presets-M8f6lDnW.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/{tools-CCsL5SCO.js → tools-DKdyPoUf.js} +279 -63
- package/dist/tools-DKdyPoUf.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-DSk8LlWt.d.ts → transcript-anchors-Fgh_rZ04.d.ts} +3 -3
- package/dist/{transcript-anchors-DSk8LlWt.d.ts.map → transcript-anchors-Fgh_rZ04.d.ts.map} +1 -1
- package/dist/tui.d.ts +2 -2
- package/dist/tui.js +3 -3
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CutZin8X.js → turn-operations-DDokWR8p.js} +4 -3
- package/dist/turn-operations-DDokWR8p.js.map +1 -0
- package/dist/types-IcokUOyC.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/docs/ARCHITECTURE.md +17 -6
- package/docs/SKILL.md +33 -2
- package/package.json +1 -1
- package/dist/agent-BXRCCHeq.d.ts.map +0 -1
- package/dist/index-BPk8-Slm.d.ts.map +0 -1
- package/dist/tools-CCsL5SCO.js.map +0 -1
- package/dist/turn-operations-CutZin8X.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets-
|
|
1
|
+
{"version":3,"file":"presets-M8f6lDnW.js","names":[],"sources":["../src/presets/basic.ts","../src/presets/index.ts"],"sourcesContent":["import { definePreset } from '.'\nimport { edit, listFiles, multiEdit, readFile, shell, writeFile } from '../tools'\nimport { createSpawnTool } from '../tools/spawn'\n\n/**\n * Core tools available in every basic preset (without spawn).\n *\n * `edit` and `multi_edit` ship in the basic set because surgical edits are the\n * default modality for production agents — `write_file` is for full overwrites.\n * `glob` and `grep` are exported but opt-in: not every agent needs codebase\n * search, and shipping them by default would force `tool:gate` work onto\n * consumers that prefer the model to use `shell` + classic Unix tools.\n */\nexport const basicTools = { shell, readFile, writeFile, listFiles, edit, multiEdit }\n\nexport default definePreset({\n name: 'basic',\n system: 'You are a helpful assistant with access to shell, file reading, file writing, surgical and multi-edit tools, directory listing, and sub-agent spawning. Prefer `edit` / `multi_edit` for in-place changes and `write_file` for full file overwrites. Use them to accomplish tasks in the project directory.',\n // `persist: true` shares the parent's session with every child agent — child\n // turns land in `session.turns` tagged with their own `runId`, and the run\n // itself is recorded in `session.runs` with `parentRunId` + `depth`. That's\n // what lets a reloaded TUI session reconstruct the full subagent tree (see\n // `eventsFromTurns` in `tui/store.ts`). Hosts that want children in-memory\n // only can construct their own preset with `createSpawnTool()`.\n tools: { ...basicTools, spawn: createSpawnTool({ persist: true }) },\n})\n","import type { AgentHooks, AgentOptions } from '../agent'\n\nexport type { AgentHookMap } from '../agent'\n\n/**\n * A preset is a reusable slice of `AgentOptions` — spread it into `createAgent()`\n * to configure tools, a default system prompt, aliases, behavior defaults, and\n * agent-lifetime hooks.\n *\n * `provider`, `execution`, `session`, and internal fields are excluded so presets\n * remain shareable and composable.\n *\n * ```ts\n * import { basic } from 'zidane/presets'\n * createAgent({ ...basic, provider })\n * ```\n *\n * ### Composing multiple presets\n *\n * Bare `...spread` is shallow — `{ ...a, ...b }` overwrites every key `b`\n * defines, including `hooks`. Use {@link composePresets} when you want\n * field-aware merging (per-event hook concat, tools shallow-merge, etc.):\n *\n * ```ts\n * createAgent({ ...composePresets(basic, telemetry, mine), provider })\n * ```\n */\nexport type Preset = Omit<Partial<AgentOptions>, 'provider' | 'execution' | 'session' | 'mcpConnector'>\n\n/**\n * Identity helper for type inference when defining a preset.\n */\nexport function definePreset(config: Preset): Preset {\n return config\n}\n\n/**\n * Field-aware composition of presets. Right-most preset wins for scalar fields;\n * objects shallow-merge; arrays and hook handler lists concatenate. Designed so\n * stacking presets does the obvious thing without the spread-collision footgun:\n *\n * - `name`, `system`, `eager`, `skills` → last-defined wins\n * - `tools`, `toolAliases`, `behavior` → shallow-merge (later keys override)\n * - `behavior.dedupTools`, `behavior.toolBudgets` → **deep-merge** (per-tool-name; later wins on collision)\n * - `mcpServers` → concat with last-wins on `name` collision\n * - `hooks` → per-event concat; every handler fires\n *\n * `hooks` always emerges as `event → handler[]` so downstream registration\n * (in `createAgent`) sees a uniform shape. Order of handlers within an event\n * follows preset order: earlier presets register first.\n *\n * `mcpServers` is deduped by `name` because shipping two servers with the same\n * name would trip the connector at runtime — a later preset overriding an\n * earlier preset's `github` server is the practical intent.\n *\n * `behavior.dedupTools` and `behavior.toolBudgets` get the same per-key deep-merge\n * because they are tool-name-keyed records — a preset that ships a dedup hasher\n * for one tool should not erase a hasher another preset ships for a different\n * tool. Last-wins still applies on a per-tool collision so a downstream preset\n * can override an upstream preset's policy for one specific tool. Other\n * `behavior` fields keep last-wins semantics.\n */\nexport function composePresets(...presets: Preset[]): Preset {\n const out: Preset = {}\n const hooksByEvent: { [K in keyof AgentHooks]?: AgentHooks[K][] } = {}\n // Keep mcpServers in source-order on first sight, but allow later\n // declarations to override earlier ones with the same `name`. A `Map`\n // keyed by name gives O(1) override + stable iteration.\n const mcpByName = new Map<string, NonNullable<Preset['mcpServers']>[number]>()\n\n for (const p of presets) {\n if (p.name !== undefined)\n out.name = p.name\n if (p.system !== undefined)\n out.system = p.system\n if (p.eager !== undefined)\n out.eager = p.eager\n if (p.skills !== undefined)\n out.skills = p.skills\n if (p.tools)\n out.tools = { ...out.tools, ...p.tools }\n if (p.toolAliases)\n out.toolAliases = { ...out.toolAliases, ...p.toolAliases }\n if (p.behavior) {\n // Top-level shallow-merge first; then deep-merge the two tool-name-keyed\n // sub-records so per-tool entries from earlier presets aren't clobbered.\n const merged: NonNullable<Preset['behavior']> = { ...out.behavior, ...p.behavior }\n if (out.behavior?.dedupTools || p.behavior.dedupTools) {\n merged.dedupTools = { ...out.behavior?.dedupTools, ...p.behavior.dedupTools }\n }\n if (out.behavior?.toolBudgets || p.behavior.toolBudgets) {\n merged.toolBudgets = { ...out.behavior?.toolBudgets, ...p.behavior.toolBudgets }\n }\n out.behavior = merged\n }\n if (p.mcpServers) {\n for (const server of p.mcpServers)\n mcpByName.set(server.name, server)\n }\n if (p.hooks) {\n for (const [event, handler] of Object.entries(p.hooks)) {\n if (handler === undefined)\n continue\n const list = Array.isArray(handler) ? handler : [handler]\n const key = event as keyof AgentHooks\n // Safe cast: we read the loose `AgentHookMap` shape (handler-or-array)\n // and re-emit only as arrays. Each `list` element matches the event's\n // handler signature by construction (the input was typed `AgentHookMap`).\n const bucket = (hooksByEvent[key] ??= []) as unknown[]\n bucket.push(...(list as unknown[]))\n }\n }\n }\n\n if (mcpByName.size > 0)\n out.mcpServers = [...mcpByName.values()]\n\n if (Object.keys(hooksByEvent).length > 0)\n out.hooks = hooksByEvent\n\n return out\n}\n\nexport { default as basic, basicTools } from './basic'\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,aAAa;CAAE;CAAO;CAAU;CAAW;CAAW;CAAM;CAAW;AAEpF,IAAA,gBAAe,aAAa;CAC1B,MAAM;CACN,QAAQ;CAOR,OAAO;EAAE,GAAG;EAAY,OAAO,gBAAgB,EAAE,SAAS,MAAM,CAAC;EAAE;CACpE,CAAC;;;;;;ACOF,SAAgB,aAAa,QAAwB;CACnD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BT,SAAgB,eAAe,GAAG,SAA2B;CAC3D,MAAM,MAAc,EAAE;CACtB,MAAM,eAA8D,EAAE;CAItE,MAAM,4BAAY,IAAI,KAAwD;CAE9E,KAAK,MAAM,KAAK,SAAS;EACvB,IAAI,EAAE,SAAS,KAAA,GACb,IAAI,OAAO,EAAE;EACf,IAAI,EAAE,WAAW,KAAA,GACf,IAAI,SAAS,EAAE;EACjB,IAAI,EAAE,UAAU,KAAA,GACd,IAAI,QAAQ,EAAE;EAChB,IAAI,EAAE,WAAW,KAAA,GACf,IAAI,SAAS,EAAE;EACjB,IAAI,EAAE,OACJ,IAAI,QAAQ;GAAE,GAAG,IAAI;GAAO,GAAG,EAAE;GAAO;EAC1C,IAAI,EAAE,aACJ,IAAI,cAAc;GAAE,GAAG,IAAI;GAAa,GAAG,EAAE;GAAa;EAC5D,IAAI,EAAE,UAAU;GAGd,MAAM,SAA0C;IAAE,GAAG,IAAI;IAAU,GAAG,EAAE;IAAU;GAClF,IAAI,IAAI,UAAU,cAAc,EAAE,SAAS,YACzC,OAAO,aAAa;IAAE,GAAG,IAAI,UAAU;IAAY,GAAG,EAAE,SAAS;IAAY;GAE/E,IAAI,IAAI,UAAU,eAAe,EAAE,SAAS,aAC1C,OAAO,cAAc;IAAE,GAAG,IAAI,UAAU;IAAa,GAAG,EAAE,SAAS;IAAa;GAElF,IAAI,WAAW;;EAEjB,IAAI,EAAE,YACJ,KAAK,MAAM,UAAU,EAAE,YACrB,UAAU,IAAI,OAAO,MAAM,OAAO;EAEtC,IAAI,EAAE,OACJ,KAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,EAAE,MAAM,EAAE;GACtD,IAAI,YAAY,KAAA,GACd;GACF,MAAM,OAAO,MAAM,QAAQ,QAAQ,GAAG,UAAU,CAAC,QAAQ;GACzD,MAAM,MAAM;GAKZ,CADgB,aAAa,SAAS,EAAE,EACjC,KAAK,GAAI,KAAmB;;;CAKzC,IAAI,UAAU,OAAO,GACnB,IAAI,aAAa,CAAC,GAAG,UAAU,QAAQ,CAAC;CAE1C,IAAI,OAAO,KAAK,aAAa,CAAC,SAAS,GACrC,IAAI,QAAQ;CAEd,OAAO"}
|
package/dist/presets.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as AgentHookMap } from "./agent-
|
|
2
|
-
import { a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-
|
|
1
|
+
import { n as AgentHookMap } from "./agent-DHQAsdj6.js";
|
|
2
|
+
import { a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-CrqFoaQA.js";
|
|
3
3
|
export { AgentHookMap, Preset, _default as basic, basicTools, composePresets, definePreset };
|
package/dist/presets.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as basic_default, n as definePreset, r as basicTools, t as composePresets } from "./presets-
|
|
1
|
+
import { i as basic_default, n as definePreset, r as basicTools, t as composePresets } from "./presets-M8f6lDnW.js";
|
|
2
2
|
export { basic_default as basic, basicTools, composePresets, definePreset };
|
package/dist/providers.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { At as cerebras, Ct as OpenAICompatParams, Dt as OpenAIParams, Et as openaiCompat, Mt as anthropic, Ot as openai, St as OpenAICompatHttpError, Tt as mapOAIFinishReason, _t as sanitizeToolSchema, bt as openrouter, ct as StreamCallbacks, dt as ToolResult, ft as ToolSpec, gt as SchemaSanitizeResult, ht as SchemaSanitizeProfile, jt as AnthropicParams, kt as CerebrasParams, lt as StreamOptions, mt as SchemaSanitizeOptions, ot as Provider, pt as TurnResult, st as ProviderCapabilities, ut as ToolCall, vt as sanitizeToolSpecs, wt as classifyOpenAICompatError, xt as OpenAICompatAuthHeader, yt as OpenRouterParams } from "./agent-
|
|
1
|
+
import { At as cerebras, Ct as OpenAICompatParams, Dt as OpenAIParams, Et as openaiCompat, Mt as anthropic, Ot as openai, St as OpenAICompatHttpError, Tt as mapOAIFinishReason, _t as sanitizeToolSchema, bt as openrouter, ct as StreamCallbacks, dt as ToolResult, ft as ToolSpec, gt as SchemaSanitizeResult, ht as SchemaSanitizeProfile, jt as AnthropicParams, kt as CerebrasParams, lt as StreamOptions, mt as SchemaSanitizeOptions, ot as Provider, pt as TurnResult, st as ProviderCapabilities, ut as ToolCall, vt as sanitizeToolSpecs, wt as classifyOpenAICompatError, xt as OpenAICompatAuthHeader, yt as OpenRouterParams } from "./agent-DHQAsdj6.js";
|
|
2
2
|
export { AnthropicParams, CerebrasParams, OpenAICompatAuthHeader, OpenAICompatHttpError, OpenAICompatParams, OpenAIParams, OpenRouterParams, Provider, ProviderCapabilities, SchemaSanitizeOptions, SchemaSanitizeProfile, SchemaSanitizeResult, StreamCallbacks, StreamOptions, ToolCall, ToolResult, ToolSpec, TurnResult, anthropic, cerebras, classifyOpenAICompatError, mapOAIFinishReason, openai, openaiCompat, openrouter, sanitizeToolSchema, sanitizeToolSpecs };
|
package/dist/session/sqlite.d.ts
CHANGED
package/dist/session.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as fromOpenAI, B as createRemoteStore, F as SessionRun, I as SessionStore, J as autoDetectAndConvert, Kt as SessionContentBlock, L as createSession, M as CreateSessionOptions, N as Session, P as SessionData, Q as fromAnthropic, R as loadSession, Xt as SessionTurn, Yt as SessionMessage, at as createFileMapStore, et as toAnthropic, it as FileMapStoreOptions, nt as createMemoryStore, rt as FileMapAdapter, tt as toOpenAI, z as RemoteStoreOptions } from "./agent-
|
|
1
|
+
import { $ as fromOpenAI, B as createRemoteStore, F as SessionRun, I as SessionStore, J as autoDetectAndConvert, Kt as SessionContentBlock, L as createSession, M as CreateSessionOptions, N as Session, P as SessionData, Q as fromAnthropic, R as loadSession, Xt as SessionTurn, Yt as SessionMessage, at as createFileMapStore, et as toAnthropic, it as FileMapStoreOptions, nt as createMemoryStore, rt as FileMapAdapter, tt as toOpenAI, z as RemoteStoreOptions } from "./agent-DHQAsdj6.js";
|
|
2
2
|
export { CreateSessionOptions, FileMapAdapter, FileMapStoreOptions, RemoteStoreOptions, Session, SessionContentBlock, SessionData, SessionMessage, SessionRun, SessionStore, SessionTurn, autoDetectAndConvert, createFileMapStore, createMemoryStore, createRemoteStore, createSession, fromAnthropic, fromOpenAI, loadSession, toAnthropic, toOpenAI };
|
package/dist/skills.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as SkillSource, D as SkillConfig, O as SkillDiagnostic, c as DeactivationReason, d as createSkillActivationState, j as SkillsConfig, k as SkillResource, l as SkillActivationState, o as ActivationVia, s as ActiveSkill, u as SkillActivationStateOptions } from "./agent-
|
|
2
|
-
import { S as installAllowedToolsGate, _ as inferSource, a as SkillValidationResult, b as buildCatalog, c as parseAllowedToolPattern, d as validateSkillName, f as resolveSkills, g as getDefaultScanPaths, h as discoverSkills, i as SkillValidationIssue, l as validateResourcePath, m as SourcedScanPath, n as writeSkillToDisk, o as isToolAllowedByUnion, p as interpolateShellCommands, r as writeSkillsToDisk, s as matchesAllowedTool, t as defineSkill, u as validateSkillForWrite, v as parseFrontmatter, x as IMPLICITLY_ALLOWED_SKILL_TOOLS, y as parseSkillFile } from "./index-
|
|
1
|
+
import { A as SkillSource, D as SkillConfig, O as SkillDiagnostic, c as DeactivationReason, d as createSkillActivationState, j as SkillsConfig, k as SkillResource, l as SkillActivationState, o as ActivationVia, s as ActiveSkill, u as SkillActivationStateOptions } from "./agent-DHQAsdj6.js";
|
|
2
|
+
import { S as installAllowedToolsGate, _ as inferSource, a as SkillValidationResult, b as buildCatalog, c as parseAllowedToolPattern, d as validateSkillName, f as resolveSkills, g as getDefaultScanPaths, h as discoverSkills, i as SkillValidationIssue, l as validateResourcePath, m as SourcedScanPath, n as writeSkillToDisk, o as isToolAllowedByUnion, p as interpolateShellCommands, r as writeSkillsToDisk, s as matchesAllowedTool, t as defineSkill, u as validateSkillForWrite, v as parseFrontmatter, x as IMPLICITLY_ALLOWED_SKILL_TOOLS, y as parseSkillFile } from "./index-CHSaLab5.js";
|
|
3
3
|
export { ActivationVia, ActiveSkill, DeactivationReason, IMPLICITLY_ALLOWED_SKILL_TOOLS, SkillActivationState, SkillActivationStateOptions, SkillConfig, SkillDiagnostic, SkillResource, SkillSource, SkillValidationIssue, SkillValidationResult, SkillsConfig, SourcedScanPath, buildCatalog, createSkillActivationState, defineSkill, discoverSkills, getDefaultScanPaths, inferSource, installAllowedToolsGate, interpolateShellCommands, isToolAllowedByUnion, matchesAllowedTool, parseAllowedToolPattern, parseFrontmatter, parseSkillFile, resolveSkills, validateResourcePath, validateSkillForWrite, validateSkillName, writeSkillToDisk, writeSkillsToDisk };
|
|
@@ -805,20 +805,13 @@ const IMAGE_OMITTED_MARKER = "[image omitted — model does not support vision]"
|
|
|
805
805
|
const INTERRUPT_MESSAGE_FOR_TOOL_USE = "[Request interrupted by user for tool use]";
|
|
806
806
|
/**
|
|
807
807
|
* Canonical tool_result text emitted when a tool call is skipped because a
|
|
808
|
-
*
|
|
809
|
-
*
|
|
810
|
-
* {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} so consumers can
|
|
808
|
+
* steering message arrived between dispatches inside
|
|
809
|
+
* {@link executeToolBatch}. Distinguished from
|
|
810
|
+
* {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} so consumers can split "user
|
|
811
811
|
* cancelled" from "framework superseded".
|
|
812
812
|
*/
|
|
813
813
|
const TOOL_USE_SKIPPED_MESSAGE = "[Tool use skipped — superseded by user message]";
|
|
814
814
|
/**
|
|
815
|
-
* Canonical tool_result text emitted when the loop catches a sequential
|
|
816
|
-
* sibling that threw and synthesizes follow-up results for the remaining
|
|
817
|
-
* queued calls. Distinct from {@link TOOL_USE_SKIPPED_MESSAGE} so telemetry
|
|
818
|
-
* can split "skipped by user steering" from "skipped after error".
|
|
819
|
-
*/
|
|
820
|
-
const TOOL_USE_AFTER_ERROR_MESSAGE = "[Tool use skipped — previous tool call in batch threw]";
|
|
821
|
-
/**
|
|
822
815
|
* Compute the effective thinking budget for a given run-relative turn, given
|
|
823
816
|
* the configured decay schedule. Pure helper — exported for tests and so
|
|
824
817
|
* downstream tooling can preview decay curves without spinning up the loop.
|
|
@@ -1518,7 +1511,7 @@ async function executeTurn(ctx, turn) {
|
|
|
1518
1511
|
usage: result.usage
|
|
1519
1512
|
};
|
|
1520
1513
|
}
|
|
1521
|
-
const toolResults =
|
|
1514
|
+
const toolResults = await executeToolBatch(ctx, canonicalToolCalls, turnId);
|
|
1522
1515
|
const toolResultMsg = ctx.provider.toolResultsMessage(toolResults);
|
|
1523
1516
|
const toolResultsTurn = {
|
|
1524
1517
|
id: await ctx.generateTurnId(),
|
|
@@ -1859,57 +1852,170 @@ async function emitToolResult(ctx, params) {
|
|
|
1859
1852
|
isError
|
|
1860
1853
|
};
|
|
1861
1854
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1855
|
+
/** Default cap on in-flight tools per turn. Mirrors Claude Code's `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY`. */
|
|
1856
|
+
const DEFAULT_MAX_CONCURRENT_TOOLS = 10;
|
|
1857
|
+
/** Canonical name of the shell tool — referenced for cascade-cancel semantics. */
|
|
1858
|
+
const SHELL_TOOL_NAME = "shell";
|
|
1859
|
+
/** Reason surfaced on `siblingAbort.signal` when a shell error cancels its fleet. */
|
|
1860
|
+
const SHELL_CASCADE_REASON = "sibling-shell-error";
|
|
1861
|
+
/**
|
|
1862
|
+
* Canonical `tool_result.content` text emitted to siblings that were
|
|
1863
|
+
* cancelled by a `shell` error in the same batch. Distinct from
|
|
1864
|
+
* {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (user-issued abort) and
|
|
1865
|
+
* {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so consumers can split
|
|
1866
|
+
* the three causes by string-match.
|
|
1867
|
+
*/
|
|
1868
|
+
const SHELL_CASCADE_CANCEL_MESSAGE = "Cancelled: a sibling `shell` call in the same batch errored; re-run independently if still needed.";
|
|
1869
|
+
/**
|
|
1870
|
+
* Resolve a tool's concurrency-safety verdict for a specific call.
|
|
1871
|
+
*
|
|
1872
|
+
* - Missing toolDef (unknown tool) → `false`. `executeSingleTool` handles
|
|
1873
|
+
* the unknown-tool path itself; barriering it keeps the unknown-tool
|
|
1874
|
+
* error from racing with siblings.
|
|
1875
|
+
* - Static `true` / `false` → use as-is.
|
|
1876
|
+
* - Function → invoke; any throw is treated as `false` (fail-closed) so a
|
|
1877
|
+
* buggy predicate can't accidentally widen the safety window.
|
|
1878
|
+
*
|
|
1879
|
+
* Pure / sync — pre-computed once per call before dispatch begins, so the
|
|
1880
|
+
* scheduler's hot path stays branch-light.
|
|
1881
|
+
*/
|
|
1882
|
+
function resolveConcurrencySafe(def, input) {
|
|
1883
|
+
if (!def) return false;
|
|
1884
|
+
const flag = def.isConcurrencySafe;
|
|
1885
|
+
if (flag === void 0) return false;
|
|
1886
|
+
if (typeof flag === "boolean") return flag;
|
|
1887
|
+
try {
|
|
1888
|
+
return flag(input) === true;
|
|
1889
|
+
} catch {
|
|
1890
|
+
return false;
|
|
1898
1891
|
}
|
|
1899
|
-
return results;
|
|
1900
1892
|
}
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1893
|
+
/**
|
|
1894
|
+
* Unified per-turn tool dispatcher.
|
|
1895
|
+
*
|
|
1896
|
+
* Walks `toolCalls` in submission order. For each call:
|
|
1897
|
+
*
|
|
1898
|
+
* - **Concurrency-safe + fleet is all safe + room under the cap** → fires
|
|
1899
|
+
* asynchronously and the loop advances to the next call. The fleet runs
|
|
1900
|
+
* in parallel up to `behavior.maxConcurrentTools` (default {@link
|
|
1901
|
+
* DEFAULT_MAX_CONCURRENT_TOOLS}).
|
|
1902
|
+
* - **Unsafe** (or the in-flight fleet contains anything unsafe) → acts
|
|
1903
|
+
* as a barrier: waits for the fleet to drain, then runs alone, then
|
|
1904
|
+
* unblocks the queue.
|
|
1905
|
+
*
|
|
1906
|
+
* Results are written into a fixed `results[index]` array on completion
|
|
1907
|
+
* and yielded back in submission order, so the model sees deterministic
|
|
1908
|
+
* adjacency regardless of which call finished first.
|
|
1909
|
+
*
|
|
1910
|
+
* **Failure modes:**
|
|
1911
|
+
*
|
|
1912
|
+
* - **Hook throws / tool body throws** — captured per-call into a
|
|
1913
|
+
* `tool_result` so the assistant turn's `tool_use` IDs always have
|
|
1914
|
+
* matching `tool_result` IDs (providers reject orphan IDs).
|
|
1915
|
+
* - **Parent abort** mid-batch — drains the in-flight fleet (their
|
|
1916
|
+
* `AbortError` becomes `INTERRUPT_MESSAGE_FOR_TOOL_USE`), then synthesizes
|
|
1917
|
+
* interrupt results for any unstarted calls so the turn closes cleanly.
|
|
1918
|
+
* - **Steering queue populated** between dispatches — same drain + a
|
|
1919
|
+
* `TOOL_USE_SKIPPED_MESSAGE` result for unstarted calls. The outer loop
|
|
1920
|
+
* picks up the steer at the next checkpoint.
|
|
1921
|
+
* - **Shell error in a fleet** — `siblingAbort.abort('sibling-shell-error')`
|
|
1922
|
+
* tears down concurrently-running siblings. Mirrors the convention that
|
|
1923
|
+
* shell commands often chain (`mkdir foo && cd foo`); one failing
|
|
1924
|
+
* sibling commonly invalidates the rest. Non-shell errors are isolated.
|
|
1925
|
+
*
|
|
1926
|
+
* A child `AbortController` (`siblingAbort`) forwards the parent abort
|
|
1927
|
+
* AND carries the shell-cascade signal — siblings see one signal source.
|
|
1928
|
+
*/
|
|
1929
|
+
async function executeToolBatch(ctx, toolCalls, turnId) {
|
|
1930
|
+
if (toolCalls.length === 0) return [];
|
|
1931
|
+
const N = toolCalls.length;
|
|
1932
|
+
const maxConcurrent = Math.max(1, ctx.maxConcurrentTools ?? DEFAULT_MAX_CONCURRENT_TOOLS);
|
|
1933
|
+
const results = Array.from({ length: N });
|
|
1934
|
+
const safe = Array.from({ length: N });
|
|
1935
|
+
for (let i = 0; i < N; i++) safe[i] = resolveConcurrencySafe(ctx.tools[toolCalls[i].name], toolCalls[i].input);
|
|
1936
|
+
const siblingAbort = new AbortController();
|
|
1937
|
+
let parentAbortListener;
|
|
1938
|
+
if (ctx.signal.aborted) siblingAbort.abort(ctx.signal.reason ?? "parent-aborted");
|
|
1939
|
+
else {
|
|
1940
|
+
parentAbortListener = () => siblingAbort.abort(ctx.signal.reason ?? "parent-aborted");
|
|
1941
|
+
ctx.signal.addEventListener("abort", parentAbortListener, { once: true });
|
|
1942
|
+
}
|
|
1943
|
+
const childCtx = {
|
|
1944
|
+
...ctx,
|
|
1945
|
+
signal: siblingAbort.signal
|
|
1946
|
+
};
|
|
1947
|
+
/** Indices currently in flight. Tracked for fleet-safety + cap checks. */
|
|
1948
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
1949
|
+
/**
|
|
1950
|
+
* Distinguish a shell-cascade kill from a user-issued abort so the
|
|
1951
|
+
* model sees actionable text. When BOTH the parent signal and the
|
|
1952
|
+
* sibling signal are aborted, the parent wins — user-issued aborts
|
|
1953
|
+
* take precedence (the model is being interrupted by the human, not
|
|
1954
|
+
* by a sibling's failure).
|
|
1955
|
+
*/
|
|
1956
|
+
const cancelMessage = () => {
|
|
1957
|
+
if (ctx.signal.aborted) return INTERRUPT_MESSAGE_FOR_TOOL_USE;
|
|
1958
|
+
if (siblingAbort.signal.reason === SHELL_CASCADE_REASON) return SHELL_CASCADE_CANCEL_MESSAGE;
|
|
1959
|
+
return INTERRUPT_MESSAGE_FOR_TOOL_USE;
|
|
1960
|
+
};
|
|
1961
|
+
const dispatch = (index) => {
|
|
1962
|
+
const call = toolCalls[index];
|
|
1963
|
+
return executeSingleTool(childCtx, call, turnId).then(({ result }) => {
|
|
1964
|
+
results[index] = result;
|
|
1965
|
+
if (result.isError && call.name === SHELL_TOOL_NAME && !siblingAbort.signal.aborted) siblingAbort.abort(SHELL_CASCADE_REASON);
|
|
1966
|
+
}, (err) => {
|
|
1967
|
+
const isAbort = siblingAbort.signal.aborted || ctx.signal.aborted || err instanceof Error && err.name === "AbortError";
|
|
1968
|
+
results[index] = {
|
|
1969
|
+
id: call.id,
|
|
1970
|
+
content: isAbort ? cancelMessage() : `Error: ${errorMessage(err)}`,
|
|
1971
|
+
isError: true
|
|
1972
|
+
};
|
|
1973
|
+
}).finally(() => {
|
|
1974
|
+
inFlight.delete(index);
|
|
1975
|
+
});
|
|
1976
|
+
};
|
|
1977
|
+
const drain = async () => {
|
|
1978
|
+
if (inFlight.size > 0) await Promise.all([...inFlight.values()]);
|
|
1979
|
+
};
|
|
1980
|
+
/** Whether every in-flight call is concurrency-safe. */
|
|
1981
|
+
const fleetAllSafe = () => {
|
|
1982
|
+
for (const idx of inFlight.keys()) if (!safe[idx]) return false;
|
|
1983
|
+
return true;
|
|
1984
|
+
};
|
|
1985
|
+
/**
|
|
1986
|
+
* Fill all unstarted slots (`results[j]` still undefined) with the
|
|
1987
|
+
* canonical text + `isError: true`. Used at every short-circuit
|
|
1988
|
+
* branch (abort / steer) so the assistant turn's `tool_use` IDs
|
|
1989
|
+
* always have matching `tool_result` IDs — providers reject orphan
|
|
1990
|
+
* IDs loudly.
|
|
1991
|
+
*/
|
|
1992
|
+
const fillUnstarted = (from, content) => {
|
|
1993
|
+
for (let j = from; j < N; j++) if (!results[j]) results[j] = {
|
|
1994
|
+
id: toolCalls[j].id,
|
|
1995
|
+
content,
|
|
1910
1996
|
isError: true
|
|
1911
1997
|
};
|
|
1912
|
-
}
|
|
1998
|
+
};
|
|
1999
|
+
try {
|
|
2000
|
+
for (let i = 0; i < N; i++) {
|
|
2001
|
+
if (!safe[i] || !fleetAllSafe() || inFlight.size >= maxConcurrent) await drain();
|
|
2002
|
+
if (ctx.signal.aborted) {
|
|
2003
|
+
await drain();
|
|
2004
|
+
fillUnstarted(i, INTERRUPT_MESSAGE_FOR_TOOL_USE);
|
|
2005
|
+
return results;
|
|
2006
|
+
}
|
|
2007
|
+
if (ctx.steeringQueue.length > 0) {
|
|
2008
|
+
await drain();
|
|
2009
|
+
fillUnstarted(i, TOOL_USE_SKIPPED_MESSAGE);
|
|
2010
|
+
return results;
|
|
2011
|
+
}
|
|
2012
|
+
inFlight.set(i, dispatch(i));
|
|
2013
|
+
}
|
|
2014
|
+
await drain();
|
|
2015
|
+
return results;
|
|
2016
|
+
} finally {
|
|
2017
|
+
if (parentAbortListener) ctx.signal.removeEventListener("abort", parentAbortListener);
|
|
2018
|
+
}
|
|
1913
2019
|
}
|
|
1914
2020
|
//#endregion
|
|
1915
2021
|
//#region src/prompt.ts
|
|
@@ -2129,6 +2235,7 @@ function looksBinary(text, sniffBytes = SNIFF_BYTES) {
|
|
|
2129
2235
|
function createSkillsReadTool(options) {
|
|
2130
2236
|
const byName = new Map(options.catalog.map((s) => [s.name, s]));
|
|
2131
2237
|
return {
|
|
2238
|
+
isConcurrencySafe: true,
|
|
2132
2239
|
spec: {
|
|
2133
2240
|
name: "skills_read",
|
|
2134
2241
|
description: "Read a bundled resource file from an active skill. The skill must have been activated via skills_use first. Path is relative to the skill's directory (e.g. \"references/REFERENCE.md\", \"assets/template.txt\").",
|
|
@@ -2392,6 +2499,7 @@ function createToolSearchTool(options) {
|
|
|
2392
2499
|
}
|
|
2393
2500
|
const maxLimit = Math.max(options.catalog.length, 1);
|
|
2394
2501
|
return {
|
|
2502
|
+
isConcurrencySafe: true,
|
|
2395
2503
|
spec: {
|
|
2396
2504
|
name: "tool_search",
|
|
2397
2505
|
description: "Discover and load schemas for additional tools listed in <searchable_tools>. Tools listed there are advertised by name + description only — their input schemas are not loaded into context until you surface them through this tool. Pass `query` for a substring search, `names` to load specific tools, or `server` to load every tool from one MCP server. Returned tools become callable for the rest of this run.",
|
|
@@ -2607,7 +2715,7 @@ async function synthesizeMissingToolResults(turns, syntheticTurnId, runId, provi
|
|
|
2607
2715
|
}
|
|
2608
2716
|
function resolveBehavior(agentBehavior, runBehavior) {
|
|
2609
2717
|
return {
|
|
2610
|
-
|
|
2718
|
+
maxConcurrentTools: runBehavior?.maxConcurrentTools ?? agentBehavior?.maxConcurrentTools,
|
|
2611
2719
|
maxTurns: runBehavior?.maxTurns ?? agentBehavior?.maxTurns,
|
|
2612
2720
|
maxTokens: runBehavior?.maxTokens ?? agentBehavior?.maxTokens,
|
|
2613
2721
|
thinkingBudget: runBehavior?.thinkingBudget ?? agentBehavior?.thinkingBudget,
|
|
@@ -2917,7 +3025,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2917
3025
|
const thinking = options.thinking ?? "off";
|
|
2918
3026
|
const model = options.model ?? provider.meta.defaultModel;
|
|
2919
3027
|
const resolvedBehavior = resolveBehavior(agentBehavior, options.behavior);
|
|
2920
|
-
const {
|
|
3028
|
+
const { maxConcurrentTools, maxTurns, maxTokens, thinkingBudget, schema, cache, toolOutputBudget, compactStrategy, compactThreshold, compactKeepTurns, thinkingDecay, dedupTools, toolBudgets, elideStaleReads, toolDisclosure, toolSearch, persistThreshold, persistExcludeTools, persistDir, strictToolPairing } = resolvedBehavior;
|
|
2921
3029
|
let system = options.system || agentSystem || "You are a helpful assistant.";
|
|
2922
3030
|
if (skillsCatalog) system = `${system}\n\n${skillsCatalog}`;
|
|
2923
3031
|
const runBaseTools = options.tools !== void 0 ? options.tools : mcpConnection ? {
|
|
@@ -3080,7 +3188,7 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
3080
3188
|
model,
|
|
3081
3189
|
system,
|
|
3082
3190
|
thinking,
|
|
3083
|
-
|
|
3191
|
+
...maxConcurrentTools !== void 0 ? { maxConcurrentTools } : {},
|
|
3084
3192
|
signal: abortController.signal,
|
|
3085
3193
|
execution: executionContext,
|
|
3086
3194
|
handle: executionHandle,
|
|
@@ -3760,6 +3868,7 @@ async function globViaShell(pattern, ctx, limit) {
|
|
|
3760
3868
|
return result.stdout.split("\n").filter((line) => line.length > 0);
|
|
3761
3869
|
}
|
|
3762
3870
|
const glob = {
|
|
3871
|
+
isConcurrencySafe: true,
|
|
3763
3872
|
spec: {
|
|
3764
3873
|
name: "glob",
|
|
3765
3874
|
description: "Match files by glob pattern (supports **, *, ?). Relative to the execution context cwd. By default each row is `<path>\\t<size-bytes>\\t<mtime-iso>`; set `metadata: false` for a plain newline-separated list of paths. Always sorted.",
|
|
@@ -3825,6 +3934,7 @@ const glob = {
|
|
|
3825
3934
|
const DEFAULT_HEAD_LIMIT = 250;
|
|
3826
3935
|
const DEFAULT_OUTPUT_MODE = "files_with_matches";
|
|
3827
3936
|
const grep = {
|
|
3937
|
+
isConcurrencySafe: true,
|
|
3828
3938
|
spec: {
|
|
3829
3939
|
name: "grep",
|
|
3830
3940
|
description: "Search file contents by regex. Returns matching paths (default), match content, or per-file counts. Backed by ripgrep when available with a Bun.Glob fallback for in-process runs.",
|
|
@@ -4060,6 +4170,7 @@ function createInteractionTool(options) {
|
|
|
4060
4170
|
//#endregion
|
|
4061
4171
|
//#region src/tools/list-files.ts
|
|
4062
4172
|
const listFiles = {
|
|
4173
|
+
isConcurrencySafe: true,
|
|
4063
4174
|
spec: {
|
|
4064
4175
|
name: "list_files",
|
|
4065
4176
|
description: "List files and directories at the given path (relative to project root).",
|
|
@@ -4244,6 +4355,7 @@ const DEFAULT_BYTE_CAP = 262144;
|
|
|
4244
4355
|
*/
|
|
4245
4356
|
const DEFAULT_IMAGE_BYTE_CAP = 5 * 1024 * 1024;
|
|
4246
4357
|
const readFile$1 = {
|
|
4358
|
+
isConcurrencySafe: true,
|
|
4247
4359
|
spec: {
|
|
4248
4360
|
name: "read_file",
|
|
4249
4361
|
description: "Read a file by path. Returns lines [offset..offset+limit). Default offset=1, limit=2000. Each line is prefixed with its 1-indexed line number followed by a tab (e.g. `42\\tconst foo = bar`); the prefix is metadata, not part of the file. Mirrors Claude Code's `cat -n`-style compact output for token efficiency. A trailing footer explains how to read the rest when truncated. Binary files return a short marker rather than mojibake.",
|
|
@@ -4438,7 +4550,110 @@ function extractTrailingCommand(command) {
|
|
|
4438
4550
|
* context's own default (30 s for in-process).
|
|
4439
4551
|
*/
|
|
4440
4552
|
const DEFAULT_MAX_OUTPUT_BYTES = 32768;
|
|
4553
|
+
/**
|
|
4554
|
+
* Best-effort read-only allow-list for the leading command token. Members
|
|
4555
|
+
* are commands whose stock behavior cannot mutate the workspace under any
|
|
4556
|
+
* argument combination — `ls`, `cat`, `pwd`, etc. Commands that *can*
|
|
4557
|
+
* mutate depending on flags (`find -delete`, `git tag <name>`, `tar -x`)
|
|
4558
|
+
* are intentionally excluded; the input-aware {@link isReadOnlyShellCommand}
|
|
4559
|
+
* predicate falls back to the conservative "not safe" answer for them, so
|
|
4560
|
+
* the scheduler barriers them.
|
|
4561
|
+
*/
|
|
4562
|
+
const SHELL_READ_ONLY_COMMANDS = new Set([
|
|
4563
|
+
"ls",
|
|
4564
|
+
"cat",
|
|
4565
|
+
"head",
|
|
4566
|
+
"tail",
|
|
4567
|
+
"wc",
|
|
4568
|
+
"pwd",
|
|
4569
|
+
"whoami",
|
|
4570
|
+
"id",
|
|
4571
|
+
"date",
|
|
4572
|
+
"uname",
|
|
4573
|
+
"hostname",
|
|
4574
|
+
"tty",
|
|
4575
|
+
"echo",
|
|
4576
|
+
"printf",
|
|
4577
|
+
"env",
|
|
4578
|
+
"printenv",
|
|
4579
|
+
"which",
|
|
4580
|
+
"type",
|
|
4581
|
+
"command",
|
|
4582
|
+
"file",
|
|
4583
|
+
"stat",
|
|
4584
|
+
"grep",
|
|
4585
|
+
"rg",
|
|
4586
|
+
"ag",
|
|
4587
|
+
"true",
|
|
4588
|
+
"false",
|
|
4589
|
+
"test"
|
|
4590
|
+
]);
|
|
4591
|
+
/**
|
|
4592
|
+
* `git` subcommands that are pure reads regardless of arguments. Excludes
|
|
4593
|
+
* `branch`/`tag`/`remote` (which can mutate when given a name) and
|
|
4594
|
+
* `config` (which writes when given a value).
|
|
4595
|
+
*/
|
|
4596
|
+
const GIT_READ_ONLY_SUBCOMMANDS = new Set([
|
|
4597
|
+
"status",
|
|
4598
|
+
"log",
|
|
4599
|
+
"diff",
|
|
4600
|
+
"show",
|
|
4601
|
+
"blame",
|
|
4602
|
+
"rev-parse",
|
|
4603
|
+
"ls-files",
|
|
4604
|
+
"ls-tree",
|
|
4605
|
+
"cat-file",
|
|
4606
|
+
"reflog",
|
|
4607
|
+
"shortlog",
|
|
4608
|
+
"describe",
|
|
4609
|
+
"rev-list",
|
|
4610
|
+
"name-rev",
|
|
4611
|
+
"whatchanged",
|
|
4612
|
+
"merge-base",
|
|
4613
|
+
"symbolic-ref"
|
|
4614
|
+
]);
|
|
4615
|
+
/**
|
|
4616
|
+
* Conservative read-only verdict for a shell command — used to opt a
|
|
4617
|
+
* `shell` invocation into the scheduler's concurrent fleet. Returns
|
|
4618
|
+
* `false` (fail-closed) on anything ambiguous so the scheduler barriers
|
|
4619
|
+
* it. Specifically:
|
|
4620
|
+
*
|
|
4621
|
+
* - Rejects compound commands (`;`, `&&`, `||`, `|`) and redirects (`>`,
|
|
4622
|
+
* `>>`, `<`) — even a pipe to a read-only sink is treated as too
|
|
4623
|
+
* complex to analyze.
|
|
4624
|
+
* - Rejects subshell / process substitution (`$(...)`, `` `...` ``,
|
|
4625
|
+
* `<(...)`, `>(...)`).
|
|
4626
|
+
* - Skips leading `VAR=value` env assignments to find the real
|
|
4627
|
+
* command token.
|
|
4628
|
+
* - Strips a possible absolute path on the command (`/usr/bin/ls` → `ls`).
|
|
4629
|
+
* - Allows the command iff its base name is in
|
|
4630
|
+
* {@link SHELL_READ_ONLY_COMMANDS} OR it's `git <subcmd>` where
|
|
4631
|
+
* `<subcmd>` is in {@link GIT_READ_ONLY_SUBCOMMANDS}.
|
|
4632
|
+
*
|
|
4633
|
+
* Cheap (no spawned process; regex + token scan). Safe to call from the
|
|
4634
|
+
* hot scheduler path.
|
|
4635
|
+
*/
|
|
4636
|
+
function isReadOnlyShellCommand(command) {
|
|
4637
|
+
if (typeof command !== "string") return false;
|
|
4638
|
+
const trimmed = command.trim();
|
|
4639
|
+
if (trimmed === "") return false;
|
|
4640
|
+
if (/[<>;&|`\n]/.test(trimmed)) return false;
|
|
4641
|
+
if (trimmed.includes("$(") || trimmed.includes("<(") || trimmed.includes(">(")) return false;
|
|
4642
|
+
const tokens = trimmed.split(/\s+/);
|
|
4643
|
+
let i = 0;
|
|
4644
|
+
while (i < tokens.length && /^[A-Z_]\w*=/i.test(tokens[i])) i++;
|
|
4645
|
+
const head = tokens[i];
|
|
4646
|
+
if (!head) return false;
|
|
4647
|
+
const base = head.split("/").pop() ?? head;
|
|
4648
|
+
if (SHELL_READ_ONLY_COMMANDS.has(base)) return true;
|
|
4649
|
+
if (base === "git") {
|
|
4650
|
+
const sub = tokens[i + 1];
|
|
4651
|
+
return typeof sub === "string" && GIT_READ_ONLY_SUBCOMMANDS.has(sub);
|
|
4652
|
+
}
|
|
4653
|
+
return false;
|
|
4654
|
+
}
|
|
4441
4655
|
const shell = {
|
|
4656
|
+
isConcurrencySafe: (input) => isReadOnlyShellCommand(input.command),
|
|
4442
4657
|
spec: {
|
|
4443
4658
|
name: "shell",
|
|
4444
4659
|
description: "Execute a shell command in the project root and return its combined stdout/stderr. Output is tail-priority truncated at 32 KiB by default; errors and exit-code summaries live in the tail. By default each call appends a `(exit N, Nms)` footer and surfaces non-empty stderr in a separate section even on success — set `metadata: false` to return only stdout. Set maxOutputBytes=0 to disable truncation.",
|
|
@@ -4715,6 +4930,7 @@ function createSpawnTool(options = {}) {
|
|
|
4715
4930
|
get totalChildStats() {
|
|
4716
4931
|
return { ...localStats };
|
|
4717
4932
|
},
|
|
4933
|
+
isConcurrencySafe: true,
|
|
4718
4934
|
spec: {
|
|
4719
4935
|
name: "spawn",
|
|
4720
4936
|
description: "Spawn a sub-agent for a self-contained task that benefits from isolation (separate context window, separate retries) — for example, a deep research dive or a long codegen pass on a specific file. The sub-agent runs independently with its own tool access and returns its final response. Do NOT spawn for sequential steps you could do yourself.",
|
|
@@ -4947,6 +5163,6 @@ const writeFile$1 = {
|
|
|
4947
5163
|
}
|
|
4948
5164
|
};
|
|
4949
5165
|
//#endregion
|
|
4950
|
-
export { readStateKey as A, PERSISTENCE_PREVIEW_BYTES as C, resolvePersistDir as D, maybePersistToolResult as E, getReadState as O, PERSISTED_STUB_PREFIX as S, cleanupPersistedSession as T, createSkillsReadTool as _, multiEdit as a, TOOL_USE_SKIPPED_MESSAGE as b, grep as c, resolveOldString as d, styleReplacementForVia as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, resolveReadStateMap as j, hashContent as k, glob as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, createAgent as p, shell as r, createInteractionTool as s, writeFile$1 as t, edit as u, INTERRUPT_MESSAGE_FOR_TOOL_USE as v, buildPersistedStub as w, validateToolArgs as x,
|
|
5166
|
+
export { readStateKey as A, PERSISTENCE_PREVIEW_BYTES as C, resolvePersistDir as D, maybePersistToolResult as E, getReadState as O, PERSISTED_STUB_PREFIX as S, cleanupPersistedSession as T, createSkillsReadTool as _, multiEdit as a, TOOL_USE_SKIPPED_MESSAGE as b, grep as c, resolveOldString as d, styleReplacementForVia as f, createSkillsRunScriptTool as g, createSkillsUseTool as h, readFile$1 as i, resolveReadStateMap as j, hashContent as k, glob as l, createToolSearchTool as m, createSpawnTool as n, listFiles as o, createAgent as p, shell as r, createInteractionTool as s, writeFile$1 as t, edit as u, INTERRUPT_MESSAGE_FOR_TOOL_USE as v, buildPersistedStub as w, validateToolArgs as x, SHELL_CASCADE_CANCEL_MESSAGE as y };
|
|
4951
5167
|
|
|
4952
|
-
//# sourceMappingURL=tools-
|
|
5168
|
+
//# sourceMappingURL=tools-DKdyPoUf.js.map
|