zidane 5.4.0 → 5.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-DHQAsdj6.d.ts → agent-DxBoKDba.d.ts} +140 -1
- package/dist/agent-DxBoKDba.d.ts.map +1 -0
- package/dist/chat.d.ts +62 -5
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/{index-CrqFoaQA.d.ts → index-B2VOOijU.d.ts} +461 -8
- package/dist/index-B2VOOijU.d.ts.map +1 -0
- package/dist/{index-CHSaLab5.d.ts → index-BOtXdQkW.d.ts} +2 -2
- package/dist/{index-CHSaLab5.d.ts.map → index-BOtXdQkW.d.ts.map} +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1522 -47
- package/dist/index.js.map +1 -1
- package/dist/{login-bK0EP8La.js → login-CJbeAadS.js} +2 -2
- package/dist/{login-bK0EP8La.js.map → login-CJbeAadS.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{presets-M8f6lDnW.js → presets-MCcvxiNT.js} +2 -2
- package/dist/{presets-M8f6lDnW.js.map → presets-MCcvxiNT.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-DKdyPoUf.js → tools-BNfyY14s.js} +192 -34
- package/dist/tools-BNfyY14s.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-Fgh_rZ04.d.ts → transcript-anchors-DonKvoh4.d.ts} +19 -4
- package/dist/transcript-anchors-DonKvoh4.d.ts.map +1 -0
- package/dist/tui.d.ts +3 -3
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +52 -23
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-DDokWR8p.js → turn-operations-TKvy0q29.js} +128 -4
- package/dist/turn-operations-TKvy0q29.js.map +1 -0
- package/dist/types-IcokUOyC.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/docs/ARCHITECTURE.md +6 -5
- package/docs/CHAT.md +21 -3
- package/docs/SKILL.md +1 -1
- package/docs/TUI.md +2 -2
- package/package.json +1 -1
- package/dist/agent-DHQAsdj6.d.ts.map +0 -1
- package/dist/index-CrqFoaQA.d.ts.map +0 -1
- package/dist/tools-DKdyPoUf.js.map +0 -1
- package/dist/transcript-anchors-Fgh_rZ04.d.ts.map +0 -1
- package/dist/turn-operations-DDokWR8p.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets-
|
|
1
|
+
{"version":3,"file":"presets-MCcvxiNT.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-DxBoKDba.js";
|
|
2
|
+
import { a as basicTools, i as _default, n as composePresets, r as definePreset, t as Preset } from "./index-B2VOOijU.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-MCcvxiNT.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-DxBoKDba.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-DxBoKDba.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-DxBoKDba.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-BOtXdQkW.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 };
|
|
@@ -1071,6 +1071,8 @@ function applyStaleReadElision(messages) {
|
|
|
1071
1071
|
messages,
|
|
1072
1072
|
elidedPaths: []
|
|
1073
1073
|
};
|
|
1074
|
+
const pathsWithFreshRead = /* @__PURE__ */ new Set();
|
|
1075
|
+
for (const [callId, info] of readCallInfo) if (!staleCallIds.has(callId)) pathsWithFreshRead.add(info.path);
|
|
1074
1076
|
let changed = false;
|
|
1075
1077
|
const out = messages.slice();
|
|
1076
1078
|
for (let i = 0; i < out.length; i++) {
|
|
@@ -1094,7 +1096,7 @@ function applyStaleReadElision(messages) {
|
|
|
1094
1096
|
}
|
|
1095
1097
|
return {
|
|
1096
1098
|
messages: changed ? out : messages,
|
|
1097
|
-
elidedPaths: [...elidedPathSet]
|
|
1099
|
+
elidedPaths: [...elidedPathSet].filter((p) => !pathsWithFreshRead.has(p))
|
|
1098
1100
|
};
|
|
1099
1101
|
}
|
|
1100
1102
|
/**
|
|
@@ -1182,7 +1184,14 @@ async function runLoop(ctx) {
|
|
|
1182
1184
|
await ctx.hooks.callHook("agent:abort", {});
|
|
1183
1185
|
break;
|
|
1184
1186
|
}
|
|
1185
|
-
const result = await executeTurn(ctx, turn
|
|
1187
|
+
const result = await executeTurn(ctx, turn, {
|
|
1188
|
+
input: totalIn,
|
|
1189
|
+
output: totalOut,
|
|
1190
|
+
cacheRead: totalCacheRead,
|
|
1191
|
+
cacheCreation: totalCacheCreation,
|
|
1192
|
+
priorCost: turnUsages.reduce((s, t) => s + (t.cost ?? 0), 0),
|
|
1193
|
+
priorTurns: turnsCompleted
|
|
1194
|
+
});
|
|
1186
1195
|
turnsCompleted = turn + 1;
|
|
1187
1196
|
totalIn += result.usage.input;
|
|
1188
1197
|
totalOut += result.usage.output;
|
|
@@ -1293,7 +1302,49 @@ function buildStreamErrorPlaceholder(err) {
|
|
|
1293
1302
|
const oneLine = raw.replace(/\s+/g, " ");
|
|
1294
1303
|
return `[✗ Streaming failed before any output: ${oneLine.length > ERROR_PLACEHOLDER_MAX ? `${oneLine.slice(0, ERROR_PLACEHOLDER_MAX - 1).trimEnd()}…` : oneLine}]`;
|
|
1295
1304
|
}
|
|
1296
|
-
|
|
1305
|
+
function buildCumulativeUsage(prior, turnUsage) {
|
|
1306
|
+
const cost = prior.priorCost + (turnUsage.cost ?? 0);
|
|
1307
|
+
return Object.freeze({
|
|
1308
|
+
input: prior.input + turnUsage.input,
|
|
1309
|
+
output: prior.output + turnUsage.output,
|
|
1310
|
+
cacheRead: prior.cacheRead + (turnUsage.cacheRead ?? 0),
|
|
1311
|
+
cacheCreation: prior.cacheCreation + (turnUsage.cacheCreation ?? 0),
|
|
1312
|
+
...cost > 0 ? { cost } : {},
|
|
1313
|
+
turns: prior.priorTurns + 1
|
|
1314
|
+
});
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Best-effort extraction of `statusCode` / `requestId` from native provider
|
|
1318
|
+
* SDK exceptions, attached to `stream:error` ctx so observability handlers
|
|
1319
|
+
* don't have to walk `cause` chains. Recognized shapes:
|
|
1320
|
+
*
|
|
1321
|
+
* - Anthropic SDK `APIError` (`status`, `headers['request-id']`)
|
|
1322
|
+
* - OpenAI SDK error (`status`, `headers['x-request-id']`)
|
|
1323
|
+
* - OpenRouter / OpenAI-compat HTTP errors (`status`)
|
|
1324
|
+
* - Cerebras (`status`)
|
|
1325
|
+
*
|
|
1326
|
+
* Silent no-op for arbitrary `Error`s and primitives — the fields stay
|
|
1327
|
+
* undefined and the raw `err` is still forwarded for handlers that need
|
|
1328
|
+
* full context.
|
|
1329
|
+
*/
|
|
1330
|
+
function extractStreamErrorMeta(err) {
|
|
1331
|
+
if (!err || typeof err !== "object") return {};
|
|
1332
|
+
const e = err;
|
|
1333
|
+
const out = {};
|
|
1334
|
+
const statusCandidate = typeof e.status === "number" ? e.status : typeof e.statusCode === "number" ? e.statusCode : void 0;
|
|
1335
|
+
if (typeof statusCandidate === "number" && Number.isFinite(statusCandidate)) out.statusCode = statusCandidate;
|
|
1336
|
+
if (typeof e.requestId === "string") out.requestId = e.requestId;
|
|
1337
|
+
else {
|
|
1338
|
+
const headers = e.headers;
|
|
1339
|
+
if (headers && typeof headers === "object") {
|
|
1340
|
+
const h = headers;
|
|
1341
|
+
const candidate = h["request-id"] ?? h["x-request-id"] ?? h.requestId;
|
|
1342
|
+
if (typeof candidate === "string") out.requestId = candidate;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
return out;
|
|
1346
|
+
}
|
|
1347
|
+
async function executeTurn(ctx, turn, priorUsage) {
|
|
1297
1348
|
const turnId = await ctx.generateTurnId();
|
|
1298
1349
|
let canonicalMessages = turnsToMessages(applyCompactSummaryCutoff(ctx.turns));
|
|
1299
1350
|
if (ctx.elideStaleReads === true) {
|
|
@@ -1341,10 +1392,20 @@ async function executeTurn(ctx, turn) {
|
|
|
1341
1392
|
});
|
|
1342
1393
|
let currentText = "";
|
|
1343
1394
|
let currentThinking = "";
|
|
1395
|
+
const streamStartedAt = Date.now();
|
|
1396
|
+
let turnTtftMs;
|
|
1397
|
+
const markTurnTtft = () => {
|
|
1398
|
+
if (turnTtftMs === void 0) turnTtftMs = Date.now() - streamStartedAt;
|
|
1399
|
+
};
|
|
1400
|
+
await ctx.hooks.callHook("stream:start", {
|
|
1401
|
+
turnId,
|
|
1402
|
+
startedAt: streamStartedAt
|
|
1403
|
+
});
|
|
1344
1404
|
let result;
|
|
1345
1405
|
try {
|
|
1346
1406
|
result = await ctx.provider.stream(streamOptions, {
|
|
1347
1407
|
onText(delta) {
|
|
1408
|
+
markTurnTtft();
|
|
1348
1409
|
currentText += delta;
|
|
1349
1410
|
ctx.hooks.callHook("stream:text", {
|
|
1350
1411
|
delta,
|
|
@@ -1353,6 +1414,7 @@ async function executeTurn(ctx, turn) {
|
|
|
1353
1414
|
});
|
|
1354
1415
|
},
|
|
1355
1416
|
onThinking(delta) {
|
|
1417
|
+
markTurnTtft();
|
|
1356
1418
|
currentThinking += delta;
|
|
1357
1419
|
ctx.hooks.callHook("stream:thinking", {
|
|
1358
1420
|
delta,
|
|
@@ -1387,10 +1449,14 @@ async function executeTurn(ctx, turn) {
|
|
|
1387
1449
|
createdAt: Date.now()
|
|
1388
1450
|
};
|
|
1389
1451
|
ctx.turns.push(errorTurn);
|
|
1390
|
-
if (!wasAborted)
|
|
1391
|
-
err
|
|
1392
|
-
|
|
1393
|
-
|
|
1452
|
+
if (!wasAborted) {
|
|
1453
|
+
const meta = extractStreamErrorMeta(err);
|
|
1454
|
+
await ctx.hooks.callHook("stream:error", {
|
|
1455
|
+
err,
|
|
1456
|
+
turnId,
|
|
1457
|
+
...meta
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1394
1460
|
await ctx.hooks.callHook("turn:after", {
|
|
1395
1461
|
turn,
|
|
1396
1462
|
turnId,
|
|
@@ -1399,7 +1465,8 @@ async function executeTurn(ctx, turn) {
|
|
|
1399
1465
|
toolCounts: {
|
|
1400
1466
|
turn: Object.freeze({}),
|
|
1401
1467
|
run: Object.freeze({ ...ctx.runToolCounts })
|
|
1402
|
-
}
|
|
1468
|
+
},
|
|
1469
|
+
cumulativeUsage: buildCumulativeUsage(priorUsage, errorUsage)
|
|
1403
1470
|
});
|
|
1404
1471
|
throw wrapProviderError(err, ctx);
|
|
1405
1472
|
}
|
|
@@ -1407,11 +1474,13 @@ async function executeTurn(ctx, turn) {
|
|
|
1407
1474
|
text: currentText,
|
|
1408
1475
|
turnId
|
|
1409
1476
|
});
|
|
1477
|
+
if (turnTtftMs === void 0 && result.toolCalls.length > 0) turnTtftMs = Date.now() - streamStartedAt;
|
|
1410
1478
|
const canonicalToolCalls = result.toolCalls.map((tc) => ({
|
|
1411
1479
|
...tc,
|
|
1412
1480
|
name: toCanonicalName(tc.name, ctx.aliasMaps)
|
|
1413
1481
|
}));
|
|
1414
1482
|
const canonicalContent = rewriteContentToCanonical(result.assistantMessage?.content ?? [], ctx.aliasMaps);
|
|
1483
|
+
if (turnTtftMs !== void 0 && result.usage.timeToFirstTokenMs === void 0) result.usage.timeToFirstTokenMs = turnTtftMs;
|
|
1415
1484
|
const assistantTurn = {
|
|
1416
1485
|
id: turnId,
|
|
1417
1486
|
runId: ctx.runId,
|
|
@@ -1434,7 +1503,8 @@ async function executeTurn(ctx, turn) {
|
|
|
1434
1503
|
toolCounts: {
|
|
1435
1504
|
turn: Object.freeze(turnCounts),
|
|
1436
1505
|
run: Object.freeze({ ...ctx.runToolCounts })
|
|
1437
|
-
}
|
|
1506
|
+
},
|
|
1507
|
+
cumulativeUsage: buildCumulativeUsage(priorUsage, result.usage)
|
|
1438
1508
|
});
|
|
1439
1509
|
if (result.done) {
|
|
1440
1510
|
if (ctx.schema && !ctx.signal.aborted) {
|
|
@@ -2588,9 +2658,11 @@ function createToolSearchTool(options) {
|
|
|
2588
2658
|
//#region src/agent.ts
|
|
2589
2659
|
const HOOK_EVENT_SET = new Set([
|
|
2590
2660
|
"system:before",
|
|
2661
|
+
"agent:start",
|
|
2591
2662
|
"turn:before",
|
|
2592
2663
|
"turn:after",
|
|
2593
2664
|
"tool-results:after",
|
|
2665
|
+
"stream:start",
|
|
2594
2666
|
"stream:text",
|
|
2595
2667
|
"stream:end",
|
|
2596
2668
|
"stream:thinking",
|
|
@@ -2647,6 +2719,7 @@ const HOOK_EVENT_SET = new Set([
|
|
|
2647
2719
|
"budget:exceeded",
|
|
2648
2720
|
"tool-budget:exceeded",
|
|
2649
2721
|
"pairing:repair",
|
|
2722
|
+
"tracing:redact",
|
|
2650
2723
|
"agent:abort",
|
|
2651
2724
|
"agent:done",
|
|
2652
2725
|
"session:start",
|
|
@@ -2981,6 +3054,16 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
|
|
|
2981
3054
|
prompt: promptLabel
|
|
2982
3055
|
});
|
|
2983
3056
|
}
|
|
3057
|
+
const runStartedAt = Date.now();
|
|
3058
|
+
await hooks.callHook("agent:start", {
|
|
3059
|
+
runId,
|
|
3060
|
+
...options.parentRunId ? { parentRunId: options.parentRunId } : {},
|
|
3061
|
+
depth: typeof options.depth === "number" ? options.depth : 0,
|
|
3062
|
+
...agentName ? { agentName } : {},
|
|
3063
|
+
...provider.name ? { providerName: provider.name } : {},
|
|
3064
|
+
startedAt: runStartedAt,
|
|
3065
|
+
...options.tracingContext ? { tracingContext: Object.freeze({ ...options.tracingContext }) } : {}
|
|
3066
|
+
});
|
|
2984
3067
|
if (externalSignal) if (externalSignal.aborted) abortController.abort();
|
|
2985
3068
|
else {
|
|
2986
3069
|
externalAbortListener = () => abortController?.abort();
|
|
@@ -3770,7 +3853,7 @@ const edit = {
|
|
|
3770
3853
|
if (readState) {
|
|
3771
3854
|
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
3772
3855
|
const prior = readState.get(absKey);
|
|
3773
|
-
if (!prior) return `Edit error: ${target} has not been read in this session. Call read_file first so the edit applies against the current contents
|
|
3856
|
+
if (!prior) return `Edit error: ${target} has not been read in this session. Call read_file first so the edit applies against the current contents.`;
|
|
3774
3857
|
if (prior.contentHash !== hashContent(original)) return `Edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`;
|
|
3775
3858
|
}
|
|
3776
3859
|
}
|
|
@@ -4193,10 +4276,33 @@ const listFiles = {
|
|
|
4193
4276
|
};
|
|
4194
4277
|
//#endregion
|
|
4195
4278
|
//#region src/tools/multi-edit.ts
|
|
4279
|
+
/**
|
|
4280
|
+
* Inline annotation builder — kept local to avoid importing from
|
|
4281
|
+
* `chat/edit-approval.ts` (that's a renderer-side module; tools live
|
|
4282
|
+
* one layer below). Line shape matches `parseEditOutcomesFromResult`'s
|
|
4283
|
+
* regex so the round-trip is lossless.
|
|
4284
|
+
*
|
|
4285
|
+
* Newlines in `reason` are folded to spaces because the parser is line-
|
|
4286
|
+
* scoped (`body.split('\n')`); a multi-line reason would split into a
|
|
4287
|
+
* "trailing prose" line and trip the malformed-block guard, losing every
|
|
4288
|
+
* outcome below it. Static reasons in this file are single-line; the
|
|
4289
|
+
* sanitize is a guard against a pathological `target` (file path
|
|
4290
|
+
* containing a newline) leaking into `old_string not found in <target>`.
|
|
4291
|
+
*/
|
|
4292
|
+
function annotationFor(outcomes) {
|
|
4293
|
+
const lines = ["<edit-outcomes>"];
|
|
4294
|
+
for (let i = 0; i < outcomes.length; i++) {
|
|
4295
|
+
const o = outcomes[i];
|
|
4296
|
+
const reason = o.reason ? `: ${o.reason.replace(/\r?\n/g, " ")}` : "";
|
|
4297
|
+
lines.push(`#${i + 1} ${o.kind}${reason}`);
|
|
4298
|
+
}
|
|
4299
|
+
lines.push("</edit-outcomes>");
|
|
4300
|
+
return lines.join("\n");
|
|
4301
|
+
}
|
|
4196
4302
|
const multiEdit = {
|
|
4197
4303
|
spec: {
|
|
4198
4304
|
name: "multi_edit",
|
|
4199
|
-
description: "Apply a sequential list of edits to a file. Each edit operates on the result of the previous edit. Prefer this over multiple `edit` calls when several non-overlapping changes are needed in the same file.
|
|
4305
|
+
description: "Apply a sequential list of edits to a file. Each edit operates on the result of the previous APPLIED edit. Prefer this over multiple `edit` calls when several non-overlapping changes are needed in the same file. Edits run **best-effort**: a per-step failure (`old_string` not found, ambiguous match without `replace_all`, identical strings) is reported in the result but does NOT block the remaining steps. The file is written iff at least one step applied. The result lists per-hunk outcomes (`applied` / `failed`) so the model can re-issue just the failures without resending the whole batch. Each step tolerates `read_file` line-number prefixes (`<N>\\t…`, `<N>|…`, or `<N>→…`) in `old_string` / `new_string`.",
|
|
4200
4306
|
inputSchema: {
|
|
4201
4307
|
type: "object",
|
|
4202
4308
|
properties: {
|
|
@@ -4206,7 +4312,7 @@ const multiEdit = {
|
|
|
4206
4312
|
},
|
|
4207
4313
|
edits: {
|
|
4208
4314
|
type: "array",
|
|
4209
|
-
description: "List of edits applied in order; each operates on the previous edit's output.",
|
|
4315
|
+
description: "List of edits applied in order; each operates on the previous applied edit's output.",
|
|
4210
4316
|
items: {
|
|
4211
4317
|
type: "object",
|
|
4212
4318
|
properties: {
|
|
@@ -4236,40 +4342,88 @@ const multiEdit = {
|
|
|
4236
4342
|
if (readState) {
|
|
4237
4343
|
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
4238
4344
|
const prior = readState.get(absKey);
|
|
4239
|
-
if (!prior) return `multi_edit error: ${target} has not been read in this session. Call read_file first so the edits apply against the current contents
|
|
4345
|
+
if (!prior) return `multi_edit error: ${target} has not been read in this session. Call read_file first so the edits apply against the current contents.`;
|
|
4240
4346
|
if (prior.contentHash !== hashContent(current)) return `multi_edit error: ${target} has changed on disk since the last read. Re-read the file before editing.`;
|
|
4241
4347
|
}
|
|
4242
4348
|
}
|
|
4349
|
+
const outcomes = [];
|
|
4243
4350
|
let totalReplacements = 0;
|
|
4244
4351
|
for (let i = 0; i < steps.length; i++) {
|
|
4245
4352
|
const step = steps[i];
|
|
4246
4353
|
const find = step.old_string;
|
|
4247
4354
|
const replacement = step.new_string;
|
|
4248
4355
|
const replaceAll = step.replace_all === true;
|
|
4249
|
-
if (typeof find !== "string" || typeof replacement !== "string")
|
|
4250
|
-
|
|
4251
|
-
|
|
4356
|
+
if (typeof find !== "string" || typeof replacement !== "string") {
|
|
4357
|
+
outcomes.push({
|
|
4358
|
+
kind: "failed",
|
|
4359
|
+
reason: "missing old_string or new_string"
|
|
4360
|
+
});
|
|
4361
|
+
continue;
|
|
4362
|
+
}
|
|
4363
|
+
if (find.length === 0) {
|
|
4364
|
+
outcomes.push({
|
|
4365
|
+
kind: "failed",
|
|
4366
|
+
reason: "empty old_string (use write_file to fully replace a file)"
|
|
4367
|
+
});
|
|
4368
|
+
continue;
|
|
4369
|
+
}
|
|
4370
|
+
if (find === replacement) {
|
|
4371
|
+
outcomes.push({
|
|
4372
|
+
kind: "failed",
|
|
4373
|
+
reason: "old_string and new_string are identical"
|
|
4374
|
+
});
|
|
4375
|
+
continue;
|
|
4376
|
+
}
|
|
4252
4377
|
const match = resolveOldString(current, find);
|
|
4253
|
-
if (!match)
|
|
4378
|
+
if (!match) {
|
|
4379
|
+
outcomes.push({
|
|
4380
|
+
kind: "failed",
|
|
4381
|
+
reason: `old_string not found in ${target}`
|
|
4382
|
+
});
|
|
4383
|
+
continue;
|
|
4384
|
+
}
|
|
4254
4385
|
const { actual, occurrences, via } = match;
|
|
4255
|
-
if (occurrences > 1 && !replaceAll)
|
|
4386
|
+
if (occurrences > 1 && !replaceAll) {
|
|
4387
|
+
outcomes.push({
|
|
4388
|
+
kind: "failed",
|
|
4389
|
+
reason: `old_string appears ${occurrences} times — pass replace_all=true on this edit or expand old_string for uniqueness`
|
|
4390
|
+
});
|
|
4391
|
+
continue;
|
|
4392
|
+
}
|
|
4256
4393
|
const styledReplacement = styleReplacementForVia(replacement, via, actual);
|
|
4257
4394
|
current = replaceAll ? current.split(actual).join(styledReplacement) : current.replace(actual, styledReplacement);
|
|
4258
4395
|
totalReplacements += occurrences;
|
|
4396
|
+
outcomes.push({ kind: "applied" });
|
|
4259
4397
|
}
|
|
4260
|
-
|
|
4261
|
-
const
|
|
4262
|
-
if (
|
|
4263
|
-
|
|
4264
|
-
const
|
|
4265
|
-
if (
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4398
|
+
const appliedCount = outcomes.reduce((n, o) => o.kind === "applied" ? n + 1 : n, 0);
|
|
4399
|
+
const failedCount = outcomes.length - appliedCount;
|
|
4400
|
+
if (appliedCount > 0) {
|
|
4401
|
+
await ctx.execution.writeFile(ctx.handle, target, current);
|
|
4402
|
+
const readState = resolveReadStateMap(ctx);
|
|
4403
|
+
if (readState) {
|
|
4404
|
+
const absKey = readStateKey(ctx.handle.cwd, target);
|
|
4405
|
+
const prior = readState.get(absKey);
|
|
4406
|
+
if (prior) readState.set(absKey, {
|
|
4407
|
+
...prior,
|
|
4408
|
+
contentHash: hashContent(current),
|
|
4409
|
+
mtimeMs: Date.now()
|
|
4410
|
+
});
|
|
4411
|
+
}
|
|
4270
4412
|
}
|
|
4271
4413
|
const n = steps.length;
|
|
4272
|
-
|
|
4414
|
+
let header;
|
|
4415
|
+
if (appliedCount === n) header = `Edited ${target}: applied ${n} edit${n === 1 ? "" : "s"} (${totalReplacements} replacement${totalReplacements === 1 ? "" : "s"}).`;
|
|
4416
|
+
else if (appliedCount > 0) header = `Edited ${target}: applied ${appliedCount} of ${n} edits (${totalReplacements} replacement${totalReplacements === 1 ? "" : "s"}).`;
|
|
4417
|
+
else header = `multi_edit error: no edits applied to ${target} (${n} attempted).`;
|
|
4418
|
+
const failureLines = [];
|
|
4419
|
+
for (let i = 0; i < outcomes.length; i++) {
|
|
4420
|
+
const o = outcomes[i];
|
|
4421
|
+
if (o.kind === "failed") failureLines.push(`edit #${i + 1} failed: ${o.reason}`);
|
|
4422
|
+
}
|
|
4423
|
+
const parts = [header];
|
|
4424
|
+
if (failureLines.length > 0) parts.push(failureLines.join("\n"));
|
|
4425
|
+
if (failedCount > 0) parts.push(annotationFor(outcomes));
|
|
4426
|
+
return parts.join("\n\n");
|
|
4273
4427
|
}
|
|
4274
4428
|
};
|
|
4275
4429
|
//#endregion
|
|
@@ -5007,11 +5161,14 @@ function createSpawnTool(options = {}) {
|
|
|
5007
5161
|
};
|
|
5008
5162
|
}
|
|
5009
5163
|
options.onSpawn?.(child);
|
|
5010
|
-
|
|
5164
|
+
const spawnHookCtx = {
|
|
5011
5165
|
id,
|
|
5012
5166
|
task,
|
|
5013
|
-
depth: childDepth
|
|
5014
|
-
|
|
5167
|
+
depth: childDepth,
|
|
5168
|
+
tracingContext: {}
|
|
5169
|
+
};
|
|
5170
|
+
await ctx.hooks.callHook("spawn:before", spawnHookCtx);
|
|
5171
|
+
const propagatedTracing = Object.keys(spawnHookCtx.tracingContext).length > 0 ? Object.freeze({ ...spawnHookCtx.tracingContext }) : void 0;
|
|
5015
5172
|
const runPromise = agent.run({
|
|
5016
5173
|
prompt: task,
|
|
5017
5174
|
model: options.model,
|
|
@@ -5019,7 +5176,8 @@ function createSpawnTool(options = {}) {
|
|
|
5019
5176
|
thinking: options.thinking,
|
|
5020
5177
|
signal: ctx.signal,
|
|
5021
5178
|
depth: childDepth,
|
|
5022
|
-
...options.persist && ctx.runId ? { parentRunId: ctx.runId } : {}
|
|
5179
|
+
...options.persist && ctx.runId ? { parentRunId: ctx.runId } : {},
|
|
5180
|
+
...propagatedTracing ? { tracingContext: propagatedTracing } : {}
|
|
5023
5181
|
});
|
|
5024
5182
|
try {
|
|
5025
5183
|
finalStats = await raceWithTimeout(runPromise, options.timeoutMs);
|
|
@@ -5165,4 +5323,4 @@ const writeFile$1 = {
|
|
|
5165
5323
|
//#endregion
|
|
5166
5324
|
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 };
|
|
5167
5325
|
|
|
5168
|
-
//# sourceMappingURL=tools-
|
|
5326
|
+
//# sourceMappingURL=tools-BNfyY14s.js.map
|