zidane 6.5.1 → 6.5.3
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/{acp-o-LQAjFw.js → acp-CIpD8UIw.js} +4 -4
- package/dist/{acp-o-LQAjFw.js.map → acp-CIpD8UIw.js.map} +1 -1
- package/dist/acp-cli.js +5 -5
- package/dist/acp.d.ts +1 -1
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-BVNkC1h4.js → agent-8kfGIDb_.js} +755 -586
- package/dist/agent-8kfGIDb_.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{anthropic-Dov2mC5e.js → anthropic-_Hn1YiWr.js} +2 -2
- package/dist/{anthropic-Dov2mC5e.js.map → anthropic-_Hn1YiWr.js.map} +1 -1
- package/dist/{auth-B8ZuBcKC.js → auth-CS_e8ng1.js} +6 -5
- package/dist/{auth-B8ZuBcKC.js.map → auth-CS_e8ng1.js.map} +1 -1
- package/dist/chat/pure.d.ts +4 -4
- package/dist/chat/pure.js +3 -3
- package/dist/chat.d.ts +124 -10
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +6 -6
- package/dist/{context-breakdown-BLF10tOO.js → context-segments-1mcqSCM3.js} +110 -2
- package/dist/context-segments-1mcqSCM3.js.map +1 -0
- package/dist/{context-transport-D-daWOmp.js → context-transport-Bco9Wo0b.js} +3 -3
- package/dist/{context-transport-D-daWOmp.js.map → context-transport-Bco9Wo0b.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +5 -2
- package/dist/contexts/daytona.js.map +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/{index-CWBSrqI6.d.ts → index-BKyWhILQ.d.ts} +179 -7
- package/dist/index-BKyWhILQ.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +7 -7
- package/dist/{login-CR3fDHXh.js → login-D3CKhgbI.js} +2 -2
- package/dist/{login-CR3fDHXh.js.map → login-D3CKhgbI.js.map} +1 -1
- package/dist/{mcp-C6IkXNOS.js → mcp-D9fqOQo5.js} +3 -3
- package/dist/{mcp-C6IkXNOS.js.map → mcp-D9fqOQo5.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{oauth-bkEOybqm.js → oauth-BYjlFR-J.js} +49 -10
- package/dist/oauth-BYjlFR-J.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.js +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +68 -1
- package/dist/providers/xai.js.map +1 -0
- package/dist/{providers-B6mFe7OD.js → providers-VypZh7rD.js} +3 -3
- package/dist/{providers-B6mFe7OD.js.map → providers-VypZh7rD.js.map} +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +4 -4
- package/dist/restate.d.ts +1 -1
- package/dist/restate.js +1 -1
- package/dist/rolldown-runtime-BhDjJH2R.js +15 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/{stdio-DzUUkkhS.js → stdio-DPpBDPx5.js} +13 -4
- package/dist/{stdio-DzUUkkhS.js.map → stdio-DPpBDPx5.js.map} +1 -1
- package/dist/{stdio-loader-BILyUGmi.js → stdio-loader-CI4sPFve.js} +11 -6
- package/dist/stdio-loader-CI4sPFve.js.map +1 -0
- package/dist/{tool-formatters-gFqQbzPY.d.ts → tool-formatters-DMr62Hpy.d.ts} +3 -3
- package/dist/{tool-formatters-gFqQbzPY.d.ts.map → tool-formatters-DMr62Hpy.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-qCs3wZpu.d.ts → transcript-anchors-BHihk9nf.d.ts} +2 -2
- package/dist/{transcript-anchors-qCs3wZpu.d.ts.map → transcript-anchors-BHihk9nf.d.ts.map} +1 -1
- package/dist/{transcript-anchors-DEIr0tJC.js → transcript-anchors-uU_KZLsp.js} +161 -36
- package/dist/transcript-anchors-uU_KZLsp.js.map +1 -0
- package/dist/tui.d.ts +74 -3
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +823 -81
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-M9-jUyDd.d.ts → turn-operations-BgqVUjtl.d.ts} +3 -3
- package/dist/{turn-operations-M9-jUyDd.d.ts.map → turn-operations-BgqVUjtl.d.ts.map} +1 -1
- package/dist/{turn-operations-C3IijXMW.js → turn-operations-iGu5J08j.js} +2 -2
- package/dist/{turn-operations-C3IijXMW.js.map → turn-operations-iGu5J08j.js.map} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/{xai-Du6Wfnlb.js → xai-CfmI5Y5k.js} +10 -67
- package/dist/xai-CfmI5Y5k.js.map +1 -0
- package/docs/CHAT.md +42 -1
- package/docs/INTERACTIONS.md +39 -0
- package/docs/RESTATE.md +7 -0
- package/docs/TUI.md +28 -2
- package/package.json +18 -17
- package/dist/agent-BVNkC1h4.js.map +0 -1
- package/dist/context-breakdown-BLF10tOO.js.map +0 -1
- package/dist/index-CWBSrqI6.d.ts.map +0 -1
- package/dist/oauth-bkEOybqm.js.map +0 -1
- package/dist/stdio-loader-BILyUGmi.js.map +0 -1
- package/dist/transcript-anchors-DEIr0tJC.js.map +0 -1
- package/dist/xai-Du6Wfnlb.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { B as rewriteMessagesToWire, H as toWireName, I as augmentMcpDoubleUnderscoreAliases, L as buildAliasMaps, M as buildPromptMessage, N as canonicalizePrompt, R as buildSanitizedWireAliases, V as toCanonicalName, z as rewriteContentToCanonical } from "./openai-compat-CnHeo4Lz.js";
|
|
2
2
|
import { a as isWireTurn, c as toolOutputByteLength, i as documentBlockMarker, l as toolResultToText, o as sanitizeToolResultMetadata, s as toolOutputBudgetByteLength, t as DEFAULT_AGENT_CLOCK } from "./types-BIarq1qE.js";
|
|
3
|
-
import { a as
|
|
3
|
+
import { a as stripLineNumberPrefixes, i as resolveOldString, n as buildContextBreakdown, o as styleReplacementForVia, r as describeVia, t as buildContextSegments } from "./context-segments-1mcqSCM3.js";
|
|
4
4
|
import { n as estimateTokens, r as utf8ByteLength } from "./utils-ngQzYzZD.js";
|
|
5
5
|
import { a as formatDuration, c as previewLine, o as formatTaskStatus, s as formatTaskSummary } from "./format-BF745pLL.js";
|
|
6
6
|
import { i as parseGitLsFiles, r as GIT_LS_FILES_COMMAND } from "./glob-DluQFSw1.js";
|
|
@@ -13,7 +13,7 @@ import { n as writeFileAtomicAsync, t as writeFileAtomic } from "./atomic-write-
|
|
|
13
13
|
import { p as resolveStorageDirs, r as loadAgentPlugin } from "./plugins-2PMTVcp-.js";
|
|
14
14
|
import { r as createLogger, t as consoleSink } from "./logger-DBX9uYOw.js";
|
|
15
15
|
import { n as reconcileImageMediaType } from "./media-sniff-UKijEaiQ.js";
|
|
16
|
-
import { f as wrapDiscoveredMcpTools, i as deriveMcpToolMeta, n as connectMcpServers, s as nonOwningMcpView } from "./mcp-
|
|
16
|
+
import { f as wrapDiscoveredMcpTools, i as deriveMcpToolMeta, n as connectMcpServers, s as nonOwningMcpView } from "./mcp-D9fqOQo5.js";
|
|
17
17
|
import { appendStaticSection, renderSystemForWire } from "./prompt.js";
|
|
18
18
|
import { a as detectTurnInterruption, c as ensureToolResultPairing, l as filterUnresolvedToolUses, m as resolveContentRefsInMessages, n as SYNTHETIC_TOOL_RESULT_PLACEHOLDER, p as remintDuplicateToolCallIds, s as ensureEndsWithUserMessage } from "./messages-C_H9soi5.js";
|
|
19
19
|
import { a as getExtensionSessionState, c as setExtensionSessionState, l as withExtensionSession, n as currentExtensionSession, r as deleteExtensionSessionState, s as resumeChainRunIds } from "./session-VpLrNaFQ.js";
|
|
@@ -10542,6 +10542,134 @@ function textForPersistence(output) {
|
|
|
10542
10542
|
return parts.join("\n");
|
|
10543
10543
|
}
|
|
10544
10544
|
//#endregion
|
|
10545
|
+
//#region src/loop-recovery.ts
|
|
10546
|
+
/**
|
|
10547
|
+
* Operation labels used by the provider-stream watchdogs.
|
|
10548
|
+
*
|
|
10549
|
+
* Single source of truth for the strings so `withTimeout` callers and the
|
|
10550
|
+
* failure classifier can never drift: the classifier matches on exactly the
|
|
10551
|
+
* label the watchdog emits.
|
|
10552
|
+
*/
|
|
10553
|
+
const PROVIDER_WATCHDOG_OPERATIONS = {
|
|
10554
|
+
"first response": "provider first response",
|
|
10555
|
+
"total stream": "provider total stream",
|
|
10556
|
+
"stream inactivity": "provider stream inactivity"
|
|
10557
|
+
};
|
|
10558
|
+
/** Watchdog operation names that count as provider-stream failures. */
|
|
10559
|
+
const PROVIDER_WATCHDOG_OPERATION_SET = new Set(Object.values(PROVIDER_WATCHDOG_OPERATIONS));
|
|
10560
|
+
const RETRY_DEFAULTS = {
|
|
10561
|
+
maxAttempts: 3,
|
|
10562
|
+
initialDelayMs: 1e3,
|
|
10563
|
+
maxDelayMs: 3e4
|
|
10564
|
+
};
|
|
10565
|
+
/**
|
|
10566
|
+
* Normalize a user-supplied `RetryConfig` (any field may be missing or invalid)
|
|
10567
|
+
* into a fully-populated config the retry loop can use without per-field guards.
|
|
10568
|
+
*
|
|
10569
|
+
* Invalid values (non-finite, < 1 for `maxAttempts`, < 0 for delays) fall back
|
|
10570
|
+
* to defaults rather than throwing — this is a behavior knob, not a validation
|
|
10571
|
+
* boundary, and a bad value here shouldn't crash a run.
|
|
10572
|
+
*/
|
|
10573
|
+
function resolveRetryConfig(cfg) {
|
|
10574
|
+
return {
|
|
10575
|
+
maxAttempts: Number.isFinite(cfg?.maxAttempts) && cfg.maxAttempts >= 1 ? Math.floor(cfg.maxAttempts) : RETRY_DEFAULTS.maxAttempts,
|
|
10576
|
+
initialDelayMs: Number.isFinite(cfg?.initialDelayMs) && cfg.initialDelayMs >= 0 ? cfg.initialDelayMs : RETRY_DEFAULTS.initialDelayMs,
|
|
10577
|
+
maxDelayMs: Number.isFinite(cfg?.maxDelayMs) && cfg.maxDelayMs >= 0 ? cfg.maxDelayMs : RETRY_DEFAULTS.maxDelayMs
|
|
10578
|
+
};
|
|
10579
|
+
}
|
|
10580
|
+
/**
|
|
10581
|
+
* Classify a failed stream attempt.
|
|
10582
|
+
*
|
|
10583
|
+
* Retry eligibility covers two sources: an error the provider's own classifier
|
|
10584
|
+
* marked retryable, and a provider-stream watchdog timeout. The latter is
|
|
10585
|
+
* retryable BY CONSTRUCTION for the first-response watchdog — zero observable
|
|
10586
|
+
* events arrived, so re-issuing is at least as safe as the mid-stream
|
|
10587
|
+
* `overloaded_error` retries the classifier opts into. The total-stream and
|
|
10588
|
+
* inactivity watchdogs ride the same carve-out but lean on `cleanSlate` for
|
|
10589
|
+
* their safety.
|
|
10590
|
+
*
|
|
10591
|
+
* Fallback excludes two classifications:
|
|
10592
|
+
* - `context_exceeded` — owned by overflow recovery; the transcript is the
|
|
10593
|
+
* problem, not the provider.
|
|
10594
|
+
* - `tool_pairing_corruption` — transcript-level corruption fails identically
|
|
10595
|
+
* on every provider.
|
|
10596
|
+
*
|
|
10597
|
+
* Everything else (rate limit, overload, 5xx, auth/billing, even unclassified
|
|
10598
|
+
* network failures) is provider-side: a sibling target may well succeed, and a
|
|
10599
|
+
* genuinely broken request just exhausts the chain and surfaces the last error.
|
|
10600
|
+
*/
|
|
10601
|
+
function assessStreamFailure(input) {
|
|
10602
|
+
const { err, runAborted, classifyError, progress, attempt, retry, hasNextTarget } = input;
|
|
10603
|
+
const wasAborted = runAborted || err instanceof Error && err.name === "AbortError";
|
|
10604
|
+
const classified = !wasAborted ? classifyError?.(err) ?? null : null;
|
|
10605
|
+
const cleanSlate = progress.text === "" && progress.thinking === "" && !progress.serverToolActivity;
|
|
10606
|
+
const isRetryable = classified?.kind === "provider_error" && classified.retryable === true;
|
|
10607
|
+
const isStreamWatchdogTimeout = !wasAborted && err instanceof OperationTimeoutError && PROVIDER_WATCHDOG_OPERATION_SET.has(err.operation);
|
|
10608
|
+
const canRetry = !wasAborted && (isRetryable || isStreamWatchdogTimeout) && cleanSlate && attempt < retry.maxAttempts;
|
|
10609
|
+
const retryAfterMs = canRetry ? extractRetryAfterMs(err) : void 0;
|
|
10610
|
+
return {
|
|
10611
|
+
wasAborted,
|
|
10612
|
+
classified,
|
|
10613
|
+
cleanSlate,
|
|
10614
|
+
retryAfterMs,
|
|
10615
|
+
canRetry,
|
|
10616
|
+
preferFallbackOverRetry: retryAfterMs !== void 0 && retryAfterMs > 15e3 && hasNextTarget,
|
|
10617
|
+
canRecoverOverflow: !wasAborted && classified?.kind === "context_exceeded" && cleanSlate,
|
|
10618
|
+
canFallback: !wasAborted && cleanSlate && hasNextTarget && classified?.kind !== "context_exceeded" && classified?.kind !== "tool_pairing_corruption"
|
|
10619
|
+
};
|
|
10620
|
+
}
|
|
10621
|
+
/**
|
|
10622
|
+
* Backoff delay for the next attempt.
|
|
10623
|
+
*
|
|
10624
|
+
* A server-declared `retry-after` wins (capped at `maxDelayMs`); otherwise
|
|
10625
|
+
* full-jitter exponential backoff — a uniform draw from `[0, capped)` rather
|
|
10626
|
+
* than a fixed `capped`, so a fleet of clients retrying the same overloaded
|
|
10627
|
+
* endpoint spreads out instead of stampeding in lockstep.
|
|
10628
|
+
*/
|
|
10629
|
+
function computeRetryDelayMs(attempt, cfg, retryAfterMs) {
|
|
10630
|
+
if (retryAfterMs !== void 0 && retryAfterMs >= 0) return Math.min(retryAfterMs, cfg.maxDelayMs);
|
|
10631
|
+
const exponential = cfg.initialDelayMs * 2 ** (attempt - 1);
|
|
10632
|
+
const capped = Math.min(exponential, cfg.maxDelayMs);
|
|
10633
|
+
return Math.floor(Math.random() * capped);
|
|
10634
|
+
}
|
|
10635
|
+
/**
|
|
10636
|
+
* Extract a `retry-after` value (in milliseconds) from an error's `.headers`, if any.
|
|
10637
|
+
*
|
|
10638
|
+
* Supports both `retry-after-ms` (non-standard but Stainless-emitted; already in ms,
|
|
10639
|
+
* always integer) and the standard `retry-after` header (integer seconds, RFC 7231).
|
|
10640
|
+
* Returns `undefined` when neither is present, non-numeric, or negative.
|
|
10641
|
+
*
|
|
10642
|
+
* `parseInt` over `parseFloat` here matches the actual contract — Stainless emits
|
|
10643
|
+
* `retry-after-ms` as an integer and RFC 7231 specifies a non-negative integer for
|
|
10644
|
+
* the seconds form. The HTTP-date form of `retry-after` is deliberately unsupported
|
|
10645
|
+
* (Anthropic + OpenAI both emit numeric seconds; supporting dates invites clock-skew
|
|
10646
|
+
* concerns for negligible benefit).
|
|
10647
|
+
*/
|
|
10648
|
+
function extractRetryAfterMs(err) {
|
|
10649
|
+
if (!err || typeof err !== "object") return void 0;
|
|
10650
|
+
const headers = err.headers;
|
|
10651
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
10652
|
+
const get = (key) => {
|
|
10653
|
+
const h = headers;
|
|
10654
|
+
if (typeof h.get === "function") {
|
|
10655
|
+
const v = h.get(key);
|
|
10656
|
+
return typeof v === "string" ? v : void 0;
|
|
10657
|
+
}
|
|
10658
|
+
const v = h[key];
|
|
10659
|
+
return typeof v === "string" ? v : void 0;
|
|
10660
|
+
};
|
|
10661
|
+
const ms = get("retry-after-ms");
|
|
10662
|
+
if (ms !== void 0) {
|
|
10663
|
+
const parsed = Number.parseInt(ms, 10);
|
|
10664
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed;
|
|
10665
|
+
}
|
|
10666
|
+
const seconds = get("retry-after");
|
|
10667
|
+
if (seconds !== void 0) {
|
|
10668
|
+
const parsed = Number.parseInt(seconds, 10);
|
|
10669
|
+
if (Number.isFinite(parsed) && parsed >= 0) return parsed * 1e3;
|
|
10670
|
+
}
|
|
10671
|
+
}
|
|
10672
|
+
//#endregion
|
|
10545
10673
|
//#region src/loop.ts
|
|
10546
10674
|
const DEFAULT_PROVIDER_STREAM_START_TIMEOUT_MS = 300 * 1e3;
|
|
10547
10675
|
const DEFAULT_PROVIDER_STREAM_TIMEOUT_MS = 1800 * 1e3;
|
|
@@ -10553,7 +10681,7 @@ const DEFAULT_PROVIDER_STREAM_TIMEOUT_MS = 1800 * 1e3;
|
|
|
10553
10681
|
*/
|
|
10554
10682
|
const DEFAULT_HOOK_TIMEOUT_MS = 300 * 1e3;
|
|
10555
10683
|
function hookTimeoutMsFor(ctx) {
|
|
10556
|
-
return resolveTimeoutMs(ctx.hookTimeoutMs, DEFAULT_HOOK_TIMEOUT_MS);
|
|
10684
|
+
return resolveTimeoutMs(ctx.behavior.hookTimeoutMs, DEFAULT_HOOK_TIMEOUT_MS);
|
|
10557
10685
|
}
|
|
10558
10686
|
/**
|
|
10559
10687
|
* Dispatch an already-invoked hook promise under {@link LoopContext.hookTimeoutMs},
|
|
@@ -11349,12 +11477,12 @@ function applyPairingRepair(ctx, messages, turnId) {
|
|
|
11349
11477
|
const repairs = [];
|
|
11350
11478
|
const repaired = ensureToolResultPairing(messages, { onRepair: (repair) => repairs.push(repair) });
|
|
11351
11479
|
if (repairs.length === 0) return repaired;
|
|
11352
|
-
if (ctx.strictToolPairing) throw new AgentToolPairingError({
|
|
11480
|
+
if (ctx.behavior.strictToolPairing) throw new AgentToolPairingError({
|
|
11353
11481
|
message: `Tool pairing corruption detected (${repairs.length} repair${repairs.length === 1 ? "" : "s"}); strict mode is on so the request was not sent.`,
|
|
11354
11482
|
...ctx.providerName ? { provider: ctx.providerName } : {},
|
|
11355
11483
|
repairs
|
|
11356
11484
|
});
|
|
11357
|
-
const rawLimit = ctx.maxPairingRepairsPerTurn;
|
|
11485
|
+
const rawLimit = ctx.behavior.maxPairingRepairsPerTurn;
|
|
11358
11486
|
const limit = typeof rawLimit === "number" && Number.isFinite(rawLimit) && rawLimit > 0 ? rawLimit : Number.POSITIVE_INFINITY;
|
|
11359
11487
|
if (repairs.length > limit) throw new AgentToolPairingError({
|
|
11360
11488
|
message: `Pairing-repair storm: ${repairs.length} repairs in a single turn (limit ${limit}). The transcript is systematically corrupt (likely duplicate tool_use ids from the provider); continuing would loop without forward progress.`,
|
|
@@ -11420,19 +11548,19 @@ async function runLoop(ctx) {
|
|
|
11420
11548
|
let totalCacheCreation = 0;
|
|
11421
11549
|
const turnUsages = [];
|
|
11422
11550
|
const startTime = Date.now();
|
|
11423
|
-
const maxTurns = ctx.maxTurns ?? Number.POSITIVE_INFINITY;
|
|
11551
|
+
const maxTurns = ctx.behavior.maxTurns ?? Number.POSITIVE_INFINITY;
|
|
11424
11552
|
let turnsCompleted = 0;
|
|
11425
|
-
const pauseCap = ctx.maxConsecutivePauseTurns ?? 0;
|
|
11553
|
+
const pauseCap = ctx.behavior.maxConsecutivePauseTurns ?? 0;
|
|
11426
11554
|
let consecutiveEmptyPauseTurns = 0;
|
|
11427
|
-
const maxConsecutiveLengthResumes = ctx.maxConsecutiveLengthResumes ?? 8;
|
|
11555
|
+
const maxConsecutiveLengthResumes = ctx.behavior.maxConsecutiveLengthResumes ?? 8;
|
|
11428
11556
|
let consecutiveLengthResumes = 0;
|
|
11429
11557
|
const maxConsecutiveEmptyLengthResumes = 2;
|
|
11430
11558
|
let consecutiveEmptyLengthResumes = 0;
|
|
11431
|
-
const maxConsecutiveRefusalResumes = ctx.maxConsecutiveRefusalResumes ?? 3;
|
|
11559
|
+
const maxConsecutiveRefusalResumes = ctx.behavior.maxConsecutiveRefusalResumes ?? 3;
|
|
11432
11560
|
let consecutiveRefusalResumes = 0;
|
|
11433
|
-
const wallDeadlineActive = typeof ctx.maxWallMs === "number" && Number.isFinite(ctx.maxWallMs) && ctx.maxWallMs > 0;
|
|
11561
|
+
const wallDeadlineActive = typeof ctx.behavior.maxWallMs === "number" && Number.isFinite(ctx.behavior.maxWallMs) && ctx.behavior.maxWallMs > 0;
|
|
11434
11562
|
const wallStartMs = wallDeadlineActive ? await ctx.clock.now() : 0;
|
|
11435
|
-
const maxTurnsWarnAt = Number.isFinite(maxTurns) && typeof ctx.maxTurnsWarning === "number" && Number.isFinite(ctx.maxTurnsWarning) && ctx.maxTurnsWarning > 0 && ctx.maxTurnsWarning < maxTurns ? Math.floor(ctx.maxTurnsWarning) : void 0;
|
|
11563
|
+
const maxTurnsWarnAt = Number.isFinite(maxTurns) && typeof ctx.behavior.maxTurnsWarning === "number" && Number.isFinite(ctx.behavior.maxTurnsWarning) && ctx.behavior.maxTurnsWarning > 0 && ctx.behavior.maxTurnsWarning < maxTurns ? Math.floor(ctx.behavior.maxTurnsWarning) : void 0;
|
|
11436
11564
|
let maxTurnsWarned = false;
|
|
11437
11565
|
const ttft = { mark: void 0 };
|
|
11438
11566
|
const markTtft = () => {
|
|
@@ -11504,9 +11632,9 @@ async function runLoop(ctx) {
|
|
|
11504
11632
|
break;
|
|
11505
11633
|
}
|
|
11506
11634
|
const breach = checkRunBudget({
|
|
11507
|
-
maxCostUsd: ctx.maxCostUsd,
|
|
11508
|
-
maxTotalTokens: ctx.maxTotalTokens,
|
|
11509
|
-
maxWallMs: ctx.maxWallMs,
|
|
11635
|
+
maxCostUsd: ctx.behavior.maxCostUsd,
|
|
11636
|
+
maxTotalTokens: ctx.behavior.maxTotalTokens,
|
|
11637
|
+
maxWallMs: ctx.behavior.maxWallMs,
|
|
11510
11638
|
cost: turnUsages.reduce((s, t) => s + (t.cost ?? 0), 0),
|
|
11511
11639
|
tokens: totalIn + totalOut,
|
|
11512
11640
|
elapsedMs: wallDeadlineActive ? await ctx.clock.now() - wallStartMs : 0
|
|
@@ -11542,7 +11670,7 @@ async function runLoop(ctx) {
|
|
|
11542
11670
|
if (!result.ended && !maxTurnsWarned && maxTurnsWarnAt !== void 0 && maxTurns - (turn + 1) <= maxTurnsWarnAt) {
|
|
11543
11671
|
maxTurnsWarned = true;
|
|
11544
11672
|
const remaining = maxTurns - (turn + 1);
|
|
11545
|
-
const warning = formatMaxTurnsWarning(ctx.maxTurnsWarningMessage, {
|
|
11673
|
+
const warning = formatMaxTurnsWarning(ctx.behavior.maxTurnsWarningMessage, {
|
|
11546
11674
|
remaining,
|
|
11547
11675
|
maxTurns
|
|
11548
11676
|
});
|
|
@@ -11584,7 +11712,7 @@ async function runLoop(ctx) {
|
|
|
11584
11712
|
}
|
|
11585
11713
|
}
|
|
11586
11714
|
let exhaustedOutput;
|
|
11587
|
-
if (ctx.schema && !ctx.signal.aborted && turnsCompleted > 0) {
|
|
11715
|
+
if (ctx.behavior.schema && !ctx.signal.aborted && turnsCompleted > 0) {
|
|
11588
11716
|
const enforcement = await enforceSchemaOutput(ctx, ctx.clock.randomUUID());
|
|
11589
11717
|
exhaustedOutput = enforcement.output;
|
|
11590
11718
|
totalIn += enforcement.usage.input;
|
|
@@ -11715,7 +11843,7 @@ async function enforceSchemaOutput(ctx, turnId) {
|
|
|
11715
11843
|
const outputSpec = {
|
|
11716
11844
|
name: "__output__",
|
|
11717
11845
|
description: "Return the final structured output matching the required schema.",
|
|
11718
|
-
inputSchema: ctx.schema
|
|
11846
|
+
inputSchema: ctx.behavior.schema
|
|
11719
11847
|
};
|
|
11720
11848
|
const schemaMessages = ensureEndsWithUserMessage(applyPairingRepair(ctx, rewriteMessagesToWire(await resolveContentRefsForWire(ctx, turnsToMessages(applyCompactSummaryCutoff(ctx.turns))), ctx.aliasMaps), turnId), ctx.provider);
|
|
11721
11849
|
let schemaResult;
|
|
@@ -11725,8 +11853,8 @@ async function enforceSchemaOutput(ctx, turnId) {
|
|
|
11725
11853
|
system: ctx.system,
|
|
11726
11854
|
tools: ctx.provider.formatTools([outputSpec]),
|
|
11727
11855
|
messages: schemaMessages,
|
|
11728
|
-
maxTokens: ctx.maxTokens,
|
|
11729
|
-
...ctx.modelCatalog ? { modelCatalog: ctx.modelCatalog } : {},
|
|
11856
|
+
maxTokens: ctx.behavior.maxTokens,
|
|
11857
|
+
...ctx.behavior.modelCatalog ? { modelCatalog: ctx.behavior.modelCatalog } : {},
|
|
11730
11858
|
toolChoice: {
|
|
11731
11859
|
type: "tool",
|
|
11732
11860
|
name: "__output__"
|
|
@@ -11743,7 +11871,7 @@ async function enforceSchemaOutput(ctx, turnId) {
|
|
|
11743
11871
|
const output = schemaResult.toolCalls.find((tc) => tc.name === "__output__")?.input;
|
|
11744
11872
|
if (output) await ctx.hooks.callHook("output", {
|
|
11745
11873
|
output,
|
|
11746
|
-
schema: ctx.schema
|
|
11874
|
+
schema: ctx.behavior.schema
|
|
11747
11875
|
});
|
|
11748
11876
|
const schemaTurn = {
|
|
11749
11877
|
id: ctx.clock.randomUUID(),
|
|
@@ -11820,17 +11948,11 @@ function wrapProviderError(err, ctx) {
|
|
|
11820
11948
|
* classifier so the retry carve-out can't silently detach from the errors
|
|
11821
11949
|
* it targets when a label is renamed.
|
|
11822
11950
|
*/
|
|
11823
|
-
const PROVIDER_WATCHDOG_OPERATIONS = {
|
|
11824
|
-
"first response": "provider first response",
|
|
11825
|
-
"total stream": "provider total stream",
|
|
11826
|
-
"stream inactivity": "provider stream inactivity"
|
|
11827
|
-
};
|
|
11828
|
-
const PROVIDER_WATCHDOG_OPERATION_SET = new Set(Object.values(PROVIDER_WATCHDOG_OPERATIONS));
|
|
11829
11951
|
function providerWatchdogTimeouts(ctx) {
|
|
11830
11952
|
return {
|
|
11831
|
-
startTimeoutMs: resolveTimeoutMs(ctx.providerStreamStartTimeoutMs, DEFAULT_PROVIDER_STREAM_START_TIMEOUT_MS, ctx.maxWallMs),
|
|
11832
|
-
totalTimeoutMs: resolveTimeoutMs(ctx.providerStreamTimeoutMs, DEFAULT_PROVIDER_STREAM_TIMEOUT_MS, ctx.maxWallMs),
|
|
11833
|
-
idleTimeoutMs: resolveTimeoutMs(ctx.providerStreamIdleTimeoutMs, 0, ctx.maxWallMs)
|
|
11953
|
+
startTimeoutMs: resolveTimeoutMs(ctx.behavior.providerStreamStartTimeoutMs, DEFAULT_PROVIDER_STREAM_START_TIMEOUT_MS, ctx.behavior.maxWallMs),
|
|
11954
|
+
totalTimeoutMs: resolveTimeoutMs(ctx.behavior.providerStreamTimeoutMs, DEFAULT_PROVIDER_STREAM_TIMEOUT_MS, ctx.behavior.maxWallMs),
|
|
11955
|
+
idleTimeoutMs: resolveTimeoutMs(ctx.behavior.providerStreamIdleTimeoutMs, 0, ctx.behavior.maxWallMs)
|
|
11834
11956
|
};
|
|
11835
11957
|
}
|
|
11836
11958
|
function stripInvalidAnthropicThinking(content) {
|
|
@@ -12140,11 +12262,6 @@ function extractStreamErrorMeta(err) {
|
|
|
12140
12262
|
return out;
|
|
12141
12263
|
}
|
|
12142
12264
|
/** Defaults applied when `behavior.retry` is absent or has missing fields. */
|
|
12143
|
-
const RETRY_DEFAULTS = {
|
|
12144
|
-
maxAttempts: 3,
|
|
12145
|
-
initialDelayMs: 1e3,
|
|
12146
|
-
maxDelayMs: 3e4
|
|
12147
|
-
};
|
|
12148
12265
|
/**
|
|
12149
12266
|
* First-response watchdog cap for RETRY attempts (attempt ≥ 2). The first
|
|
12150
12267
|
* attempt gets the full `providerStreamStartTimeoutMs` window (large-prompt
|
|
@@ -12277,7 +12394,7 @@ async function maybeAutoCompact(ctx, turn, lastTurnUsage, state) {
|
|
|
12277
12394
|
keepTurns: cfg.keepTurns,
|
|
12278
12395
|
signal: ctx.signal,
|
|
12279
12396
|
onProgress,
|
|
12280
|
-
...ctx.providerStreamTimeoutMs !== void 0 ? { providerStreamTimeoutMs: ctx.providerStreamTimeoutMs } : {}
|
|
12397
|
+
...ctx.behavior.providerStreamTimeoutMs !== void 0 ? { providerStreamTimeoutMs: ctx.behavior.providerStreamTimeoutMs } : {}
|
|
12281
12398
|
});
|
|
12282
12399
|
const summaryTurn = summaryToTurn({
|
|
12283
12400
|
summary: result.summary,
|
|
@@ -12310,8 +12427,8 @@ async function maybeAutoCompact(ctx, turn, lastTurnUsage, state) {
|
|
|
12310
12427
|
}
|
|
12311
12428
|
ctx.turns.push(summaryTurn, ...restorationTurns);
|
|
12312
12429
|
await ctx.persistTurns?.();
|
|
12313
|
-
if (cfg.releaseReplacedTurns && ctx.persistDir && result.summarizedTurnIds.length > 0) try {
|
|
12314
|
-
await releaseReplacedTurnContent(ctx.turns, new Set(result.summarizedTurnIds), { persistDir: ctx.persistDir });
|
|
12430
|
+
if (cfg.releaseReplacedTurns && ctx.behavior.persistDir && result.summarizedTurnIds.length > 0) try {
|
|
12431
|
+
await releaseReplacedTurnContent(ctx.turns, new Set(result.summarizedTurnIds), { persistDir: ctx.behavior.persistDir });
|
|
12315
12432
|
} catch (err) {
|
|
12316
12433
|
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/loop] post-compact turn release failed: ${errorMessage(err)}\n`);
|
|
12317
12434
|
}
|
|
@@ -12348,87 +12465,6 @@ async function maybeAutoCompact(ctx, turn, lastTurnUsage, state) {
|
|
|
12348
12465
|
}
|
|
12349
12466
|
}
|
|
12350
12467
|
/**
|
|
12351
|
-
* Normalize a user-supplied `RetryConfig` (any field may be missing or invalid)
|
|
12352
|
-
* into a fully-populated config the retry loop can use without per-field guards.
|
|
12353
|
-
*
|
|
12354
|
-
* Invalid values (non-finite, < 1 for `maxAttempts`, < 0 for delays) fall back
|
|
12355
|
-
* to defaults rather than throwing — this is a behavior knob, not a validation
|
|
12356
|
-
* boundary, and a bad value here shouldn't crash a run.
|
|
12357
|
-
*/
|
|
12358
|
-
function resolveRetryConfig(cfg) {
|
|
12359
|
-
return {
|
|
12360
|
-
maxAttempts: Number.isFinite(cfg?.maxAttempts) && cfg.maxAttempts >= 1 ? Math.floor(cfg.maxAttempts) : RETRY_DEFAULTS.maxAttempts,
|
|
12361
|
-
initialDelayMs: Number.isFinite(cfg?.initialDelayMs) && cfg.initialDelayMs >= 0 ? cfg.initialDelayMs : RETRY_DEFAULTS.initialDelayMs,
|
|
12362
|
-
maxDelayMs: Number.isFinite(cfg?.maxDelayMs) && cfg.maxDelayMs >= 0 ? cfg.maxDelayMs : RETRY_DEFAULTS.maxDelayMs
|
|
12363
|
-
};
|
|
12364
|
-
}
|
|
12365
|
-
/**
|
|
12366
|
-
* Compute the backoff delay for the upcoming retry.
|
|
12367
|
-
*
|
|
12368
|
-
* Strategy:
|
|
12369
|
-
* - If the server returned `retry-after` / `retry-after-ms`, honor it (capped at `maxDelayMs`).
|
|
12370
|
-
* - Otherwise: `initialDelayMs * 2^(attempt-1)`, capped at `maxDelayMs`, then "full jitter"
|
|
12371
|
-
* (`Math.random() * computed`). Full jitter scatters retries from concurrent clients
|
|
12372
|
-
* across the whole window — empirically better than fixed exponential under thundering-herd
|
|
12373
|
-
* (per AWS Architecture Blog's analysis of EBO+jitter strategies).
|
|
12374
|
-
*
|
|
12375
|
-
* `attempt` is the 1-indexed number of the attempt that just *failed*, so the first
|
|
12376
|
-
* post-failure delay uses `attempt=1` → `initialDelayMs * 1` before jitter.
|
|
12377
|
-
*/
|
|
12378
|
-
function computeRetryDelayMs(attempt, cfg, retryAfterMs) {
|
|
12379
|
-
if (retryAfterMs !== void 0 && retryAfterMs >= 0) return Math.min(retryAfterMs, cfg.maxDelayMs);
|
|
12380
|
-
const exponential = cfg.initialDelayMs * 2 ** (attempt - 1);
|
|
12381
|
-
const capped = Math.min(exponential, cfg.maxDelayMs);
|
|
12382
|
-
return Math.floor(Math.random() * capped);
|
|
12383
|
-
}
|
|
12384
|
-
/**
|
|
12385
|
-
* Extract a `retry-after` value (in milliseconds) from an error's `.headers`, if any.
|
|
12386
|
-
*
|
|
12387
|
-
* Supports both `retry-after-ms` (non-standard but Stainless-emitted; already in ms,
|
|
12388
|
-
* always integer) and the standard `retry-after` header (integer seconds, RFC 7231).
|
|
12389
|
-
* Returns `undefined` when neither is present, non-numeric, or negative.
|
|
12390
|
-
*
|
|
12391
|
-
* `parseInt` over `parseFloat` here matches the actual contract — Stainless emits
|
|
12392
|
-
* `retry-after-ms` as an integer and RFC 7231 specifies a non-negative integer for
|
|
12393
|
-
* the seconds form. The HTTP-date form of `retry-after` is deliberately unsupported
|
|
12394
|
-
* (Anthropic + OpenAI both emit numeric seconds; supporting dates invites clock-skew
|
|
12395
|
-
* concerns for negligible benefit).
|
|
12396
|
-
*/
|
|
12397
|
-
/**
|
|
12398
|
-
* Server-declared `retry-after` above this is treated as "not a transient
|
|
12399
|
-
* blip" by the fallback machinery: burst rate limits announce seconds,
|
|
12400
|
-
* quota/usage exhaustion announces minutes-to-hours. A run holding more
|
|
12401
|
-
* fallback targets fails over immediately instead of burning its retry
|
|
12402
|
-
* budget against a wall that won't move within the wait window; a
|
|
12403
|
-
* single-target run still waits (capped at `maxDelayMs`) because waiting
|
|
12404
|
-
* is its only option.
|
|
12405
|
-
*/
|
|
12406
|
-
const LONG_RETRY_AFTER_FALLBACK_MS = 15e3;
|
|
12407
|
-
function extractRetryAfterMs(err) {
|
|
12408
|
-
if (!err || typeof err !== "object") return void 0;
|
|
12409
|
-
const headers = err.headers;
|
|
12410
|
-
if (!headers || typeof headers !== "object") return void 0;
|
|
12411
|
-
const get = (key) => {
|
|
12412
|
-
const h = headers;
|
|
12413
|
-
if (typeof h.get === "function") {
|
|
12414
|
-
const v = h.get(key);
|
|
12415
|
-
return typeof v === "string" ? v : void 0;
|
|
12416
|
-
}
|
|
12417
|
-
const v = h[key];
|
|
12418
|
-
return typeof v === "string" ? v : void 0;
|
|
12419
|
-
};
|
|
12420
|
-
const ms = get("retry-after-ms");
|
|
12421
|
-
if (ms !== void 0) {
|
|
12422
|
-
const parsed = Number.parseInt(ms, 10);
|
|
12423
|
-
if (Number.isFinite(parsed) && parsed >= 0) return parsed;
|
|
12424
|
-
}
|
|
12425
|
-
const seconds = get("retry-after");
|
|
12426
|
-
if (seconds !== void 0) {
|
|
12427
|
-
const parsed = Number.parseInt(seconds, 10);
|
|
12428
|
-
if (Number.isFinite(parsed) && parsed >= 0) return parsed * 1e3;
|
|
12429
|
-
}
|
|
12430
|
-
}
|
|
12431
|
-
/**
|
|
12432
12468
|
* `setTimeout` that rejects if the given signal aborts before the timer fires.
|
|
12433
12469
|
*
|
|
12434
12470
|
* Resolves with `undefined` on normal completion. Rejects with the signal's
|
|
@@ -12451,11 +12487,60 @@ function abortableSleep(ms, signal) {
|
|
|
12451
12487
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
12452
12488
|
});
|
|
12453
12489
|
}
|
|
12490
|
+
/**
|
|
12491
|
+
* Advance the run to the next provider+model target and rebind the prepared
|
|
12492
|
+
* request to it.
|
|
12493
|
+
*
|
|
12494
|
+
* Caller contract: only invoke when `assessStreamFailure` returned
|
|
12495
|
+
* `canFallback` — that verdict guarantees an untried target exists, so the
|
|
12496
|
+
* index arithmetic here needs no bounds check of its own.
|
|
12497
|
+
*
|
|
12498
|
+
* Run-sticky: `activeTargetIndex` only advances, so later turns of this run
|
|
12499
|
+
* stay on the fallback target. The next `run()` resolves a fresh target list
|
|
12500
|
+
* starting from the primary.
|
|
12501
|
+
*/
|
|
12502
|
+
async function advanceToFallbackTarget(ctx, streamOptions, turnId, err) {
|
|
12503
|
+
const targets = ctx.targets;
|
|
12504
|
+
const fromIndex = ctx.activeTargetIndex ?? 0;
|
|
12505
|
+
const nextIndex = fromIndex + 1;
|
|
12506
|
+
const from = targets[fromIndex];
|
|
12507
|
+
const to = targets[nextIndex];
|
|
12508
|
+
ctx.activeTargetIndex = nextIndex;
|
|
12509
|
+
ctx.provider = to.provider;
|
|
12510
|
+
ctx.model = to.model;
|
|
12511
|
+
ctx.providerName = to.provider.name;
|
|
12512
|
+
if (ctx.rebuildFormattedTools) ctx.formattedTools = ctx.rebuildFormattedTools(to.provider);
|
|
12513
|
+
(ctx.targetFailures ??= []).push({
|
|
12514
|
+
provider: from.provider.name,
|
|
12515
|
+
model: from.model,
|
|
12516
|
+
err
|
|
12517
|
+
});
|
|
12518
|
+
if (ctx.autoCompact) {
|
|
12519
|
+
const nextWindow = to.contextWindow ?? (ctx.autoCompact.contextWindowFromProviderMeta ? to.provider.meta.contextWindow : void 0);
|
|
12520
|
+
if (nextWindow !== void 0 && Number.isFinite(nextWindow) && nextWindow > 0) ctx.autoCompact.contextWindow = nextWindow;
|
|
12521
|
+
}
|
|
12522
|
+
streamOptions.model = to.model;
|
|
12523
|
+
streamOptions.tools = ctx.formattedTools;
|
|
12524
|
+
streamOptions.messages = sanitizeStoredToolResults(to.provider, streamOptions.messages);
|
|
12525
|
+
await settledHook(ctx, "hook model:fallback", ctx.hooks.callHook("model:fallback", {
|
|
12526
|
+
turnId,
|
|
12527
|
+
from: {
|
|
12528
|
+
provider: from.provider.name,
|
|
12529
|
+
model: from.model
|
|
12530
|
+
},
|
|
12531
|
+
to: {
|
|
12532
|
+
provider: to.provider.name,
|
|
12533
|
+
model: to.model
|
|
12534
|
+
},
|
|
12535
|
+
targetIndex: nextIndex,
|
|
12536
|
+
err
|
|
12537
|
+
}));
|
|
12538
|
+
}
|
|
12454
12539
|
async function executeTurn(ctx, turn, priorUsage) {
|
|
12455
12540
|
const turnId = ctx.clock.randomUUID();
|
|
12456
12541
|
let canonicalMessages = turnsToMessages(applyCompactSummaryCutoff(ctx.turns));
|
|
12457
12542
|
canonicalMessages = await resolveContentRefsForWire(ctx, canonicalMessages);
|
|
12458
|
-
if (ctx.elideStaleReads === true || ctx.elideStaleReads === "stub") {
|
|
12543
|
+
if (ctx.behavior.elideStaleReads === true || ctx.behavior.elideStaleReads === "stub") {
|
|
12459
12544
|
/**
|
|
12460
12545
|
* Deliberately UNQUANTIZED, unlike tail compaction and media age-out below.
|
|
12461
12546
|
*
|
|
@@ -12483,30 +12568,30 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12483
12568
|
let sanitizedMessages = sanitizeStoredToolResults(ctx.provider, wireMessages);
|
|
12484
12569
|
let callMapsMemo;
|
|
12485
12570
|
const callMaps = () => callMapsMemo ??= collectCallMaps(canonicalMessages);
|
|
12486
|
-
if (ctx.compactStrategy === "tail") {
|
|
12487
|
-
const threshold = typeof ctx.compactThreshold === "number" && ctx.compactThreshold > 0 ? ctx.compactThreshold : 131072;
|
|
12488
|
-
const keep = typeof ctx.compactKeepTurns === "number" && ctx.compactKeepTurns >= 0 ? ctx.compactKeepTurns : 4;
|
|
12571
|
+
if (ctx.behavior.compactStrategy === "tail") {
|
|
12572
|
+
const threshold = typeof ctx.behavior.compactThreshold === "number" && ctx.behavior.compactThreshold > 0 ? ctx.behavior.compactThreshold : 131072;
|
|
12573
|
+
const keep = typeof ctx.behavior.compactKeepTurns === "number" && ctx.behavior.compactKeepTurns >= 0 ? ctx.behavior.compactKeepTurns : 4;
|
|
12489
12574
|
const { readPathByCallId, toolNameByCallId } = callMaps();
|
|
12490
12575
|
const compacted = applyTailCompaction(sanitizedMessages, threshold, keep, {
|
|
12491
12576
|
readPathByCallId,
|
|
12492
12577
|
toolNameByCallId,
|
|
12493
12578
|
chunkTurns: 8,
|
|
12494
|
-
persistElideMinBytes: ctx.persistDir ? PERSISTENCE_PREVIEW_BYTES : 0
|
|
12579
|
+
persistElideMinBytes: ctx.behavior.persistDir ? PERSISTENCE_PREVIEW_BYTES : 0
|
|
12495
12580
|
});
|
|
12496
12581
|
sanitizedMessages = compacted.messages;
|
|
12497
12582
|
markReadStateForElidedPaths(ctx, ctx.handle.cwd, compacted.elidedReadPaths);
|
|
12498
|
-
if (ctx.persistDir && compacted.persistableElided.length > 0) sanitizedMessages = await persistElidedToolResults(sanitizedMessages, compacted.persistableElided, {
|
|
12499
|
-
persistDir: ctx.persistDir,
|
|
12500
|
-
maxBytes: ctx.persistMaxBytes,
|
|
12583
|
+
if (ctx.behavior.persistDir && compacted.persistableElided.length > 0) sanitizedMessages = await persistElidedToolResults(sanitizedMessages, compacted.persistableElided, {
|
|
12584
|
+
persistDir: ctx.behavior.persistDir,
|
|
12585
|
+
maxBytes: ctx.behavior.persistMaxBytes,
|
|
12501
12586
|
writeBlob: executionBlobWriter(ctx)
|
|
12502
12587
|
});
|
|
12503
|
-
} else if (typeof ctx.compactStrategy === "function") {
|
|
12504
|
-
const threshold = typeof ctx.compactThreshold === "number" && ctx.compactThreshold > 0 ? ctx.compactThreshold : 131072;
|
|
12505
|
-
const keep = typeof ctx.compactKeepTurns === "number" && ctx.compactKeepTurns >= 0 ? ctx.compactKeepTurns : 4;
|
|
12588
|
+
} else if (typeof ctx.behavior.compactStrategy === "function") {
|
|
12589
|
+
const threshold = typeof ctx.behavior.compactThreshold === "number" && ctx.behavior.compactThreshold > 0 ? ctx.behavior.compactThreshold : 131072;
|
|
12590
|
+
const keep = typeof ctx.behavior.compactKeepTurns === "number" && ctx.behavior.compactKeepTurns >= 0 ? ctx.behavior.compactKeepTurns : 4;
|
|
12506
12591
|
let totalBytes = 0;
|
|
12507
12592
|
for (const msg of sanitizedMessages) for (const block of msg.content) if (block.type === "tool_result") totalBytes += memoizedToolResultBudgetBytes(block);
|
|
12508
12593
|
try {
|
|
12509
|
-
const compacted = await ctx.compactStrategy(sanitizedMessages, {
|
|
12594
|
+
const compacted = await ctx.behavior.compactStrategy(sanitizedMessages, {
|
|
12510
12595
|
threshold,
|
|
12511
12596
|
keepTurns: keep,
|
|
12512
12597
|
totalBytes
|
|
@@ -12516,9 +12601,9 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12516
12601
|
console.error("[zidane] compactStrategy function threw:", err);
|
|
12517
12602
|
}
|
|
12518
12603
|
}
|
|
12519
|
-
if (typeof ctx.mediaKeepTurns === "number" && ctx.mediaKeepTurns >= 0 && ctx.tools.read_file) {
|
|
12604
|
+
if (typeof ctx.behavior.mediaKeepTurns === "number" && ctx.behavior.mediaKeepTurns >= 0 && ctx.tools.read_file) {
|
|
12520
12605
|
const { readPathByCallId } = callMaps();
|
|
12521
|
-
const aged = applyMediaAgeout(sanitizedMessages, ctx.mediaKeepTurns, {
|
|
12606
|
+
const aged = applyMediaAgeout(sanitizedMessages, ctx.behavior.mediaKeepTurns, {
|
|
12522
12607
|
chunkTurns: 8,
|
|
12523
12608
|
readPathByCallId,
|
|
12524
12609
|
readFileToolName: toWireName("read_file", ctx.aliasMaps),
|
|
@@ -12527,22 +12612,22 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12527
12612
|
sanitizedMessages = aged.messages;
|
|
12528
12613
|
markReadStateForElidedPaths(ctx, ctx.handle.cwd, aged.elidedReadPaths);
|
|
12529
12614
|
}
|
|
12530
|
-
const effectiveThinkingBudget = ctx.thinking === "adaptive" && ctx.provider.meta.capabilities?.adaptiveBudgetIsEnvelope === true ? ctx.thinkingBudget : applyThinkingDecay(ctx.thinkingBudget, ctx.thinkingDecay, turn + 1);
|
|
12615
|
+
const effectiveThinkingBudget = ctx.thinking === "adaptive" && ctx.provider.meta.capabilities?.adaptiveBudgetIsEnvelope === true ? ctx.behavior.thinkingBudget : applyThinkingDecay(ctx.behavior.thinkingBudget, ctx.behavior.thinkingDecay, turn + 1);
|
|
12531
12616
|
const formattedTools = ctx.rebuildFormattedTools ? ctx.rebuildFormattedTools(ctx.provider) : ctx.formattedTools;
|
|
12532
12617
|
const streamOptions = {
|
|
12533
12618
|
model: ctx.model,
|
|
12534
12619
|
system: ctx.system,
|
|
12535
12620
|
tools: formattedTools,
|
|
12536
12621
|
messages: sanitizedMessages,
|
|
12537
|
-
maxTokens: ctx.maxTokens,
|
|
12538
|
-
...ctx.modelCatalog ? { modelCatalog: ctx.modelCatalog } : {},
|
|
12622
|
+
maxTokens: ctx.behavior.maxTokens,
|
|
12623
|
+
...ctx.behavior.modelCatalog ? { modelCatalog: ctx.behavior.modelCatalog } : {},
|
|
12539
12624
|
thinking: ctx.thinking,
|
|
12540
12625
|
thinkingBudget: effectiveThinkingBudget,
|
|
12541
|
-
...ctx.taskBudget !== void 0 ? { taskBudget: ctx.taskBudget } : {},
|
|
12542
|
-
...ctx.effortHint !== void 0 ? { effortHint: ctx.effortHint } : {},
|
|
12626
|
+
...ctx.behavior.taskBudget !== void 0 ? { taskBudget: ctx.behavior.taskBudget } : {},
|
|
12627
|
+
...ctx.behavior.effortHint !== void 0 ? { effortHint: ctx.behavior.effortHint } : {},
|
|
12543
12628
|
...ctx.modelOptions ? { modelOptions: ctx.modelOptions } : {},
|
|
12544
|
-
cache: ctx.cache ?? true,
|
|
12545
|
-
...ctx.cacheTtl !== void 0 ? { cacheTtl: ctx.cacheTtl } : {},
|
|
12629
|
+
cache: ctx.behavior.cache ?? true,
|
|
12630
|
+
...ctx.behavior.cacheTtl !== void 0 ? { cacheTtl: ctx.behavior.cacheTtl } : {},
|
|
12546
12631
|
signal: ctx.signal
|
|
12547
12632
|
};
|
|
12548
12633
|
const transformCtx = { messages: streamOptions.messages };
|
|
@@ -12585,7 +12670,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12585
12670
|
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/loop] stream hook handler threw: ${errorMessage(err)}\n`);
|
|
12586
12671
|
});
|
|
12587
12672
|
};
|
|
12588
|
-
const retryCfg = resolveRetryConfig(ctx.retry);
|
|
12673
|
+
const retryCfg = resolveRetryConfig(ctx.behavior.retry);
|
|
12589
12674
|
let result;
|
|
12590
12675
|
let attempt = 0;
|
|
12591
12676
|
let overflowRecoveries = 0;
|
|
@@ -12641,17 +12726,23 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12641
12726
|
break;
|
|
12642
12727
|
} catch (caught) {
|
|
12643
12728
|
let terminalErr = caught;
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12729
|
+
const failure = assessStreamFailure({
|
|
12730
|
+
err: caught,
|
|
12731
|
+
runAborted: ctx.signal.aborted,
|
|
12732
|
+
classifyError: ctx.provider.classifyError?.bind(ctx.provider),
|
|
12733
|
+
progress: {
|
|
12734
|
+
text: currentText,
|
|
12735
|
+
thinking: currentThinking,
|
|
12736
|
+
serverToolActivity
|
|
12737
|
+
},
|
|
12738
|
+
attempt,
|
|
12739
|
+
retry: retryCfg,
|
|
12740
|
+
hasNextTarget: ctx.targets !== void 0 && (ctx.activeTargetIndex ?? 0) + 1 < ctx.targets.length
|
|
12741
|
+
});
|
|
12742
|
+
let wasAborted = failure.wasAborted;
|
|
12743
|
+
if (failure.canRetry && !failure.preferFallbackOverRetry) {
|
|
12653
12744
|
const meta = extractStreamErrorMeta(caught);
|
|
12654
|
-
const delayMs = computeRetryDelayMs(attempt, retryCfg, retryAfterMs);
|
|
12745
|
+
const delayMs = computeRetryDelayMs(attempt, retryCfg, failure.retryAfterMs);
|
|
12655
12746
|
await settledHook(ctx, "hook stream:retry", ctx.hooks.callHook("stream:retry", {
|
|
12656
12747
|
turnId,
|
|
12657
12748
|
attempt,
|
|
@@ -12671,7 +12762,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12671
12762
|
wasAborted = true;
|
|
12672
12763
|
}
|
|
12673
12764
|
}
|
|
12674
|
-
if (!wasAborted &&
|
|
12765
|
+
if (!wasAborted && failure.canRecoverOverflow && overflowRecoveries < CONTEXT_OVERFLOW_KEEP_TURNS.length) {
|
|
12675
12766
|
const { readPathByCallId, toolNameByCallId } = callMaps();
|
|
12676
12767
|
let recoveredMessages;
|
|
12677
12768
|
const elidedReadPaths = [];
|
|
@@ -12708,45 +12799,10 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12708
12799
|
continue;
|
|
12709
12800
|
}
|
|
12710
12801
|
}
|
|
12711
|
-
if (!wasAborted &&
|
|
12712
|
-
|
|
12713
|
-
|
|
12714
|
-
|
|
12715
|
-
const from = ctx.targets[fromIndex];
|
|
12716
|
-
const to = ctx.targets[nextIndex];
|
|
12717
|
-
ctx.activeTargetIndex = nextIndex;
|
|
12718
|
-
ctx.provider = to.provider;
|
|
12719
|
-
ctx.model = to.model;
|
|
12720
|
-
ctx.providerName = to.provider.name;
|
|
12721
|
-
if (ctx.rebuildFormattedTools) ctx.formattedTools = ctx.rebuildFormattedTools(to.provider);
|
|
12722
|
-
(ctx.targetFailures ??= []).push({
|
|
12723
|
-
provider: from.provider.name,
|
|
12724
|
-
model: from.model,
|
|
12725
|
-
err: caught
|
|
12726
|
-
});
|
|
12727
|
-
if (ctx.autoCompact) {
|
|
12728
|
-
const nextWindow = to.contextWindow ?? (ctx.autoCompact.contextWindowFromProviderMeta ? to.provider.meta.contextWindow : void 0);
|
|
12729
|
-
if (typeof nextWindow === "number" && Number.isFinite(nextWindow) && nextWindow > 0) ctx.autoCompact.contextWindow = nextWindow;
|
|
12730
|
-
}
|
|
12731
|
-
streamOptions.model = to.model;
|
|
12732
|
-
streamOptions.tools = ctx.formattedTools;
|
|
12733
|
-
streamOptions.messages = sanitizeStoredToolResults(to.provider, streamOptions.messages);
|
|
12734
|
-
attempt = 0;
|
|
12735
|
-
await settledHook(ctx, "hook model:fallback", ctx.hooks.callHook("model:fallback", {
|
|
12736
|
-
turnId,
|
|
12737
|
-
from: {
|
|
12738
|
-
provider: from.provider.name,
|
|
12739
|
-
model: from.model
|
|
12740
|
-
},
|
|
12741
|
-
to: {
|
|
12742
|
-
provider: to.provider.name,
|
|
12743
|
-
model: to.model
|
|
12744
|
-
},
|
|
12745
|
-
targetIndex: nextIndex,
|
|
12746
|
-
err: caught
|
|
12747
|
-
}));
|
|
12748
|
-
continue;
|
|
12749
|
-
}
|
|
12802
|
+
if (!wasAborted && failure.canFallback) {
|
|
12803
|
+
await advanceToFallbackTarget(ctx, streamOptions, turnId, caught);
|
|
12804
|
+
attempt = 0;
|
|
12805
|
+
continue;
|
|
12750
12806
|
}
|
|
12751
12807
|
await streamHookChain;
|
|
12752
12808
|
const errorUsage = {
|
|
@@ -12801,7 +12857,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12801
12857
|
name: toCanonicalName(tc.name, ctx.aliasMaps)
|
|
12802
12858
|
}));
|
|
12803
12859
|
let canonicalContent = rewriteContentToCanonical(result.assistantMessage?.content ?? [], ctx.aliasMaps);
|
|
12804
|
-
if (canonicalToolCalls.length > 0 && !ctx.strictToolPairing) {
|
|
12860
|
+
if (canonicalToolCalls.length > 0 && !ctx.behavior.strictToolPairing) {
|
|
12805
12861
|
const priorIds = /* @__PURE__ */ new Set();
|
|
12806
12862
|
for (const t of ctx.turns) for (const block of t.content) if (block.type === "tool_call") priorIds.add(block.id);
|
|
12807
12863
|
const reminted = remintDuplicateToolCallIds(canonicalToolCalls, canonicalContent, priorIds);
|
|
@@ -12843,7 +12899,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12843
12899
|
},
|
|
12844
12900
|
cumulativeUsage: buildCumulativeUsage(priorUsage, result.usage)
|
|
12845
12901
|
}));
|
|
12846
|
-
if (ctx.resumeOnMaxTokens && (ctx.maxConsecutiveLengthResumes ?? 8) > 0 && result.usage.finishReason === "length" && canonicalToolCalls.length === 0 && !ctx.signal.aborted) {
|
|
12902
|
+
if (ctx.behavior.resumeOnMaxTokens && (ctx.behavior.maxConsecutiveLengthResumes ?? 8) > 0 && result.usage.finishReason === "length" && canonicalToolCalls.length === 0 && !ctx.signal.aborted) {
|
|
12847
12903
|
const continueMsg = ctx.provider.userMessage("Please continue.");
|
|
12848
12904
|
ctx.turns.push({
|
|
12849
12905
|
id: await ctx.generateTurnId(),
|
|
@@ -12860,7 +12916,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12860
12916
|
...currentText.length === 0 ? { lengthEmpty: true } : {}
|
|
12861
12917
|
};
|
|
12862
12918
|
}
|
|
12863
|
-
if (result.usage.finishReason === "content-filter" && canonicalToolCalls.length === 0 && !ctx.signal.aborted && (ctx.maxConsecutiveRefusalResumes ?? 3) > 0) {
|
|
12919
|
+
if (result.usage.finishReason === "content-filter" && canonicalToolCalls.length === 0 && !ctx.signal.aborted && (ctx.behavior.maxConsecutiveRefusalResumes ?? 3) > 0) {
|
|
12864
12920
|
const continueMsg = ctx.provider.userMessage("The previous response was interrupted by the provider (refusal stop). Please continue with the task.");
|
|
12865
12921
|
ctx.turns.push({
|
|
12866
12922
|
id: await ctx.generateTurnId(),
|
|
@@ -12878,7 +12934,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12878
12934
|
};
|
|
12879
12935
|
}
|
|
12880
12936
|
if (result.done) {
|
|
12881
|
-
if (ctx.schema && !ctx.signal.aborted) {
|
|
12937
|
+
if (ctx.behavior.schema && !ctx.signal.aborted) {
|
|
12882
12938
|
const enforcement = await enforceSchemaOutput(ctx, turnId);
|
|
12883
12939
|
const sumOptional = (a, b) => ({
|
|
12884
12940
|
has: a !== void 0 || b !== void 0,
|
|
@@ -12927,7 +12983,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12927
12983
|
};
|
|
12928
12984
|
}
|
|
12929
12985
|
const toolResults = await executeToolBatch(ctx, canonicalToolCalls, turnId);
|
|
12930
|
-
if (ctx.elideStaleReads === "notice") appendStaleReadNotices(ctx.turns, canonicalToolCalls, toolResults);
|
|
12986
|
+
if (ctx.behavior.elideStaleReads === "notice") appendStaleReadNotices(ctx.turns, canonicalToolCalls, toolResults);
|
|
12931
12987
|
const toolResultMsg = ctx.provider.toolResultsMessage(toolResults);
|
|
12932
12988
|
const toolResultsTurn = {
|
|
12933
12989
|
id: ctx.clock.randomUUID(),
|
|
@@ -12943,8 +12999,8 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12943
12999
|
message: toolResultsTurn,
|
|
12944
13000
|
results: toolResults
|
|
12945
13001
|
}));
|
|
12946
|
-
if (typeof ctx.toolOutputBudget === "number" && ctx.toolOutputBudget > 0) {
|
|
12947
|
-
const excludeSet = ctx.toolOutputBudgetExcludeTools && ctx.toolOutputBudgetExcludeTools.length > 0 ? new Set(ctx.toolOutputBudgetExcludeTools) : void 0;
|
|
13002
|
+
if (typeof ctx.behavior.toolOutputBudget === "number" && ctx.behavior.toolOutputBudget > 0) {
|
|
13003
|
+
const excludeSet = ctx.behavior.toolOutputBudgetExcludeTools && ctx.behavior.toolOutputBudgetExcludeTools.length > 0 ? new Set(ctx.behavior.toolOutputBudgetExcludeTools) : void 0;
|
|
12948
13004
|
const nameById = excludeSet ? new Map(canonicalToolCalls.map((c) => [c.id, c.name])) : void 0;
|
|
12949
13005
|
const totalBytes = toolResults.reduce((sum, r) => {
|
|
12950
13006
|
if (excludeSet && nameById) {
|
|
@@ -12953,8 +13009,8 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12953
13009
|
}
|
|
12954
13010
|
return sum + toolOutputBudgetByteLength(r.content);
|
|
12955
13011
|
}, 0);
|
|
12956
|
-
if (totalBytes > ctx.toolOutputBudget) {
|
|
12957
|
-
const warning = `[Tool output budget exceeded: ${totalBytes} text-equivalent bytes returned in this turn (cap: ${ctx.toolOutputBudget}). Summarize the salient findings before calling more tools.]`;
|
|
13012
|
+
if (totalBytes > ctx.behavior.toolOutputBudget) {
|
|
13013
|
+
const warning = `[Tool output budget exceeded: ${totalBytes} text-equivalent bytes returned in this turn (cap: ${ctx.behavior.toolOutputBudget}). Summarize the salient findings before calling more tools.]`;
|
|
12958
13014
|
const userMsg = ctx.provider.userMessage(warning);
|
|
12959
13015
|
ctx.turns.push({
|
|
12960
13016
|
id: await ctx.generateTurnId(),
|
|
@@ -12967,7 +13023,7 @@ async function executeTurn(ctx, turn, priorUsage) {
|
|
|
12967
13023
|
turn,
|
|
12968
13024
|
turnId,
|
|
12969
13025
|
bytes: totalBytes,
|
|
12970
|
-
budget: ctx.toolOutputBudget
|
|
13026
|
+
budget: ctx.behavior.toolOutputBudget
|
|
12971
13027
|
});
|
|
12972
13028
|
}
|
|
12973
13029
|
}
|
|
@@ -13042,7 +13098,7 @@ function sanitizeToolOutputForProvider(provider, output) {
|
|
|
13042
13098
|
* Empty object when the agent has no live connection.
|
|
13043
13099
|
*/
|
|
13044
13100
|
function mcpConnectionFor(ctx) {
|
|
13045
|
-
const connection = ctx.
|
|
13101
|
+
const connection = ctx.inheritance.mcpConnection?.();
|
|
13046
13102
|
if (!connection) return {};
|
|
13047
13103
|
return { mcpConnection: nonOwningMcpView(connection) };
|
|
13048
13104
|
}
|
|
@@ -13265,14 +13321,14 @@ async function runSingleToolDispatch(ctx, call, turnId, fixed) {
|
|
|
13265
13321
|
execution: ctx.execution,
|
|
13266
13322
|
handle: ctx.handle,
|
|
13267
13323
|
hooks: ctx.hooks,
|
|
13268
|
-
tools: ctx.
|
|
13269
|
-
...ctx.
|
|
13270
|
-
...ctx.
|
|
13271
|
-
...ctx.
|
|
13272
|
-
...ctx.
|
|
13324
|
+
tools: ctx.inheritance.tools,
|
|
13325
|
+
...ctx.inheritance.name !== void 0 ? { name: ctx.inheritance.name } : {},
|
|
13326
|
+
...ctx.inheritance.system !== void 0 ? { system: ctx.inheritance.system } : {},
|
|
13327
|
+
...ctx.inheritance.toolAliases !== void 0 ? { toolAliases: ctx.inheritance.toolAliases } : {},
|
|
13328
|
+
...ctx.inheritance.mcpServers !== void 0 ? { mcpServers: ctx.inheritance.mcpServers } : {},
|
|
13273
13329
|
...mcpConnectionFor(ctx),
|
|
13274
|
-
...ctx.
|
|
13275
|
-
|
|
13330
|
+
...ctx.inheritance.skills !== void 0 ? { skills: ctx.inheritance.skills } : {},
|
|
13331
|
+
behavior: ctx.behavior,
|
|
13276
13332
|
turnId,
|
|
13277
13333
|
callId,
|
|
13278
13334
|
runId: ctx.runId,
|
|
@@ -13335,7 +13391,7 @@ async function runSingleToolDispatch(ctx, call, turnId, fixed) {
|
|
|
13335
13391
|
isError = true;
|
|
13336
13392
|
} else {
|
|
13337
13393
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
13338
|
-
if (ctx.shouldRethrowToolError?.(error)) {
|
|
13394
|
+
if (ctx.behavior.shouldRethrowToolError?.(error)) {
|
|
13339
13395
|
ctx.toolState?.discard(callId);
|
|
13340
13396
|
throw error;
|
|
13341
13397
|
}
|
|
@@ -13493,8 +13549,8 @@ async function emitToolResult(ctx, params) {
|
|
|
13493
13549
|
const metadata = sanitizedMetadata.metadata;
|
|
13494
13550
|
if (sanitizedMetadata.warnings.length > 0 && process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/loop] sanitized tool metadata for ${name}/${callId}: ${sanitizedMetadata.warnings.join("; ")}\n`);
|
|
13495
13551
|
const finalOutcome = isError && outcome && outcome !== "failed" ? "failed" : outcome;
|
|
13496
|
-
const threshold = ctx.persistThreshold;
|
|
13497
|
-
const persistDir = ctx.persistDir;
|
|
13552
|
+
const threshold = ctx.behavior.persistThreshold;
|
|
13553
|
+
const persistDir = ctx.behavior.persistDir;
|
|
13498
13554
|
if (threshold && threshold > 0 && persistDir) {
|
|
13499
13555
|
const outcome = await maybePersistToolResult({
|
|
13500
13556
|
toolName: name,
|
|
@@ -13502,8 +13558,8 @@ async function emitToolResult(ctx, params) {
|
|
|
13502
13558
|
output,
|
|
13503
13559
|
threshold,
|
|
13504
13560
|
persistDir,
|
|
13505
|
-
...ctx.persistExcludeTools ? { excludeTools: ctx.persistExcludeTools } : {},
|
|
13506
|
-
...typeof ctx.persistMaxBytes === "number" ? { maxBytes: ctx.persistMaxBytes } : {},
|
|
13561
|
+
...ctx.behavior.persistExcludeTools ? { excludeTools: ctx.behavior.persistExcludeTools } : {},
|
|
13562
|
+
...typeof ctx.behavior.persistMaxBytes === "number" ? { maxBytes: ctx.behavior.persistMaxBytes } : {},
|
|
13507
13563
|
writeBlob: executionBlobWriter(ctx)
|
|
13508
13564
|
});
|
|
13509
13565
|
if (outcome.kind === "persisted") output = outcome.output;
|
|
@@ -13593,13 +13649,12 @@ function resolveConcurrencySafe(def, input) {
|
|
|
13593
13649
|
* AND carries the shell-cascade signal — siblings see one signal source.
|
|
13594
13650
|
*/
|
|
13595
13651
|
async function executeToolBatch(ctx, toolCalls, turnId) {
|
|
13596
|
-
if (ctx.toolBatchExecutor) return executeCustomToolBatch(ctx, toolCalls, turnId, ctx.toolBatchExecutor);
|
|
13652
|
+
if (ctx.behavior.toolBatchExecutor && !ctx.suppressBatchExecutor) return executeCustomToolBatch(ctx, toolCalls, turnId, ctx.behavior.toolBatchExecutor);
|
|
13597
13653
|
return executeNativeToolBatch(ctx, toolCalls, turnId);
|
|
13598
13654
|
}
|
|
13599
|
-
|
|
13600
|
-
if (toolCalls.length === 0) return [];
|
|
13655
|
+
function createToolBatchHarness(ctx, toolCalls, turnId, options = {}) {
|
|
13601
13656
|
const N = toolCalls.length;
|
|
13602
|
-
const maxConcurrent = Math.max(1, ctx.maxConcurrentTools ?? DEFAULT_MAX_CONCURRENT_TOOLS);
|
|
13657
|
+
const maxConcurrent = Math.max(1, ctx.behavior.maxConcurrentTools ?? DEFAULT_MAX_CONCURRENT_TOOLS);
|
|
13603
13658
|
const safe = Array.from({ length: N });
|
|
13604
13659
|
for (let i = 0; i < N; i++) safe[i] = resolveConcurrencySafe(ctx.tools[toolCalls[i].name], toolCalls[i].input);
|
|
13605
13660
|
const siblingAbort = new AbortController();
|
|
@@ -13612,14 +13667,20 @@ async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
|
13612
13667
|
const childCtx = {
|
|
13613
13668
|
...ctx,
|
|
13614
13669
|
signal: siblingAbort.signal,
|
|
13615
|
-
|
|
13670
|
+
...options.suppressBatchExecutor ? { suppressBatchExecutor: true } : {}
|
|
13616
13671
|
};
|
|
13672
|
+
/**
|
|
13673
|
+
* Distinguish a shell-cascade kill from a user-issued abort so the model sees
|
|
13674
|
+
* actionable text. When BOTH the parent signal and the sibling signal are
|
|
13675
|
+
* aborted, the parent wins — user-issued aborts take precedence (the model is
|
|
13676
|
+
* being interrupted by the human, not by a sibling's failure).
|
|
13677
|
+
*/
|
|
13617
13678
|
const cancelMessage = () => {
|
|
13618
13679
|
if (ctx.signal.aborted) return INTERRUPT_MESSAGE_FOR_TOOL_USE;
|
|
13619
13680
|
if (siblingAbort.signal.reason === SHELL_CASCADE_REASON) return SHELL_CASCADE_CANCEL_MESSAGE;
|
|
13620
13681
|
return INTERRUPT_MESSAGE_FOR_TOOL_USE;
|
|
13621
13682
|
};
|
|
13622
|
-
const
|
|
13683
|
+
const settle = async (index) => {
|
|
13623
13684
|
const call = toolCalls[index];
|
|
13624
13685
|
try {
|
|
13625
13686
|
const { result } = await executeSingleTool(childCtx, call, turnId);
|
|
@@ -13627,7 +13688,7 @@ async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
|
13627
13688
|
if (result.isError && !isUserCancel && call.name === SHELL_TOOL_NAME && !siblingAbort.signal.aborted) siblingAbort.abort(SHELL_CASCADE_REASON);
|
|
13628
13689
|
return result;
|
|
13629
13690
|
} catch (err) {
|
|
13630
|
-
if (ctx.shouldRethrowToolError?.(err)) throw err;
|
|
13691
|
+
if (ctx.behavior.shouldRethrowToolError?.(err)) throw err;
|
|
13631
13692
|
const isAbort = siblingAbort.signal.aborted || ctx.signal.aborted || err instanceof Error && err.name === "AbortError";
|
|
13632
13693
|
return {
|
|
13633
13694
|
id: call.id,
|
|
@@ -13636,6 +13697,25 @@ async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
|
13636
13697
|
};
|
|
13637
13698
|
}
|
|
13638
13699
|
};
|
|
13700
|
+
return {
|
|
13701
|
+
childCtx,
|
|
13702
|
+
siblingAbort,
|
|
13703
|
+
safe,
|
|
13704
|
+
maxConcurrent,
|
|
13705
|
+
cancelMessage,
|
|
13706
|
+
settle,
|
|
13707
|
+
dispose: () => {
|
|
13708
|
+
if (parentAbortListener) {
|
|
13709
|
+
ctx.signal.removeEventListener("abort", parentAbortListener);
|
|
13710
|
+
parentAbortListener = void 0;
|
|
13711
|
+
}
|
|
13712
|
+
}
|
|
13713
|
+
};
|
|
13714
|
+
}
|
|
13715
|
+
async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
13716
|
+
if (toolCalls.length === 0) return [];
|
|
13717
|
+
const harness = createToolBatchHarness(ctx, toolCalls, turnId, { suppressBatchExecutor: true });
|
|
13718
|
+
const { childCtx, siblingAbort, safe, maxConcurrent, cancelMessage } = harness;
|
|
13639
13719
|
const executeDurable = async (indices, all) => {
|
|
13640
13720
|
const starts = [];
|
|
13641
13721
|
const results = /* @__PURE__ */ new Map();
|
|
@@ -13700,7 +13780,7 @@ async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
|
13700
13780
|
signal: ctx.signal,
|
|
13701
13781
|
steeringQueue: ctx.steeringQueue,
|
|
13702
13782
|
isConcurrencySafe: (index) => safe[index] === true,
|
|
13703
|
-
execute,
|
|
13783
|
+
execute: harness.settle,
|
|
13704
13784
|
canExecuteDurably: (index) => typeof ctx.tools[toolCalls[index].name]?.durableExecute === "function",
|
|
13705
13785
|
executeDurable,
|
|
13706
13786
|
interruptedResult: (index) => ({
|
|
@@ -13714,7 +13794,7 @@ async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
|
13714
13794
|
isError: true
|
|
13715
13795
|
})
|
|
13716
13796
|
};
|
|
13717
|
-
const timeoutMs = typeof ctx.toolBatchTimeoutMs === "number" && Number.isFinite(ctx.toolBatchTimeoutMs) && ctx.toolBatchTimeoutMs > 0 ? ctx.toolBatchTimeoutMs : 0;
|
|
13797
|
+
const timeoutMs = typeof ctx.behavior.toolBatchTimeoutMs === "number" && Number.isFinite(ctx.behavior.toolBatchTimeoutMs) && ctx.behavior.toolBatchTimeoutMs > 0 ? ctx.behavior.toolBatchTimeoutMs : 0;
|
|
13718
13798
|
try {
|
|
13719
13799
|
if (timeoutMs <= 0) return await executor(executionCtx);
|
|
13720
13800
|
return await withTimeout$1(executor(executionCtx), {
|
|
@@ -13731,7 +13811,7 @@ async function executeCustomToolBatch(ctx, toolCalls, turnId, executor) {
|
|
|
13731
13811
|
isError: true
|
|
13732
13812
|
}));
|
|
13733
13813
|
} finally {
|
|
13734
|
-
|
|
13814
|
+
harness.dispose();
|
|
13735
13815
|
}
|
|
13736
13816
|
}
|
|
13737
13817
|
async function startDurableToolExecution(ctx, call, turnId, index) {
|
|
@@ -13866,14 +13946,14 @@ async function startDurableToolExecution(ctx, call, turnId, index) {
|
|
|
13866
13946
|
execution: ctx.execution,
|
|
13867
13947
|
handle: ctx.handle,
|
|
13868
13948
|
hooks: ctx.hooks,
|
|
13869
|
-
tools: ctx.
|
|
13870
|
-
...ctx.
|
|
13871
|
-
...ctx.
|
|
13872
|
-
...ctx.
|
|
13873
|
-
...ctx.
|
|
13949
|
+
tools: ctx.inheritance.tools,
|
|
13950
|
+
...ctx.inheritance.name !== void 0 ? { name: ctx.inheritance.name } : {},
|
|
13951
|
+
...ctx.inheritance.system !== void 0 ? { system: ctx.inheritance.system } : {},
|
|
13952
|
+
...ctx.inheritance.toolAliases !== void 0 ? { toolAliases: ctx.inheritance.toolAliases } : {},
|
|
13953
|
+
...ctx.inheritance.mcpServers !== void 0 ? { mcpServers: ctx.inheritance.mcpServers } : {},
|
|
13874
13954
|
...mcpConnectionFor(ctx),
|
|
13875
|
-
...ctx.
|
|
13876
|
-
|
|
13955
|
+
...ctx.inheritance.skills !== void 0 ? { skills: ctx.inheritance.skills } : {},
|
|
13956
|
+
behavior: ctx.behavior,
|
|
13877
13957
|
turnId,
|
|
13878
13958
|
callId,
|
|
13879
13959
|
runId: ctx.runId,
|
|
@@ -13930,7 +14010,7 @@ async function completeDurableToolExecution(ctx, start, output) {
|
|
|
13930
14010
|
};
|
|
13931
14011
|
}
|
|
13932
14012
|
async function failDurableToolExecution(ctx, start, err, cancelMessage) {
|
|
13933
|
-
if (ctx.shouldRethrowToolError?.(err)) {
|
|
14013
|
+
if (ctx.behavior.shouldRethrowToolError?.(err)) {
|
|
13934
14014
|
ctx.toolState?.discard(start.callId);
|
|
13935
14015
|
throw err;
|
|
13936
14016
|
}
|
|
@@ -14013,49 +14093,14 @@ function errorFromSerializedFailure(failure) {
|
|
|
14013
14093
|
async function executeNativeToolBatch(ctx, toolCalls, turnId) {
|
|
14014
14094
|
if (toolCalls.length === 0) return [];
|
|
14015
14095
|
const N = toolCalls.length;
|
|
14016
|
-
const maxConcurrent = Math.max(1, ctx.maxConcurrentTools ?? DEFAULT_MAX_CONCURRENT_TOOLS);
|
|
14017
14096
|
const results = Array.from({ length: N });
|
|
14018
|
-
const
|
|
14019
|
-
|
|
14020
|
-
const siblingAbort = new AbortController();
|
|
14021
|
-
let parentAbortListener;
|
|
14022
|
-
if (ctx.signal.aborted) siblingAbort.abort(ctx.signal.reason ?? "parent-aborted");
|
|
14023
|
-
else {
|
|
14024
|
-
parentAbortListener = () => siblingAbort.abort(ctx.signal.reason ?? "parent-aborted");
|
|
14025
|
-
ctx.signal.addEventListener("abort", parentAbortListener, { once: true });
|
|
14026
|
-
}
|
|
14027
|
-
const childCtx = {
|
|
14028
|
-
...ctx,
|
|
14029
|
-
signal: siblingAbort.signal
|
|
14030
|
-
};
|
|
14097
|
+
const harness = createToolBatchHarness(ctx, toolCalls, turnId);
|
|
14098
|
+
const { safe, maxConcurrent } = harness;
|
|
14031
14099
|
/** Indices currently in flight. Tracked for fleet-safety + cap checks. */
|
|
14032
14100
|
const inFlight = /* @__PURE__ */ new Map();
|
|
14033
|
-
/**
|
|
14034
|
-
* Distinguish a shell-cascade kill from a user-issued abort so the
|
|
14035
|
-
* model sees actionable text. When BOTH the parent signal and the
|
|
14036
|
-
* sibling signal are aborted, the parent wins — user-issued aborts
|
|
14037
|
-
* take precedence (the model is being interrupted by the human, not
|
|
14038
|
-
* by a sibling's failure).
|
|
14039
|
-
*/
|
|
14040
|
-
const cancelMessage = () => {
|
|
14041
|
-
if (ctx.signal.aborted) return INTERRUPT_MESSAGE_FOR_TOOL_USE;
|
|
14042
|
-
if (siblingAbort.signal.reason === SHELL_CASCADE_REASON) return SHELL_CASCADE_CANCEL_MESSAGE;
|
|
14043
|
-
return INTERRUPT_MESSAGE_FOR_TOOL_USE;
|
|
14044
|
-
};
|
|
14045
14101
|
const dispatch = (index) => {
|
|
14046
|
-
|
|
14047
|
-
return executeSingleTool(childCtx, call, turnId).then(({ result }) => {
|
|
14102
|
+
return harness.settle(index).then((result) => {
|
|
14048
14103
|
results[index] = result;
|
|
14049
|
-
const isUserCancel = typeof result.content === "string" && result.content === "[Tool call cancelled by user]";
|
|
14050
|
-
if (result.isError && !isUserCancel && call.name === SHELL_TOOL_NAME && !siblingAbort.signal.aborted) siblingAbort.abort(SHELL_CASCADE_REASON);
|
|
14051
|
-
}, (err) => {
|
|
14052
|
-
if (ctx.shouldRethrowToolError?.(err)) throw err;
|
|
14053
|
-
const isAbort = siblingAbort.signal.aborted || ctx.signal.aborted || err instanceof Error && err.name === "AbortError";
|
|
14054
|
-
results[index] = {
|
|
14055
|
-
id: call.id,
|
|
14056
|
-
content: isAbort ? cancelMessage() : `Error: ${errorMessage(err)}`,
|
|
14057
|
-
isError: true
|
|
14058
|
-
};
|
|
14059
14104
|
}).finally(() => {
|
|
14060
14105
|
inFlight.delete(index);
|
|
14061
14106
|
});
|
|
@@ -14115,7 +14160,7 @@ async function executeNativeToolBatch(ctx, toolCalls, turnId) {
|
|
|
14115
14160
|
await drain();
|
|
14116
14161
|
return results;
|
|
14117
14162
|
} finally {
|
|
14118
|
-
|
|
14163
|
+
harness.dispose();
|
|
14119
14164
|
}
|
|
14120
14165
|
}
|
|
14121
14166
|
//#endregion
|
|
@@ -15076,6 +15121,257 @@ function buildMcpToolNameSeparatorAliases(mcpToolNames, servers, separator) {
|
|
|
15076
15121
|
return Object.keys(aliases).length > 0 ? aliases : void 0;
|
|
15077
15122
|
}
|
|
15078
15123
|
/**
|
|
15124
|
+
* Partition the registry into eager vs lazy buckets and build the per-run
|
|
15125
|
+
* unlock bookkeeping the loop reads when rebuilding the wire-level tool list.
|
|
15126
|
+
*
|
|
15127
|
+
* Native (non-MCP) tools are always eager; `tool_search` itself must be eager
|
|
15128
|
+
* too (the discovery path can't gate on its own surfacing). The `unlocked` set
|
|
15129
|
+
* seeds with every eager canonical tool name and grows as the model surfaces
|
|
15130
|
+
* lazy tools through `tool_search`.
|
|
15131
|
+
*
|
|
15132
|
+
* Aliases are passed through so lazy entries carry their wire-level display
|
|
15133
|
+
* name — what the catalog and `tool_search` results show to the model — while
|
|
15134
|
+
* keeping the canonical name on the entry for unlock-set membership and
|
|
15135
|
+
* dispatch-map lookup.
|
|
15136
|
+
*/
|
|
15137
|
+
function buildRunDisclosureState(input) {
|
|
15138
|
+
const { tools: baseTools, mcpToolNames, mcpServers, toolDisclosure, toolSearch, toolAliases, hasRunToolOverride } = input;
|
|
15139
|
+
const disclosure = partitionToolDisclosure(baseTools, mcpToolNames, mcpServers, toolDisclosure, toolAliases);
|
|
15140
|
+
const unlocked = new Set(disclosure.eagerCanonicalNames);
|
|
15141
|
+
const initialUnlocked = new Set(disclosure.eagerCanonicalNames);
|
|
15142
|
+
const dynamicUnlockOrder = [];
|
|
15143
|
+
const dynamicUnlockSeen = /* @__PURE__ */ new Set();
|
|
15144
|
+
const recordUnlock = (canonical) => {
|
|
15145
|
+
if (initialUnlocked.has(canonical)) return;
|
|
15146
|
+
if (dynamicUnlockSeen.has(canonical)) return;
|
|
15147
|
+
dynamicUnlockSeen.add(canonical);
|
|
15148
|
+
unlocked.add(canonical);
|
|
15149
|
+
dynamicUnlockOrder.push(canonical);
|
|
15150
|
+
};
|
|
15151
|
+
const hostDefinedToolSearch = !!baseTools.tool_search;
|
|
15152
|
+
const injectedToolSearch = !hasRunToolOverride && (toolDisclosure === "lazy" || disclosure.lazyEntries.length > 0) && toolSearch?.tool !== false && !hostDefinedToolSearch;
|
|
15153
|
+
let tools = baseTools;
|
|
15154
|
+
if (injectedToolSearch) {
|
|
15155
|
+
const toolSearchTool = createToolSearchTool({
|
|
15156
|
+
catalog: disclosure.lazyEntries,
|
|
15157
|
+
unlocked,
|
|
15158
|
+
addUnlock: recordUnlock,
|
|
15159
|
+
...toolSearch?.limit !== void 0 ? { defaultLimit: toolSearch.limit } : {}
|
|
15160
|
+
});
|
|
15161
|
+
tools = {
|
|
15162
|
+
...baseTools,
|
|
15163
|
+
[toolSearchTool.spec.name]: toolSearchTool
|
|
15164
|
+
};
|
|
15165
|
+
unlocked.add(toolSearchTool.spec.name);
|
|
15166
|
+
initialUnlocked.add(toolSearchTool.spec.name);
|
|
15167
|
+
}
|
|
15168
|
+
return {
|
|
15169
|
+
disclosure,
|
|
15170
|
+
unlocked,
|
|
15171
|
+
initialUnlocked,
|
|
15172
|
+
dynamicUnlockOrder,
|
|
15173
|
+
recordUnlock,
|
|
15174
|
+
tools,
|
|
15175
|
+
injectedToolSearch,
|
|
15176
|
+
hostDefinedToolSearch
|
|
15177
|
+
};
|
|
15178
|
+
}
|
|
15179
|
+
/**
|
|
15180
|
+
* Choose the prior turns a run starts from, or `undefined` for a fresh start.
|
|
15181
|
+
*
|
|
15182
|
+
* Two resume flavors:
|
|
15183
|
+
* - `resumeRunId` (child-run resume): seed ONLY the referenced prior run's
|
|
15184
|
+
* lineage. Used by the spawn tool to continue a stopped/failed subagent —
|
|
15185
|
+
* the parent's conversation (and every other child's) stays invisible,
|
|
15186
|
+
* mirroring how a fresh child starts from just its task prompt. Allowed
|
|
15187
|
+
* WITH `parentRunId` set (unlike a full-session resume).
|
|
15188
|
+
* - full-session resume: the historical top-level path, on re-runs
|
|
15189
|
+
* (`runs > 0`) or promptless runs (session turns already contain the user
|
|
15190
|
+
* message). **Excluded for child agents**: when the spawn tool runs with
|
|
15191
|
+
* `persist: true`, the child shares the parent's session for *storage* but
|
|
15192
|
+
* its conversation must start fresh from the task prompt. Otherwise the
|
|
15193
|
+
* child would pull in the parent's in-flight assistant turn — including the
|
|
15194
|
+
* parent's pending `spawn` tool_use — and every provider (Anthropic loudly,
|
|
15195
|
+
* OpenAI implicitly) rejects a history where a `tool_use` lacks its
|
|
15196
|
+
* matching `tool_result`.
|
|
15197
|
+
*/
|
|
15198
|
+
function selectSeedTurns(input) {
|
|
15199
|
+
const { session, options, resumeFilteredTurns } = input;
|
|
15200
|
+
if (options.resumeRunId && session) {
|
|
15201
|
+
const chain = resumeChainRunIds(session.runs, options.resumeRunId);
|
|
15202
|
+
return filterUnresolvedToolUses(session.turns.filter((t) => t.runId !== void 0 && chain.has(t.runId)));
|
|
15203
|
+
}
|
|
15204
|
+
if (!(session && session.turns.length > 0 && (session.runs.length > 0 || !options.prompt) && !options.parentRunId && !options.resumeRunId)) return void 0;
|
|
15205
|
+
const childRunIds = childRunIdSet(session);
|
|
15206
|
+
const resumed = childRunIds.size === 0 ? session.turns : session.turns.filter((t) => !t.runId || !childRunIds.has(t.runId));
|
|
15207
|
+
return resumeFilteredTurns && resumed === session.turns ? resumeFilteredTurns : filterUnresolvedToolUses(resumed);
|
|
15208
|
+
}
|
|
15209
|
+
/**
|
|
15210
|
+
* Replay every resolved `tool_search` from a resumed history into the per-run
|
|
15211
|
+
* `unlocked` set.
|
|
15212
|
+
*
|
|
15213
|
+
* Without this seeding a resumed conversation shows the model "These tools are
|
|
15214
|
+
* now callable" in the prior tool_result, but the next turn's `formattedTools`
|
|
15215
|
+
* and the `tool:gate` hook still treat the tools as locked — every subsequent
|
|
15216
|
+
* `tool_use` is rejected with "load via tool_search first", which the model
|
|
15217
|
+
* can't recover from without a fresh `tool_search` round-trip.
|
|
15218
|
+
*
|
|
15219
|
+
* Only replays calls whose result the model actually consumed: a `tool_call`
|
|
15220
|
+
* without a matching successful `tool_result` is either an unresolved pair
|
|
15221
|
+
* `filterUnresolvedToolUses` already stripped or a structural error — either
|
|
15222
|
+
* way, unlocking from it would be speculative.
|
|
15223
|
+
*/
|
|
15224
|
+
function replayToolSearchUnlocks(seededTurns, lazyEntries, unlocked, limit, recordUnlock) {
|
|
15225
|
+
const resolvedCallIds = /* @__PURE__ */ new Set();
|
|
15226
|
+
for (const turn of seededTurns) for (const block of turn.content) if (block.type === "tool_result" && !block.isError) resolvedCallIds.add(block.callId);
|
|
15227
|
+
for (const turn of seededTurns) for (const block of turn.content) {
|
|
15228
|
+
if (block.type !== "tool_call") continue;
|
|
15229
|
+
if (block.name !== "tool_search") continue;
|
|
15230
|
+
if (!resolvedCallIds.has(block.id)) continue;
|
|
15231
|
+
applyToolSearchToUnlocked(lazyEntries, block.input, unlocked, limit, recordUnlock);
|
|
15232
|
+
}
|
|
15233
|
+
}
|
|
15234
|
+
/**
|
|
15235
|
+
* Reconcile + drain pending background-task notifications.
|
|
15236
|
+
*
|
|
15237
|
+
* Each exit becomes a `<task-notification>` text block prepended to the user
|
|
15238
|
+
* turn so the model sees task completions on its very next prompt, without
|
|
15239
|
+
* polling. Two sources, merged by taskId:
|
|
15240
|
+
*
|
|
15241
|
+
* 1. PUSH — the agent-scoped queue populated by `background:exit` since the
|
|
15242
|
+
* last `run()` (in-process contexts fire `onExit`).
|
|
15243
|
+
* 2. PULL — a `listBackground` sweep for terminated tasks the model hasn't
|
|
15244
|
+
* been told about. This is what makes remote / durable contexts work:
|
|
15245
|
+
* they have no legal way to push from a timer into the host (journal
|
|
15246
|
+
* rules), so the loop polls at the run boundary instead.
|
|
15247
|
+
* `endedAt - startedAt` reproduces `durationMs` without depending on
|
|
15248
|
+
* sweep timing.
|
|
15249
|
+
*
|
|
15250
|
+
* The `background:reconcile` hook fires on the merged list INSIDE the run()
|
|
15251
|
+
* await chain — the journalable seam for durable hosts (see the hook's doc).
|
|
15252
|
+
* Entries suppressed earlier (`shell_kill`, `read_file`, `wait_task`) are
|
|
15253
|
+
* absent from both sources via the `notified` latch. See
|
|
15254
|
+
* `docs/RUN_IN_BACKGROUND.md` §Completion notification.
|
|
15255
|
+
*
|
|
15256
|
+
* Durable hosts wrap the live `listBackground` poll in `journalReconcile` so it
|
|
15257
|
+
* records as one journaled side effect (replay returns the recorded snapshot,
|
|
15258
|
+
* keeping `exits.length` — and therefore the conditional hook's journal
|
|
15259
|
+
* position — stable across attempts). Everything downstream of the snapshot is
|
|
15260
|
+
* pure over journaled / replayed inputs (session-turn acks, duration
|
|
15261
|
+
* derivation), so journaling the poll is enough to make the whole reconcile
|
|
15262
|
+
* deterministic.
|
|
15263
|
+
*/
|
|
15264
|
+
async function drainTaskNotifications(input) {
|
|
15265
|
+
const { state, executionContext, executionHandle, behavior, journalReconcile, session, turns, hooks } = input;
|
|
15266
|
+
const reconciled = new Map(state.pending);
|
|
15267
|
+
state.pending.clear();
|
|
15268
|
+
if (executionContext.listBackground && executionHandle && typeof behavior.tasksDir === "string" && behavior.tasksDir.length > 0) try {
|
|
15269
|
+
const listBackground = executionContext.listBackground;
|
|
15270
|
+
const handle = executionHandle;
|
|
15271
|
+
const entries = journalReconcile ? await journalReconcile(() => listBackground(handle)) : await listBackground(handle);
|
|
15272
|
+
const acks = entries.some((e) => e.status !== "running") ? collectTaskAcksFromTurns(session ? session.turns : turns) : void 0;
|
|
15273
|
+
for (const entry of entries) {
|
|
15274
|
+
if (entry.status === "running" || state.notified.has(entry.taskId) || reconciled.has(entry.taskId)) continue;
|
|
15275
|
+
if (acks) {
|
|
15276
|
+
if (acks.taskIds.has(entry.taskId)) continue;
|
|
15277
|
+
const readAt = acks.outputPaths.get(resolve(entry.outputPath));
|
|
15278
|
+
if (readAt !== void 0 && entry.endedAt !== void 0 && readAt >= entry.endedAt + READ_ACK_CLOCK_SKEW_MARGIN_MS) continue;
|
|
15279
|
+
}
|
|
15280
|
+
reconciled.set(entry.taskId, {
|
|
15281
|
+
taskId: entry.taskId,
|
|
15282
|
+
status: entry.status,
|
|
15283
|
+
exitCode: entry.exitCode ?? 0,
|
|
15284
|
+
...entry.signal ? { signal: entry.signal } : {},
|
|
15285
|
+
outputPath: entry.outputPath,
|
|
15286
|
+
durationMs: Math.max(0, (entry.endedAt ?? entry.startedAt) - entry.startedAt),
|
|
15287
|
+
command: entry.command
|
|
15288
|
+
});
|
|
15289
|
+
}
|
|
15290
|
+
} catch (err) {
|
|
15291
|
+
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/agent] background reconcile failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
15292
|
+
}
|
|
15293
|
+
const reconcileCtx = { exits: [...reconciled.values()] };
|
|
15294
|
+
if (reconcileCtx.exits.length > 0) await hooks.callHook("background:reconcile", reconcileCtx);
|
|
15295
|
+
for (const taskId of reconciled.keys()) {
|
|
15296
|
+
state.notified.add(taskId);
|
|
15297
|
+
state.pendingStalls.delete(taskId);
|
|
15298
|
+
}
|
|
15299
|
+
const drained = [];
|
|
15300
|
+
for (const notif of reconcileCtx.exits) drained.push({
|
|
15301
|
+
type: "text",
|
|
15302
|
+
text: renderTaskNotificationXml(notif)
|
|
15303
|
+
});
|
|
15304
|
+
if (state.pendingStalls.size > 0) {
|
|
15305
|
+
for (const stall of state.pendingStalls.values()) drained.push({
|
|
15306
|
+
type: "text",
|
|
15307
|
+
text: renderTaskStallXml(stall)
|
|
15308
|
+
});
|
|
15309
|
+
state.pendingStalls.clear();
|
|
15310
|
+
}
|
|
15311
|
+
return drained;
|
|
15312
|
+
}
|
|
15313
|
+
/**
|
|
15314
|
+
* Assemble the tool registry a single run advertises.
|
|
15315
|
+
*
|
|
15316
|
+
* Pipeline: resolve the base set (run override > agent + MCP) → derive the
|
|
15317
|
+
* wire-name aliases → inject the skills tools → apply extension catalog
|
|
15318
|
+
* transforms → index by spec name → rewrite the built-in `shell` for this
|
|
15319
|
+
* run's capabilities.
|
|
15320
|
+
*/
|
|
15321
|
+
function buildRunToolRegistry(input) {
|
|
15322
|
+
const { runOverrideTools, sourceTools, mcpConnection, mcpServers, mcpToolNameSeparator, toolAliases, resolvedSkills, skillsConfig, skillActivationState, hooks, toolCatalogTransforms, executionContext, behavior } = input;
|
|
15323
|
+
const runBaseTools = runOverrideTools !== void 0 ? runOverrideTools : mcpConnection ? {
|
|
15324
|
+
...sourceTools,
|
|
15325
|
+
...mcpConnection.tools
|
|
15326
|
+
} : sourceTools;
|
|
15327
|
+
const mcpToolNames = runOverrideTools === void 0 && mcpConnection ? new Set(Object.keys(mcpConnection.tools)) : /* @__PURE__ */ new Set();
|
|
15328
|
+
const generatedMcpToolAliases = buildMcpToolNameSeparatorAliases(mcpToolNames, mcpServers, mcpToolNameSeparator);
|
|
15329
|
+
const baseToolAliases = generatedMcpToolAliases ? {
|
|
15330
|
+
...generatedMcpToolAliases,
|
|
15331
|
+
...toolAliases ?? {}
|
|
15332
|
+
} : toolAliases;
|
|
15333
|
+
const sanitizedWireAliases = buildSanitizedWireAliases(mcpToolNames, baseToolAliases);
|
|
15334
|
+
const effectiveToolAliases = sanitizedWireAliases ? {
|
|
15335
|
+
...baseToolAliases ?? {},
|
|
15336
|
+
...sanitizedWireAliases
|
|
15337
|
+
} : baseToolAliases;
|
|
15338
|
+
const transformedToolCatalog = applyToolCatalogTransforms(runOverrideTools === void 0 && !!resolvedSkills && resolvedSkills.length > 0 && skillsConfig?.tool !== false ? {
|
|
15339
|
+
skills_use: createSkillsUseTool({
|
|
15340
|
+
catalog: resolvedSkills,
|
|
15341
|
+
state: skillActivationState,
|
|
15342
|
+
hooks,
|
|
15343
|
+
allowShellInterpolation: skillsConfig?.allowShellInterpolation,
|
|
15344
|
+
approveShellInterpolation: skillsConfig?.approveShellInterpolation
|
|
15345
|
+
}),
|
|
15346
|
+
skills_read: createSkillsReadTool({
|
|
15347
|
+
catalog: resolvedSkills,
|
|
15348
|
+
state: skillActivationState
|
|
15349
|
+
}),
|
|
15350
|
+
skills_run_script: createSkillsRunScriptTool({
|
|
15351
|
+
catalog: resolvedSkills,
|
|
15352
|
+
state: skillActivationState,
|
|
15353
|
+
scriptTimeoutMs: skillsConfig?.scriptTimeoutMs
|
|
15354
|
+
}),
|
|
15355
|
+
...runBaseTools
|
|
15356
|
+
} : runBaseTools, toolCatalogTransforms, "run", mcpToolNames);
|
|
15357
|
+
const tools = {};
|
|
15358
|
+
for (const tool of Object.values(transformedToolCatalog)) tools[tool.spec.name] = tool;
|
|
15359
|
+
if (tools.shell === shell) {
|
|
15360
|
+
const detachedTasks = resolveDetachedTasksCapability(executionContext);
|
|
15361
|
+
const bgDisabled = behavior.disableBackgroundTasks === true || behavior.disableBackgroundTasks === "non-durable" && detachedTasks !== "durable";
|
|
15362
|
+
tools.shell = createShellTool({
|
|
15363
|
+
allowBackground: typeof behavior.tasksDir === "string" && behavior.tasksDir.length > 0 && !bgDisabled && detachedTasks !== "none",
|
|
15364
|
+
registeredCanonicals: new Set(Object.keys(tools)),
|
|
15365
|
+
...effectiveToolAliases ? { toolAliases: effectiveToolAliases } : {}
|
|
15366
|
+
});
|
|
15367
|
+
}
|
|
15368
|
+
return {
|
|
15369
|
+
tools,
|
|
15370
|
+
mcpToolNames,
|
|
15371
|
+
toolAliases: effectiveToolAliases
|
|
15372
|
+
};
|
|
15373
|
+
}
|
|
15374
|
+
/**
|
|
15079
15375
|
* Partition a tool registry into eager and lazy buckets.
|
|
15080
15376
|
*
|
|
15081
15377
|
* Native + skill tools always end up in the eager bucket — only MCP tools
|
|
@@ -15656,6 +15952,7 @@ function createAgent(rawOptions) {
|
|
|
15656
15952
|
const externalSignal = options.signal;
|
|
15657
15953
|
running = true;
|
|
15658
15954
|
toolCancels.clearPending();
|
|
15955
|
+
const perRunUnregisters = [];
|
|
15659
15956
|
try {
|
|
15660
15957
|
abortController = new AbortController();
|
|
15661
15958
|
idlePromise = new Promise((resolve) => {
|
|
@@ -15702,10 +15999,9 @@ function createAgent(rawOptions) {
|
|
|
15702
15999
|
externalSignal.addEventListener("abort", externalAbortListener, { once: true });
|
|
15703
16000
|
}
|
|
15704
16001
|
const childrenStats = [];
|
|
15705
|
-
|
|
16002
|
+
perRunUnregisters.push(hooks.hook("spawn:complete", (ctx) => {
|
|
15706
16003
|
childrenStats.push(ctx);
|
|
15707
|
-
});
|
|
15708
|
-
const perRunUnregisters = [];
|
|
16004
|
+
}));
|
|
15709
16005
|
if (options.hooks) for (const [event, handler] of Object.entries(options.hooks)) {
|
|
15710
16006
|
if (!isKnownHookEvent(event)) throw new Error(`Unknown hook event "${event}" passed to run(). See AgentHooks for valid events.`);
|
|
15711
16007
|
const handlerList = Array.isArray(handler) ? handler : [handler];
|
|
@@ -15741,86 +16037,37 @@ function createAgent(rawOptions) {
|
|
|
15741
16037
|
}
|
|
15742
16038
|
const thinking = options.thinking ?? "off";
|
|
15743
16039
|
const model = targets[0].model;
|
|
15744
|
-
if (runProvider.meta
|
|
15745
|
-
|
|
16040
|
+
if (runProvider.meta.clearsContextServerSide) resolvedBehavior.dedupReads = false;
|
|
16041
|
+
Object.freeze(resolvedBehavior);
|
|
16042
|
+
const { thinkingOverrunPolicy, thinkingBudget, modelOptions: behaviorModelOptions, compactKeepTurns, writeFileExistingPolicy, textToolCallRescue, unknownToolRecovery, progressNudges, dedupTools, toolBudgets, repeatGuard, autoCompact, toolDisclosure, mcpToolNameSeparator, toolSearch, surfaceMcpInstructions, persistTurns } = resolvedBehavior;
|
|
15746
16043
|
const modelOptions = options.modelOptions ?? behaviorModelOptions;
|
|
15747
16044
|
let system = options.system || agentSystem || "You are a helpful assistant.";
|
|
15748
16045
|
const baseSystemForBreakdown = renderSystemForWire(system);
|
|
15749
16046
|
if (skillsCatalog) system = appendStaticSection(system, skillsCatalog);
|
|
15750
|
-
const
|
|
15751
|
-
|
|
15752
|
-
|
|
15753
|
-
|
|
15754
|
-
|
|
15755
|
-
|
|
15756
|
-
|
|
15757
|
-
|
|
15758
|
-
|
|
15759
|
-
|
|
15760
|
-
|
|
15761
|
-
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
}
|
|
15765
|
-
const
|
|
15766
|
-
|
|
15767
|
-
|
|
15768
|
-
|
|
15769
|
-
|
|
15770
|
-
|
|
15771
|
-
|
|
15772
|
-
|
|
15773
|
-
|
|
15774
|
-
catalog: resolvedSkills,
|
|
15775
|
-
state: skillActivationState
|
|
15776
|
-
}),
|
|
15777
|
-
skills_run_script: createSkillsRunScriptTool({
|
|
15778
|
-
catalog: resolvedSkills,
|
|
15779
|
-
state: skillActivationState,
|
|
15780
|
-
scriptTimeoutMs: skillsConfig?.scriptTimeoutMs
|
|
15781
|
-
}),
|
|
15782
|
-
...runBaseTools
|
|
15783
|
-
} : runBaseTools, toolCatalogTransforms, "run", mcpToolNames);
|
|
15784
|
-
const toolsPreSearch = {};
|
|
15785
|
-
for (const tool of Object.values(transformedToolCatalog)) toolsPreSearch[tool.spec.name] = tool;
|
|
15786
|
-
if (toolsPreSearch.shell === shell) {
|
|
15787
|
-
const detachedTasks = resolveDetachedTasksCapability(executionContext);
|
|
15788
|
-
const bgDisabled = resolvedBehavior?.disableBackgroundTasks === true || resolvedBehavior?.disableBackgroundTasks === "non-durable" && detachedTasks !== "durable";
|
|
15789
|
-
toolsPreSearch.shell = createShellTool({
|
|
15790
|
-
allowBackground: typeof resolvedBehavior?.tasksDir === "string" && resolvedBehavior.tasksDir.length > 0 && !bgDisabled && detachedTasks !== "none",
|
|
15791
|
-
registeredCanonicals: new Set(Object.keys(toolsPreSearch)),
|
|
15792
|
-
...effectiveToolAliases ? { toolAliases: effectiveToolAliases } : {}
|
|
15793
|
-
});
|
|
15794
|
-
}
|
|
15795
|
-
const disclosure = partitionToolDisclosure(toolsPreSearch, mcpToolNames, mcpServers, toolDisclosure, effectiveToolAliases);
|
|
15796
|
-
const unlocked = new Set(disclosure.eagerCanonicalNames);
|
|
15797
|
-
const initialUnlocked = new Set(disclosure.eagerCanonicalNames);
|
|
15798
|
-
const dynamicUnlockOrder = [];
|
|
15799
|
-
const dynamicUnlockSeen = /* @__PURE__ */ new Set();
|
|
15800
|
-
function recordDynamicUnlock(canonical) {
|
|
15801
|
-
if (initialUnlocked.has(canonical)) return;
|
|
15802
|
-
if (dynamicUnlockSeen.has(canonical)) return;
|
|
15803
|
-
dynamicUnlockSeen.add(canonical);
|
|
15804
|
-
unlocked.add(canonical);
|
|
15805
|
-
dynamicUnlockOrder.push(canonical);
|
|
15806
|
-
}
|
|
15807
|
-
const hostDefinedToolSearch = !!toolsPreSearch.tool_search;
|
|
15808
|
-
const shouldInjectToolSearch = options.tools === void 0 && (toolDisclosure === "lazy" || disclosure.lazyEntries.length > 0) && toolSearch?.tool !== false && !hostDefinedToolSearch;
|
|
15809
|
-
let tools = toolsPreSearch;
|
|
15810
|
-
if (shouldInjectToolSearch) {
|
|
15811
|
-
const toolSearchTool = createToolSearchTool({
|
|
15812
|
-
catalog: disclosure.lazyEntries,
|
|
15813
|
-
unlocked,
|
|
15814
|
-
addUnlock: recordDynamicUnlock,
|
|
15815
|
-
...toolSearch?.limit !== void 0 ? { defaultLimit: toolSearch.limit } : {}
|
|
15816
|
-
});
|
|
15817
|
-
tools = {
|
|
15818
|
-
...toolsPreSearch,
|
|
15819
|
-
[toolSearchTool.spec.name]: toolSearchTool
|
|
15820
|
-
};
|
|
15821
|
-
unlocked.add(toolSearchTool.spec.name);
|
|
15822
|
-
initialUnlocked.add(toolSearchTool.spec.name);
|
|
15823
|
-
}
|
|
16047
|
+
const { tools: toolsPreSearch, mcpToolNames, toolAliases: effectiveToolAliases } = buildRunToolRegistry({
|
|
16048
|
+
runOverrideTools: options.tools,
|
|
16049
|
+
sourceTools,
|
|
16050
|
+
mcpConnection,
|
|
16051
|
+
mcpServers,
|
|
16052
|
+
mcpToolNameSeparator,
|
|
16053
|
+
toolAliases,
|
|
16054
|
+
resolvedSkills,
|
|
16055
|
+
skillsConfig,
|
|
16056
|
+
skillActivationState,
|
|
16057
|
+
hooks,
|
|
16058
|
+
toolCatalogTransforms,
|
|
16059
|
+
executionContext,
|
|
16060
|
+
behavior: resolvedBehavior
|
|
16061
|
+
});
|
|
16062
|
+
const { disclosure, unlocked, initialUnlocked, dynamicUnlockOrder, recordUnlock: recordDynamicUnlock, tools, injectedToolSearch: shouldInjectToolSearch, hostDefinedToolSearch } = buildRunDisclosureState({
|
|
16063
|
+
tools: toolsPreSearch,
|
|
16064
|
+
mcpToolNames,
|
|
16065
|
+
mcpServers,
|
|
16066
|
+
toolDisclosure,
|
|
16067
|
+
toolSearch,
|
|
16068
|
+
toolAliases: effectiveToolAliases,
|
|
16069
|
+
hasRunToolOverride: options.tools !== void 0
|
|
16070
|
+
});
|
|
15824
16071
|
const discoveryToolName = shouldInjectToolSearch ? "tool_search" : hostDefinedToolSearch ? effectiveToolAliases?.tool_search ?? "tool_search" : null;
|
|
15825
16072
|
let searchableCatalogText;
|
|
15826
16073
|
if (disclosure.lazyEntries.length > 0) {
|
|
@@ -15905,76 +16152,31 @@ function createAgent(rawOptions) {
|
|
|
15905
16152
|
});
|
|
15906
16153
|
}
|
|
15907
16154
|
const turns = [];
|
|
15908
|
-
const
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
|
|
15913
|
-
} else if (isResume) {
|
|
15914
|
-
const childRunIds = childRunIdSet(session);
|
|
15915
|
-
const resumed = childRunIds.size === 0 ? session.turns : session.turns.filter((t) => !t.runId || !childRunIds.has(t.runId));
|
|
15916
|
-
seededTurns = resumeFilteredTurns && resumed === session.turns ? resumeFilteredTurns : filterUnresolvedToolUses(resumed);
|
|
15917
|
-
}
|
|
16155
|
+
const seededTurns = selectSeedTurns({
|
|
16156
|
+
session,
|
|
16157
|
+
options,
|
|
16158
|
+
resumeFilteredTurns
|
|
16159
|
+
});
|
|
15918
16160
|
if (seededTurns) {
|
|
15919
16161
|
turns.push(...seededTurns);
|
|
15920
|
-
if (shouldInjectToolSearch && disclosure.lazyEntries.length > 0)
|
|
15921
|
-
const resolvedCallIds = /* @__PURE__ */ new Set();
|
|
15922
|
-
for (const turn of seededTurns) for (const block of turn.content) if (block.type === "tool_result" && !block.isError) resolvedCallIds.add(block.callId);
|
|
15923
|
-
for (const turn of seededTurns) for (const block of turn.content) {
|
|
15924
|
-
if (block.type !== "tool_call") continue;
|
|
15925
|
-
if (block.name !== "tool_search") continue;
|
|
15926
|
-
if (!resolvedCallIds.has(block.id)) continue;
|
|
15927
|
-
applyToolSearchToUnlocked(disclosure.lazyEntries, block.input, unlocked, toolSearch?.limit, recordDynamicUnlock);
|
|
15928
|
-
}
|
|
15929
|
-
}
|
|
16162
|
+
if (shouldInjectToolSearch && disclosure.lazyEntries.length > 0) replayToolSearchUnlocks(seededTurns, disclosure.lazyEntries, unlocked, toolSearch?.limit, recordDynamicUnlock);
|
|
15930
16163
|
}
|
|
15931
16164
|
const runTurnStart = turns.length;
|
|
15932
16165
|
if (options.system) await hooks.callHook("system:before", { system: options.system });
|
|
15933
|
-
const
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
|
|
15942
|
-
|
|
15943
|
-
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
}
|
|
15947
|
-
reconciled.set(entry.taskId, {
|
|
15948
|
-
taskId: entry.taskId,
|
|
15949
|
-
status: entry.status,
|
|
15950
|
-
exitCode: entry.exitCode ?? 0,
|
|
15951
|
-
...entry.signal ? { signal: entry.signal } : {},
|
|
15952
|
-
outputPath: entry.outputPath,
|
|
15953
|
-
durationMs: Math.max(0, (entry.endedAt ?? entry.startedAt) - entry.startedAt),
|
|
15954
|
-
command: entry.command
|
|
15955
|
-
});
|
|
15956
|
-
}
|
|
15957
|
-
} catch (err) {
|
|
15958
|
-
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/agent] background reconcile failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
15959
|
-
}
|
|
15960
|
-
const reconcileCtx = { exits: [...reconciled.values()] };
|
|
15961
|
-
if (reconcileCtx.exits.length > 0) await hooks.callHook("background:reconcile", reconcileCtx);
|
|
15962
|
-
for (const taskId of reconciled.keys()) {
|
|
15963
|
-
notifiedTaskIds.add(taskId);
|
|
15964
|
-
pendingStallNotifications.delete(taskId);
|
|
15965
|
-
}
|
|
15966
|
-
const drainedNotifications = [];
|
|
15967
|
-
for (const notif of reconcileCtx.exits) drainedNotifications.push({
|
|
15968
|
-
type: "text",
|
|
15969
|
-
text: renderTaskNotificationXml(notif)
|
|
16166
|
+
const drainedNotifications = await drainTaskNotifications({
|
|
16167
|
+
state: {
|
|
16168
|
+
pending: pendingTaskNotifications,
|
|
16169
|
+
pendingStalls: pendingStallNotifications,
|
|
16170
|
+
notified: notifiedTaskIds
|
|
16171
|
+
},
|
|
16172
|
+
executionContext,
|
|
16173
|
+
executionHandle,
|
|
16174
|
+
behavior: resolvedBehavior,
|
|
16175
|
+
journalReconcile: options.journalReconcile,
|
|
16176
|
+
session,
|
|
16177
|
+
turns,
|
|
16178
|
+
hooks
|
|
15970
16179
|
});
|
|
15971
|
-
if (pendingStallNotifications.size > 0) {
|
|
15972
|
-
for (const stall of pendingStallNotifications.values()) drainedNotifications.push({
|
|
15973
|
-
type: "text",
|
|
15974
|
-
text: renderTaskStallXml(stall)
|
|
15975
|
-
});
|
|
15976
|
-
pendingStallNotifications.clear();
|
|
15977
|
-
}
|
|
15978
16180
|
let lastPersistedTurnCount = turns.length;
|
|
15979
16181
|
const promptParts = canonicalizePrompt(options.prompt);
|
|
15980
16182
|
if (promptParts || drainedNotifications.length > 0) {
|
|
@@ -16021,8 +16223,10 @@ function createAgent(rawOptions) {
|
|
|
16021
16223
|
});
|
|
16022
16224
|
}
|
|
16023
16225
|
const perTurnSync = session && persistTurns !== false;
|
|
16024
|
-
|
|
16025
|
-
|
|
16226
|
+
if (perTurnSync) {
|
|
16227
|
+
perRunUnregisters.push(hooks.hook("turn:after", persistPendingTurns));
|
|
16228
|
+
perRunUnregisters.push(hooks.hook("tool-results:after", persistPendingTurns));
|
|
16229
|
+
}
|
|
16026
16230
|
async function flushTurns(opts = {}) {
|
|
16027
16231
|
if (!session) return;
|
|
16028
16232
|
if (opts.failureFallback) {
|
|
@@ -16067,7 +16271,7 @@ function createAgent(rawOptions) {
|
|
|
16067
16271
|
const run = session?.runs.find((r) => r.id === runId);
|
|
16068
16272
|
if (run) run.endedAt = await clock.now();
|
|
16069
16273
|
}
|
|
16070
|
-
|
|
16274
|
+
perRunUnregisters.push(installAllowedToolsGate(hooks, skillActivationState));
|
|
16071
16275
|
const getExecutionHandle = () => executionHandle ?? void 0;
|
|
16072
16276
|
perRunUnregisters.push(installWriteFileExistingPolicy(hooks, writeFileExistingPolicy, {
|
|
16073
16277
|
execution: executionContext,
|
|
@@ -16078,10 +16282,10 @@ function createAgent(rawOptions) {
|
|
|
16078
16282
|
advertisedToolNames,
|
|
16079
16283
|
enqueueNudge: (message) => nonInterruptingNudgeQueue.push(message)
|
|
16080
16284
|
}));
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16285
|
+
perRunUnregisters.push(installToolBudgetsGate(hooks, () => toolBudgets, (msg) => nonInterruptingNudgeQueue.push(msg)));
|
|
16286
|
+
perRunUnregisters.push(installRepeatGuard(hooks, () => repeatGuard, () => abortController?.abort()));
|
|
16287
|
+
perRunUnregisters.push(installDedupToolsGate(hooks, () => dedupTools, () => session ?? void 0));
|
|
16288
|
+
perRunUnregisters.push(installLazyDisclosureHydrationGate(hooks, {
|
|
16085
16289
|
enabled: shouldInjectToolSearch && disclosure.lazyEntries.length > 0,
|
|
16086
16290
|
session: session ?? void 0,
|
|
16087
16291
|
lazyCanonicalNames: disclosure.lazyCanonicalNames,
|
|
@@ -16089,20 +16293,20 @@ function createAgent(rawOptions) {
|
|
|
16089
16293
|
unlocked,
|
|
16090
16294
|
recordUnlock: recordDynamicUnlock,
|
|
16091
16295
|
defaultLimit: toolSearch?.limit
|
|
16092
|
-
});
|
|
16093
|
-
|
|
16094
|
-
|
|
16296
|
+
}));
|
|
16297
|
+
perRunUnregisters.push(installLazyDisclosureGate(hooks, disclosure.lazyCanonicalNames, unlocked, discoveryToolName));
|
|
16298
|
+
perRunUnregisters.push(installReadBeforeEditHydrationGate(hooks, resolvedBehavior.requireReadBeforeEdit === true, {
|
|
16095
16299
|
session: session ?? void 0,
|
|
16096
16300
|
getHandle: () => executionHandle,
|
|
16097
16301
|
execution: executionContext,
|
|
16098
16302
|
aliasMaps,
|
|
16099
16303
|
defaultLineNumbers: resolvedBehavior.readLineNumbers ?? true
|
|
16100
|
-
});
|
|
16101
|
-
|
|
16304
|
+
}));
|
|
16305
|
+
perRunUnregisters.push(installSkillsActivationHydrationGate(hooks, {
|
|
16102
16306
|
session: session ?? void 0,
|
|
16103
16307
|
getResolvedSkills: () => resolvedSkills,
|
|
16104
16308
|
state: skillActivationState
|
|
16105
|
-
});
|
|
16309
|
+
}));
|
|
16106
16310
|
perRunUnregisters.push(installThinkingOverrunPolicy(hooks, thinkingOverrunPolicy, {
|
|
16107
16311
|
baseBudget: thinkingBudget,
|
|
16108
16312
|
enqueueNudge: (message) => nonInterruptingNudgeQueue.push(message)
|
|
@@ -16121,25 +16325,100 @@ function createAgent(rawOptions) {
|
|
|
16121
16325
|
turnUsage: []
|
|
16122
16326
|
};
|
|
16123
16327
|
const wallStartMs = Date.now();
|
|
16124
|
-
const providerContextWindow =
|
|
16328
|
+
const providerContextWindow = runProvider.meta.contextWindow;
|
|
16125
16329
|
const resolvedAutoCompact = resolveAutoCompact(autoCompact, {
|
|
16126
16330
|
...providerContextWindow !== void 0 ? { fallbackContextWindow: providerContextWindow } : {},
|
|
16127
16331
|
...compactKeepTurns !== void 0 ? { compactKeepTurns } : {}
|
|
16128
16332
|
});
|
|
16333
|
+
/**
|
|
16334
|
+
* Loop-view stats synthesized from the live usage mirror.
|
|
16335
|
+
*
|
|
16336
|
+
* Used by every exit that did NOT get a clean `AgentStats` back from
|
|
16337
|
+
* `runLoop` (mid-stream abort, budget breach, hard failure): the mirror
|
|
16338
|
+
* carries the usage of every turn that completed before the throw, so the
|
|
16339
|
+
* persisted record and `agent:done` report real spend instead of zeros.
|
|
16340
|
+
* Wall time comes from `wallStartMs` (a real clock) rather than the
|
|
16341
|
+
* possibly-journaled `runStartedAt`, matching `runLoop`'s own accounting.
|
|
16342
|
+
*/
|
|
16343
|
+
function mirroredLoopStats() {
|
|
16344
|
+
return {
|
|
16345
|
+
totalIn: usageMirror.totalIn,
|
|
16346
|
+
totalOut: usageMirror.totalOut,
|
|
16347
|
+
totalCacheRead: usageMirror.totalCacheRead,
|
|
16348
|
+
totalCacheCreation: usageMirror.totalCacheCreation,
|
|
16349
|
+
turns: usageMirror.turns,
|
|
16350
|
+
elapsed: Date.now() - wallStartMs,
|
|
16351
|
+
turnUsage: usageMirror.turnUsage,
|
|
16352
|
+
...usageMirror.cost > 0 ? { cost: usageMirror.cost } : {}
|
|
16353
|
+
};
|
|
16354
|
+
}
|
|
16355
|
+
/**
|
|
16356
|
+
* The single exit path for a run. Every terminal branch — completed,
|
|
16357
|
+
* clean-break abort, mid-stream abort, budget breach, hard error — routes
|
|
16358
|
+
* through here so all five report identically: children folded into the
|
|
16359
|
+
* returned totals, session ledger written from the loop-only view, run row
|
|
16360
|
+
* stamped, `session:end` fired, then `agent:done` with the final stats.
|
|
16361
|
+
*
|
|
16362
|
+
* Callers that must propagate an error still `throw` after awaiting this;
|
|
16363
|
+
* the finalization itself is outcome-independent.
|
|
16364
|
+
*/
|
|
16365
|
+
async function finishRun(disposition) {
|
|
16366
|
+
const { kind, loopStats, parentCost } = disposition;
|
|
16367
|
+
let childrenIn = 0;
|
|
16368
|
+
let childrenOut = 0;
|
|
16369
|
+
let childrenCost = 0;
|
|
16370
|
+
let childrenCacheRead = 0;
|
|
16371
|
+
let childrenCacheCreation = 0;
|
|
16372
|
+
for (const c of childrenStats) {
|
|
16373
|
+
childrenIn += c.stats.totalIn;
|
|
16374
|
+
childrenOut += c.stats.totalOut;
|
|
16375
|
+
childrenCost += c.stats.cost ?? 0;
|
|
16376
|
+
childrenCacheRead += c.stats.totalCacheRead;
|
|
16377
|
+
childrenCacheCreation += c.stats.totalCacheCreation;
|
|
16378
|
+
}
|
|
16379
|
+
const cumulativeCost = parentCost + childrenCost;
|
|
16380
|
+
const finalStats = {
|
|
16381
|
+
...loopStats,
|
|
16382
|
+
totalIn: loopStats.totalIn + childrenIn,
|
|
16383
|
+
totalOut: loopStats.totalOut + childrenOut,
|
|
16384
|
+
totalCacheRead: loopStats.totalCacheRead + childrenCacheRead,
|
|
16385
|
+
totalCacheCreation: loopStats.totalCacheCreation + childrenCacheCreation,
|
|
16386
|
+
...cumulativeCost > 0 ? { cost: cumulativeCost } : {},
|
|
16387
|
+
children: childrenStats.length > 0 ? childrenStats : void 0
|
|
16388
|
+
};
|
|
16389
|
+
if (session) {
|
|
16390
|
+
const ledger = {
|
|
16391
|
+
turns: loopStats.turns,
|
|
16392
|
+
tokensIn: loopStats.totalIn,
|
|
16393
|
+
tokensOut: loopStats.totalOut,
|
|
16394
|
+
turnUsage: loopStats.turnUsage,
|
|
16395
|
+
...parentCost > 0 ? { cost: parentCost } : {}
|
|
16396
|
+
};
|
|
16397
|
+
if (disposition.kind === "completed") session.completeRun(runId, ledger);
|
|
16398
|
+
else if (disposition.kind === "aborted") session.abortRun(runId, ledger);
|
|
16399
|
+
else session.errorRun(runId, disposition.failure, ledger);
|
|
16400
|
+
}
|
|
16401
|
+
await stampSessionRunEnd();
|
|
16402
|
+
await finalizeSession(kind);
|
|
16403
|
+
await settleWithinTimeout("hook agent:done", hooks.callHook("agent:done", finalStats), hookTimeoutMs);
|
|
16404
|
+
return finalStats;
|
|
16405
|
+
}
|
|
16129
16406
|
try {
|
|
16130
16407
|
await toolStateController.hydrate();
|
|
16131
16408
|
const stats = await runLoop({
|
|
16132
16409
|
provider: runProvider,
|
|
16133
16410
|
targets,
|
|
16134
16411
|
hooks,
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16412
|
+
behavior: resolvedBehavior,
|
|
16413
|
+
inheritance: {
|
|
16414
|
+
...agentName !== void 0 ? { name: agentName } : {},
|
|
16415
|
+
...agentSystem !== void 0 ? { system: agentSystem } : {},
|
|
16416
|
+
tools: sourceTools,
|
|
16417
|
+
...effectiveToolAliases !== void 0 ? { toolAliases: effectiveToolAliases } : {},
|
|
16418
|
+
...allMcpServers.length > 0 ? { mcpServers: allMcpServers } : {},
|
|
16419
|
+
mcpConnection: () => mcpConnection,
|
|
16420
|
+
...agentSkills !== void 0 ? { skills: agentSkills } : {}
|
|
16421
|
+
},
|
|
16143
16422
|
tools,
|
|
16144
16423
|
formattedTools,
|
|
16145
16424
|
rebuildFormattedTools: buildFormattedTools,
|
|
@@ -16147,10 +16426,6 @@ function createAgent(rawOptions) {
|
|
|
16147
16426
|
model,
|
|
16148
16427
|
system,
|
|
16149
16428
|
thinking,
|
|
16150
|
-
...maxConcurrentTools !== void 0 ? { maxConcurrentTools } : {},
|
|
16151
|
-
...toolBatchExecutor !== void 0 ? { toolBatchExecutor } : {},
|
|
16152
|
-
...toolBatchTimeoutMs !== void 0 ? { toolBatchTimeoutMs } : {},
|
|
16153
|
-
...shouldRethrowToolError !== void 0 ? { shouldRethrowToolError } : {},
|
|
16154
16429
|
signal: abortController.signal,
|
|
16155
16430
|
execution: executionContext,
|
|
16156
16431
|
handle: executionHandle,
|
|
@@ -16161,53 +16436,16 @@ function createAgent(rawOptions) {
|
|
|
16161
16436
|
runId,
|
|
16162
16437
|
generateTurnId: mintTurnId,
|
|
16163
16438
|
clock,
|
|
16164
|
-
|
|
16165
|
-
...
|
|
16166
|
-
...maxTurnsWarningMessage !== void 0 ? { maxTurnsWarningMessage } : {},
|
|
16167
|
-
...maxCostUsd !== void 0 ? { maxCostUsd } : {},
|
|
16168
|
-
...maxTotalTokens !== void 0 ? { maxTotalTokens } : {},
|
|
16169
|
-
...maxWallMs !== void 0 ? { maxWallMs } : {},
|
|
16170
|
-
...providerStreamStartTimeoutMs !== void 0 ? { providerStreamStartTimeoutMs } : {},
|
|
16171
|
-
...providerStreamTimeoutMs !== void 0 ? { providerStreamTimeoutMs } : {},
|
|
16172
|
-
...providerStreamIdleTimeoutMs !== void 0 ? { providerStreamIdleTimeoutMs } : {},
|
|
16173
|
-
...resolvedBehavior.hookTimeoutMs !== void 0 ? { hookTimeoutMs: resolvedBehavior.hookTimeoutMs } : {},
|
|
16174
|
-
...retry !== void 0 ? { retry } : {},
|
|
16175
|
-
maxTokens,
|
|
16176
|
-
...modelCatalog !== void 0 ? { modelCatalog } : {},
|
|
16439
|
+
...modelOptions ? { modelOptions } : {},
|
|
16440
|
+
...resolvedAutoCompact ? { autoCompact: resolvedAutoCompact } : {},
|
|
16177
16441
|
...session ? { session } : {},
|
|
16178
16442
|
...agentReadState ? { readState: agentReadState } : {},
|
|
16179
16443
|
toolState: toolStateController,
|
|
16180
16444
|
...options.parentRunId ? { parentRunId: options.parentRunId } : {},
|
|
16181
16445
|
...options.parentCallId ? { parentCallId: options.parentCallId } : {},
|
|
16182
16446
|
depth: runDepth,
|
|
16183
|
-
thinkingBudget,
|
|
16184
|
-
...taskBudget !== void 0 ? { taskBudget } : {},
|
|
16185
|
-
...effortHint !== void 0 ? { effortHint } : {},
|
|
16186
|
-
...modelOptions ? { modelOptions } : {},
|
|
16187
|
-
schema,
|
|
16188
|
-
cache,
|
|
16189
|
-
...cacheTtl !== void 0 ? { cacheTtl } : {},
|
|
16190
|
-
toolOutputBudget,
|
|
16191
|
-
...toolOutputBudgetExcludeTools !== void 0 ? { toolOutputBudgetExcludeTools } : {},
|
|
16192
|
-
compactStrategy,
|
|
16193
|
-
compactThreshold,
|
|
16194
|
-
compactKeepTurns,
|
|
16195
|
-
...elideStaleReads !== void 0 ? { elideStaleReads } : {},
|
|
16196
|
-
...mediaKeepTurns !== void 0 ? { mediaKeepTurns } : {},
|
|
16197
|
-
...resolvedAutoCompact ? { autoCompact: resolvedAutoCompact } : {},
|
|
16198
16447
|
...perTurnSync ? { persistTurns: persistPendingTurns } : {},
|
|
16199
16448
|
getActiveSkills: () => skillActivationState.active(),
|
|
16200
|
-
...thinkingDecay !== void 0 ? { thinkingDecay } : {},
|
|
16201
|
-
...persistThreshold !== void 0 ? { persistThreshold } : {},
|
|
16202
|
-
...persistExcludeTools !== void 0 ? { persistExcludeTools } : {},
|
|
16203
|
-
...persistDir !== void 0 ? { persistDir } : {},
|
|
16204
|
-
...persistMaxBytes !== void 0 ? { persistMaxBytes } : {},
|
|
16205
|
-
...strictToolPairing ? { strictToolPairing: true } : {},
|
|
16206
|
-
...maxPairingRepairsPerTurn !== void 0 ? { maxPairingRepairsPerTurn } : {},
|
|
16207
|
-
...maxConsecutivePauseTurns !== void 0 ? { maxConsecutivePauseTurns } : {},
|
|
16208
|
-
...maxConsecutiveRefusalResumes !== void 0 ? { maxConsecutiveRefusalResumes } : {},
|
|
16209
|
-
...resumeOnMaxTokens !== void 0 ? { resumeOnMaxTokens } : {},
|
|
16210
|
-
...maxConsecutiveLengthResumes !== void 0 ? { maxConsecutiveLengthResumes } : {},
|
|
16211
16449
|
providerName: runProvider.name,
|
|
16212
16450
|
runStartMs,
|
|
16213
16451
|
runToolCounts: {},
|
|
@@ -16215,53 +16453,12 @@ function createAgent(rawOptions) {
|
|
|
16215
16453
|
usageMirror
|
|
16216
16454
|
});
|
|
16217
16455
|
const parentTurnCost = stats.turnUsage?.reduce((sum, t) => sum + (t.cost ?? 0), 0) ?? 0;
|
|
16218
|
-
let childrenIn = 0;
|
|
16219
|
-
let childrenOut = 0;
|
|
16220
|
-
let childrenCost = 0;
|
|
16221
|
-
let childrenCacheRead = 0;
|
|
16222
|
-
let childrenCacheCreation = 0;
|
|
16223
|
-
for (const c of childrenStats) {
|
|
16224
|
-
childrenIn += c.stats.totalIn;
|
|
16225
|
-
childrenOut += c.stats.totalOut;
|
|
16226
|
-
childrenCost += c.stats.cost ?? 0;
|
|
16227
|
-
childrenCacheRead += c.stats.totalCacheRead;
|
|
16228
|
-
childrenCacheCreation += c.stats.totalCacheCreation;
|
|
16229
|
-
}
|
|
16230
|
-
const cumulativeCost = parentTurnCost + childrenCost;
|
|
16231
|
-
const finalStats = {
|
|
16232
|
-
...stats,
|
|
16233
|
-
totalIn: stats.totalIn + childrenIn,
|
|
16234
|
-
totalOut: stats.totalOut + childrenOut,
|
|
16235
|
-
totalCacheRead: stats.totalCacheRead + childrenCacheRead,
|
|
16236
|
-
totalCacheCreation: stats.totalCacheCreation + childrenCacheCreation,
|
|
16237
|
-
...cumulativeCost > 0 ? { cost: cumulativeCost } : {},
|
|
16238
|
-
children: childrenStats.length > 0 ? childrenStats : void 0
|
|
16239
|
-
};
|
|
16240
16456
|
await flushTurns();
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
16245
|
-
tokensOut: stats.totalOut,
|
|
16246
|
-
turnUsage: stats.turnUsage,
|
|
16247
|
-
cost: parentTurnCost > 0 ? parentTurnCost : void 0
|
|
16248
|
-
});
|
|
16249
|
-
await stampSessionRunEnd();
|
|
16250
|
-
await finalizeSession("aborted");
|
|
16251
|
-
await settleWithinTimeout("hook agent:done", hooks.callHook("agent:done", finalStats), hookTimeoutMs);
|
|
16252
|
-
return finalStats;
|
|
16253
|
-
}
|
|
16254
|
-
session?.completeRun(runId, {
|
|
16255
|
-
turns: stats.turns,
|
|
16256
|
-
tokensIn: stats.totalIn,
|
|
16257
|
-
tokensOut: stats.totalOut,
|
|
16258
|
-
turnUsage: stats.turnUsage,
|
|
16259
|
-
cost: parentTurnCost > 0 ? parentTurnCost : void 0
|
|
16457
|
+
return await finishRun({
|
|
16458
|
+
kind: abortController.signal.aborted ? "aborted" : "completed",
|
|
16459
|
+
loopStats: stats,
|
|
16460
|
+
parentCost: parentTurnCost
|
|
16260
16461
|
});
|
|
16261
|
-
await stampSessionRunEnd();
|
|
16262
|
-
await finalizeSession("completed");
|
|
16263
|
-
await settleWithinTimeout("hook agent:done", hooks.callHook("agent:done", finalStats), hookTimeoutMs);
|
|
16264
|
-
return finalStats;
|
|
16265
16462
|
} catch (err) {
|
|
16266
16463
|
await flushTurns({ failureFallback: true });
|
|
16267
16464
|
if (abortController.signal.aborted) {
|
|
@@ -16270,84 +16467,39 @@ function createAgent(rawOptions) {
|
|
|
16270
16467
|
...runId ? { runId } : {},
|
|
16271
16468
|
...typeof abortReason === "string" && abortReason.length > 0 ? { reason: abortReason } : {}
|
|
16272
16469
|
});
|
|
16273
|
-
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
turnUsage: usageMirror.turnUsage,
|
|
16278
|
-
cost: usageMirror.cost > 0 ? usageMirror.cost : void 0
|
|
16470
|
+
return await finishRun({
|
|
16471
|
+
kind: "aborted",
|
|
16472
|
+
loopStats: mirroredLoopStats(),
|
|
16473
|
+
parentCost: usageMirror.cost
|
|
16279
16474
|
});
|
|
16280
|
-
await stampSessionRunEnd();
|
|
16281
|
-
await finalizeSession("aborted");
|
|
16282
|
-
const stats = {
|
|
16283
|
-
totalIn: usageMirror.totalIn,
|
|
16284
|
-
totalOut: usageMirror.totalOut,
|
|
16285
|
-
totalCacheRead: usageMirror.totalCacheRead,
|
|
16286
|
-
totalCacheCreation: usageMirror.totalCacheCreation,
|
|
16287
|
-
turns: usageMirror.turns,
|
|
16288
|
-
elapsed: Date.now() - wallStartMs,
|
|
16289
|
-
turnUsage: usageMirror.turnUsage,
|
|
16290
|
-
...usageMirror.cost > 0 ? { cost: usageMirror.cost } : {}
|
|
16291
|
-
};
|
|
16292
|
-
await settleWithinTimeout("hook agent:done", hooks.callHook("agent:done", stats), hookTimeoutMs);
|
|
16293
|
-
return stats;
|
|
16294
16475
|
}
|
|
16295
16476
|
if (err instanceof AgentBudgetExceededError) {
|
|
16296
|
-
|
|
16297
|
-
|
|
16298
|
-
|
|
16299
|
-
|
|
16300
|
-
turnUsage: usageMirror.turnUsage,
|
|
16301
|
-
cost: usageMirror.cost > 0 ? usageMirror.cost : void 0
|
|
16477
|
+
await finishRun({
|
|
16478
|
+
kind: "aborted",
|
|
16479
|
+
loopStats: mirroredLoopStats(),
|
|
16480
|
+
parentCost: usageMirror.cost
|
|
16302
16481
|
});
|
|
16303
|
-
await stampSessionRunEnd();
|
|
16304
|
-
await finalizeSession("aborted");
|
|
16305
|
-
await settleWithinTimeout("hook agent:done", hooks.callHook("agent:done", {
|
|
16306
|
-
totalIn: usageMirror.totalIn,
|
|
16307
|
-
totalOut: usageMirror.totalOut,
|
|
16308
|
-
totalCacheRead: usageMirror.totalCacheRead,
|
|
16309
|
-
totalCacheCreation: usageMirror.totalCacheCreation,
|
|
16310
|
-
turns: usageMirror.turns,
|
|
16311
|
-
elapsed: Date.now() - wallStartMs,
|
|
16312
|
-
turnUsage: usageMirror.turnUsage,
|
|
16313
|
-
...usageMirror.cost > 0 ? { cost: usageMirror.cost } : {}
|
|
16314
|
-
}), hookTimeoutMs);
|
|
16315
16482
|
throw err;
|
|
16316
16483
|
}
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
totalCacheRead: usageMirror.totalCacheRead,
|
|
16324
|
-
totalCacheCreation: usageMirror.totalCacheCreation,
|
|
16325
|
-
turns: usageMirror.turns,
|
|
16326
|
-
elapsed: Date.now() - wallStartMs,
|
|
16327
|
-
turnUsage: usageMirror.turnUsage,
|
|
16328
|
-
...usageMirror.cost > 0 ? { cost: usageMirror.cost } : {}
|
|
16329
|
-
}), hookTimeoutMs);
|
|
16484
|
+
await finishRun({
|
|
16485
|
+
kind: "error",
|
|
16486
|
+
loopStats: mirroredLoopStats(),
|
|
16487
|
+
parentCost: usageMirror.cost,
|
|
16488
|
+
failure: errorMessage(err)
|
|
16489
|
+
});
|
|
16330
16490
|
throw err;
|
|
16331
16491
|
} finally {
|
|
16332
16492
|
await deactivateAllSkills();
|
|
16333
|
-
uninstallAllowedToolsGate();
|
|
16334
|
-
uninstallDedupTools();
|
|
16335
|
-
uninstallRepeatGuard();
|
|
16336
|
-
uninstallToolBudgets();
|
|
16337
|
-
uninstallLazyDisclosureHydration();
|
|
16338
|
-
uninstallLazyDisclosureGate();
|
|
16339
|
-
uninstallReadBeforeEditHydration();
|
|
16340
|
-
uninstallSkillsActivationHydration();
|
|
16341
|
-
unregisterSpawnHook();
|
|
16342
|
-
unregisterTurnSync?.();
|
|
16343
|
-
unregisterToolResultsSync?.();
|
|
16344
16493
|
for (const unregister of perRunUnregisters) unregister();
|
|
16494
|
+
perRunUnregisters.length = 0;
|
|
16345
16495
|
steeringQueue.length = 0;
|
|
16346
16496
|
nonInterruptingNudgeQueue.length = 0;
|
|
16347
16497
|
followUpQueue.length = 0;
|
|
16348
16498
|
resetRunScope();
|
|
16349
16499
|
}
|
|
16350
16500
|
} finally {
|
|
16501
|
+
for (const unregister of perRunUnregisters) unregister();
|
|
16502
|
+
perRunUnregisters.length = 0;
|
|
16351
16503
|
resetRunScope();
|
|
16352
16504
|
if (externalSignal && externalAbortListener) externalSignal.removeEventListener("abort", externalAbortListener);
|
|
16353
16505
|
}
|
|
@@ -16680,6 +16832,22 @@ function createAgent(rawOptions) {
|
|
|
16680
16832
|
wireTools
|
|
16681
16833
|
});
|
|
16682
16834
|
}
|
|
16835
|
+
async function getContextSegments(opts) {
|
|
16836
|
+
if (destroyed) return null;
|
|
16837
|
+
const assembly = lastContextAssembly ?? await buildPreRunAssembly();
|
|
16838
|
+
if (!assembly) return null;
|
|
16839
|
+
const rulesBlock = opts?.rulesBlock ?? assembly.rulesBlock;
|
|
16840
|
+
return buildContextSegments({
|
|
16841
|
+
system: assembly.system,
|
|
16842
|
+
baseSystem: assembly.baseSystem,
|
|
16843
|
+
...rulesBlock ? { rulesBlock } : {},
|
|
16844
|
+
...opts?.rulesFiles?.length ? { rulesFiles: opts.rulesFiles } : {},
|
|
16845
|
+
...opts?.systemPath !== void 0 ? { systemPath: opts.systemPath } : {},
|
|
16846
|
+
...assembly.skillsCatalog ? { skillsCatalog: assembly.skillsCatalog } : {},
|
|
16847
|
+
...assembly.mcpInstructions ? { mcpInstructions: assembly.mcpInstructions } : {},
|
|
16848
|
+
...assembly.subagentDefs ? { subagentDefs: assembly.subagentDefs } : {}
|
|
16849
|
+
});
|
|
16850
|
+
}
|
|
16683
16851
|
async function getContextBreakdown(opts) {
|
|
16684
16852
|
if (destroyed) return null;
|
|
16685
16853
|
const assembly = lastContextAssembly ?? await buildPreRunAssembly(opts?.model);
|
|
@@ -16793,10 +16961,11 @@ function createAgent(rawOptions) {
|
|
|
16793
16961
|
},
|
|
16794
16962
|
meta: Object.freeze({ ...provider.meta }),
|
|
16795
16963
|
getContextBreakdown,
|
|
16964
|
+
getContextSegments,
|
|
16796
16965
|
[Symbol.asyncDispose]: destroy
|
|
16797
16966
|
};
|
|
16798
16967
|
}
|
|
16799
16968
|
//#endregion
|
|
16800
16969
|
export { installExtensionFromSpec as $, groupBindings as $t, selectFilesFromSession as A, defaultRepeatGuardNormalize as An, createSkillsReadTool as At, buildUpToCompactPrompt as B, matchModelEntries as Bt, resolveLegacySessionDir as C, resolveExtensionConfigValue as Cn, waitTask as Ct, resolveTasksDir as D, OUTPUT_RESERVE_TOKENS as Dn, reserveChildLabel as Dt, resolveSessionDir as E, AUTO_COMPACT_MIN_GROWTH_FRACTION as En, isSpawnTool as Et, TRAILER as F, hashContent as Fn, readFile$1 as Ft, summaryToTurn as G, edit as Gt, anchorPreviewFor as H, createInteractionTool as Ht, buildCompactPrompt as I, hydrateReadStateFromSession as In, looksBinary as It, CompactPromptTooLongError as J, KEYBINDING_DEFS as Jt, truncateHeadForPtlRetry as K, validateToolArgs as Kt, buildFromCompactPrompt as L, hydrateReadStateFromSessionAsync as Ln, multiEdit as Lt, compactConversation as M, normalizeShellCommand as Mn, createShellTool as Mt, BASE_INSTRUCTIONS as N, stableStringify as Nn, shell as Nt, buildPostCompactAttachments as O, effectiveContextWindow as On, createSkillsUseTool as Ot, NO_TOOLS_PREAMBLE as P, getReadState as Pn, tailTruncate as Pt, fetchExtensionSource as Q, formatBindingForDisplay as Qt, buildFullCompactPrompt as R, readStateKey as Rn, createModelSearchTool as Rt, resolveLegacyPersistDir as S, resolveExtensionConfig as Sn, WAIT_TASK_TIMED_OUT_PREFIX as St, resolvePersistDir as T, toWireConfigSchema as Tn, createSpawnTool as Tt, sliceForCompaction as U, grep as Ut, ANCHOR_PREVIEW_MAX_CHARS as V, listFiles as Vt, stripImagesFromTurns as W, glob as Wt, createExtensionPromptBridge as X, KEYBINDING_KEY_COL_WIDTH as Xt, EMPTY_EXTENSION_REGISTRY as Y, KEYBINDING_DEF_BY_ACTION as Yt, ExtensionInstallError as Z, ensureKeybindingsFile as Zt, buildPersistedStub as _, defineExtension as _n, composePresets as _t, stagedToolState as a, readKeybindingsRaw as an, createExtensionHud as at, migrateSessionArtifactDirs as b, isValidExtensionConfigItem as bn, basic_default as bt, INTERRUPT_MESSAGE_FOR_TOOL_USE as c, registerExtensionHostModules as cn, buildExtensionRegistry as ct, TOOL_USE_SKIPPED_MESSAGE as d, discoverExtensions as dn, filterExtensionRegistry as dt, keybindingsPath as en, listExtensionCandidates as et, applyCompactSummaryCutoff as f, inlineLoadedExtension as fn, filterRegistryPlugins as ft, PERSISTENCE_PREVIEW_BYTES as g, createDebugLog as gn, createWorkspaceSurface as gt, PERSISTED_STUB_PREFIX as h, scanExtensionDirectories as hn, createExtensionHostRuntimeBridge as ht, isToolStateOps as i, readKeybindings as in, updateInstalledExtension as it, selectRecentFiles as j, defaultRepeatGuardTracked as jn, shellKill as jt, selectFilesFromReadState as k, shouldAutoCompact as kn, createSkillsRunScriptTool as kt, SHELL_CASCADE_CANCEL_MESSAGE as l, ENTRY_CANDIDATES as ln, composeExtensionPreset as lt, renderStaleReadNotice as m, parseExtensionScanPathEnv as mn, partitionExtensionCatalog as mt, DEFAULT_MAX_VALUE_BYTES as n, mergeKeybindings as nn, readExtensionInstallProvenance as nt, normalizeProviders as o, resolveExtensionKeybindings as on, discoverAndBuildExtensionRegistry as ot, collectNewlyStaleReadPaths as p, isExtensionDefinition as pn, mergeContributions as pt, CompactInvalidInputError as q, DEFAULT_KEYBINDINGS as qt, createToolStateController as r, parseBindingSpec as rn, removeInstalledExtension as rt, resolveModelTargets as s, stripJsonComments as sn, buildExtensionPreset as st, createAgent as t, matchesBinding as tn, parseExtensionInstallSource as tt, TOOL_USE_CANCELLED_MESSAGE as u, defaultExtensionScanPaths as un, disposeExtensionRegistry as ut, cleanupPersistedSession as v, clampExtensionConfigNumber as vn, definePreset as vt, resolveMcpWarningsDir as w, sanitizeExtensionConfigActionPatch as wn, createToolSearchTool as wt, rehomePersistedStubs as x, isValidExtensionConfigValue as xn, writeFile$1 as xt, maybePersistToolResult as y, coerceExtensionConfigInput as yn, basicTools as yt, buildTailCompactPrompt as z, resolveReadStateMap as zn, formatModelLine as zt };
|
|
16801
16970
|
|
|
16802
|
-
//# sourceMappingURL=agent-
|
|
16971
|
+
//# sourceMappingURL=agent-8kfGIDb_.js.map
|