@cydm/pie 2.7.6 → 2.7.8

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.
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from "node:module"; const require =
2
2
  import {
3
3
  Agent,
4
4
  getToolCallerIdentity
5
- } from "./chunk-5YWEUFLM.js";
5
+ } from "./chunk-W5B3OXHQ.js";
6
6
  import {
7
7
  AssistantMessageEventStream,
8
8
  FileSystemGateway,
@@ -12,7 +12,7 @@ import {
12
12
  getPlatformConfig,
13
13
  hashText,
14
14
  streamSimple
15
- } from "./chunk-ZF5FHTES.js";
15
+ } from "./chunk-2FEDB5GR.js";
16
16
  import {
17
17
  Type
18
18
  } from "./chunk-XXGYUYXI.js";
@@ -899,11 +899,6 @@ function shouldPreserveExecutionStateForUserText(text) {
899
899
  return CONTINUE_PATTERNS.some((pattern) => pattern.test(trimmed));
900
900
  }
901
901
 
902
- // ../../packages/shared-headless-capabilities/src/capability.ts
903
- function defineSharedCapability(definition) {
904
- return definition;
905
- }
906
-
907
902
  // ../../packages/shared-headless-capabilities/src/tool-policy.ts
908
903
  var BUILTIN_TOOL_CAPABILITY_METADATA = {
909
904
  search_context: { riskClass: "read_only", concurrencySafe: true, permissionScope: "session", availableInPlanMode: true, allowedForSubagentByDefault: false, maxOutputChars: 2e4 },
@@ -914,6 +909,7 @@ var BUILTIN_TOOL_CAPABILITY_METADATA = {
914
909
  write_file: { riskClass: "write", concurrencySafe: false, requiresPermission: true, permissionScope: "filesystem", writesFile: true, highRisk: true },
915
910
  edit_file: { riskClass: "write", concurrencySafe: false, requiresPermission: true, permissionScope: "filesystem", writesFile: true, highRisk: true },
916
911
  bash: { riskClass: "shell", concurrencySafe: false, requiresPermission: true, permissionScope: "shell", executesShell: true, availableInPlanMode: true, allowedForSubagentByDefault: true, highRisk: true, maxOutputChars: 1e5 },
912
+ shell: { riskClass: "shell", concurrencySafe: false, requiresPermission: true, permissionScope: "shell", executesShell: true, availableInPlanMode: true, allowedForSubagentByDefault: true, highRisk: true, maxOutputChars: 1e5 },
917
913
  web_research: { riskClass: "network", concurrencySafe: true, permissionScope: "network", readsNetwork: true, availableInPlanMode: true, allowedForSubagentByDefault: true, maxOutputChars: 1e5 },
918
914
  web_search: { riskClass: "network", concurrencySafe: true, permissionScope: "network", readsNetwork: true, availableInPlanMode: true, allowedForSubagentByDefault: true, maxOutputChars: 1e5 },
919
915
  web_fetch: { riskClass: "network", concurrencySafe: true, permissionScope: "network", readsNetwork: true, availableInPlanMode: true, allowedForSubagentByDefault: true, maxOutputChars: 1e5 },
@@ -975,6 +971,11 @@ function getSubagentToolPolicyDecision(tool) {
975
971
  }
976
972
  var DEFAULT_PLAN_MODE_TOOL_NAMES = Object.entries(BUILTIN_TOOL_CAPABILITY_METADATA).filter(([, metadata]) => metadata.availableInPlanMode).map(([name]) => name);
977
973
 
974
+ // ../../packages/shared-headless-capabilities/src/capability.ts
975
+ function defineSharedCapability(definition) {
976
+ return definition;
977
+ }
978
+
978
979
  // ../../packages/shared-headless-capabilities/src/plan.ts
979
980
  var import_shell_quote = __toESM(require_shell_quote(), 1);
980
981
  var SIMPLE_READ_COMMANDS = /* @__PURE__ */ new Set(["pwd", "ls", "cat", "head", "tail", "wc", "grep", "rg", "which", "type", "echo", "printf", "cd", "true", "false", "tree", "jq", "stat", "file", "du", "df", "basename", "dirname", "date", "uname", "sort", "uniq", "cut", "column", "shasum", "printenv"]);
@@ -1752,6 +1753,9 @@ function normalizeUserContentBlock(block) {
1752
1753
  if (block.type === "text") {
1753
1754
  return { type: "text", text: block.text };
1754
1755
  }
1756
+ if (block.type === "hostContext") {
1757
+ return { type: "text", text: "x".repeat(512) };
1758
+ }
1755
1759
  if (block.type === "image") {
1756
1760
  return { type: "image", mimeType: block.mimeType };
1757
1761
  }
@@ -1932,6 +1936,109 @@ function getSessionEntryText(entry) {
1932
1936
  }).filter(Boolean).join("\n");
1933
1937
  }
1934
1938
 
1939
+ // ../../packages/agent-framework/src/session/host-envelope.ts
1940
+ import { createHash } from "node:crypto";
1941
+ function createHostEnvelopeProjectorRegistry(projectors = []) {
1942
+ const byKey = /* @__PURE__ */ new Map();
1943
+ const latestByKind = /* @__PURE__ */ new Map();
1944
+ const key = (kind, version) => `${kind}@${version}`;
1945
+ for (const projector of projectors) validateAndIndex(projector);
1946
+ function validateAndIndex(input) {
1947
+ if (!input.kind || typeof input.kind !== "string") throw new Error("Host envelope projector requires a kind.");
1948
+ if (!Number.isInteger(input.version) || input.version < 1) throw new Error(`Host envelope projector ${input.kind} requires an integer version >= 1.`);
1949
+ if (typeof input.project !== "function") throw new Error(`Host envelope projector ${input.kind} requires a project function.`);
1950
+ const projector = Object.freeze({
1951
+ kind: input.kind,
1952
+ version: input.version,
1953
+ project: input.project
1954
+ });
1955
+ const existing = byKey.get(key(projector.kind, projector.version));
1956
+ if (existing && existing.project !== projector.project) {
1957
+ throw new Error(`Duplicate host envelope projector registration for ${projector.kind}@${projector.version}: a version's text must never change after registration.`);
1958
+ }
1959
+ byKey.set(key(projector.kind, projector.version), projector);
1960
+ const currentLatest = latestByKind.get(projector.kind);
1961
+ if (!currentLatest || projector.version > currentLatest.version) latestByKind.set(projector.kind, projector);
1962
+ }
1963
+ return {
1964
+ register: validateAndIndex,
1965
+ resolve: (kind, version) => byKey.get(key(kind, version)),
1966
+ latest: (kind) => latestByKind.get(kind),
1967
+ listPins: () => [...byKey.values()].map(({ kind, version }) => ({ kind, version }))
1968
+ };
1969
+ }
1970
+ function projectHostContextBlock(block, registry) {
1971
+ let hash;
1972
+ try {
1973
+ hash = createHash("sha256").update(JSON.stringify({ kind: block.kind, version: block.version, data: block.data })).digest("hex").slice(0, 16);
1974
+ } catch {
1975
+ hash = "unhashable";
1976
+ }
1977
+ const projector = registry.resolve(block.kind, block.version);
1978
+ if (!projector) {
1979
+ return {
1980
+ text: `runtime state: unknown (projector missing: ${block.kind}@${block.version})`,
1981
+ degraded: true,
1982
+ audit: { kind: block.kind, version: block.version, hash }
1983
+ };
1984
+ }
1985
+ try {
1986
+ const text = projector.project(block.data);
1987
+ if (typeof text !== "string" || text.trim().length === 0) throw new Error("projector returned empty text");
1988
+ return { text, degraded: false, audit: { kind: block.kind, version: block.version, hash } };
1989
+ } catch (error) {
1990
+ return {
1991
+ text: `runtime state: unknown (projector failed: ${block.kind}@${block.version}: ${error instanceof Error ? error.message.slice(0, 120) : String(error).slice(0, 120)})`,
1992
+ degraded: true,
1993
+ audit: { kind: block.kind, version: block.version, hash }
1994
+ };
1995
+ }
1996
+ }
1997
+ function leadingHostContextBlock(message) {
1998
+ if (message.role !== "user") return void 0;
1999
+ const content = message.content;
2000
+ if (!Array.isArray(content) || content.length === 0) return void 0;
2001
+ const first = content[0];
2002
+ if (!isHostContextBlock(first)) return void 0;
2003
+ return first;
2004
+ }
2005
+ function projectionSeparator(projectionText) {
2006
+ return projectionText.endsWith("\n") && !projectionText.endsWith("\n\n") ? "" : "\n\n";
2007
+ }
2008
+ function projectHostEnvelopes(messages, registry, onProjection) {
2009
+ let changed = false;
2010
+ const next = [];
2011
+ for (const message of messages) {
2012
+ const block = leadingHostContextBlock(message);
2013
+ if (!block) {
2014
+ next.push(message);
2015
+ continue;
2016
+ }
2017
+ const outcome = projectHostContextBlock(block, registry);
2018
+ onProjection?.(outcome);
2019
+ const content = message.content;
2020
+ const rest = content.slice(1);
2021
+ const separator = projectionSeparator(outcome.text);
2022
+ const first = rest[0];
2023
+ let projectedContent;
2024
+ if (first && first.type === "text" && typeof first.text === "string") {
2025
+ const merged = first.text.trim().length > 0 ? `${outcome.text}${separator}${first.text}` : outcome.text;
2026
+ projectedContent = [{ ...first, text: merged }, ...rest.slice(1)];
2027
+ } else {
2028
+ projectedContent = [{ type: "text", text: outcome.text }, ...rest];
2029
+ }
2030
+ next.push({ ...message, content: projectedContent });
2031
+ changed = true;
2032
+ }
2033
+ return changed ? next : messages;
2034
+ }
2035
+ function isHostContextBlock(value) {
2036
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2037
+ const block = value;
2038
+ const version = block.version;
2039
+ return block.type === "hostContext" && typeof block.kind === "string" && block.kind.length > 0 && block.kind.length <= 128 && typeof version === "number" && Number.isInteger(version) && version >= 1 && !!block.data && typeof block.data === "object" && !Array.isArray(block.data);
2040
+ }
2041
+
1935
2042
  // ../../packages/agent-framework/src/session/store.ts
1936
2043
  import { createRequire } from "node:module";
1937
2044
  import { fileURLToPath } from "node:url";
@@ -2972,7 +3079,19 @@ function normalizeSessionDisplayName(raw) {
2972
3079
  }
2973
3080
  function isSyntheticEnvelopePreview(preview) {
2974
3081
  const trimmed = preview.trimStart();
2975
- return trimmed.startsWith("<environment_context>") || trimmed.startsWith("<turn_aborted>") || trimmed.startsWith("# AGENTS.md instructions") || trimmed.startsWith("## Project Context\nProject-specific instructions from AGENTS.md");
3082
+ if (trimmed.startsWith("<environment_context>") || trimmed.startsWith("<turn_aborted>") || trimmed.startsWith("# AGENTS.md instructions") || trimmed.startsWith("## Project Context\nProject-specific instructions from AGENTS.md")) {
3083
+ return true;
3084
+ }
3085
+ const runtimeMatch = trimmed.match(/^<runtime-mode-context>[\s\S]*?<\/runtime-mode-context>/);
3086
+ if (runtimeMatch) {
3087
+ const rest = trimmed.slice(runtimeMatch[0].length).trim();
3088
+ if (rest.length === 0) return true;
3089
+ return false;
3090
+ }
3091
+ if (trimmed.startsWith("<runtime-mode-context>")) {
3092
+ return true;
3093
+ }
3094
+ return /^HE_INPUT kind=(?:USER_REQUEST|QUEUE_WAKE) source=/.test(trimmed);
2976
3095
  }
2977
3096
  function isAutoGeneratedSessionName(name) {
2978
3097
  return /^Session (\d|[a-z0-9]{6,8}$)/i.test(name.trim());
@@ -2986,7 +3105,10 @@ function userEntryPreview(entry) {
2986
3105
  if (!message) return "";
2987
3106
  if (typeof message.content === "string") return message.content;
2988
3107
  if (!Array.isArray(message.content)) return "";
2989
- return message.content.map((block) => isRecord2(block) && block.type === "text" && typeof block.text === "string" ? block.text : "").join(" ").trim();
3108
+ return message.content.map((block) => {
3109
+ if (isRecord2(block) && block.type === "hostContext") return "";
3110
+ return isRecord2(block) && block.type === "text" && typeof block.text === "string" ? block.text : "";
3111
+ }).join(" ").trim();
2990
3112
  }
2991
3113
  function entryJsonBytes(entry) {
2992
3114
  try {
@@ -4917,7 +5039,7 @@ function isUserContentBlock(value) {
4917
5039
  return false;
4918
5040
  }
4919
5041
  const type = value.type;
4920
- return type === "text" || type === "image" || type === "audio" || type === "video" || type === "fileRef";
5042
+ return type === "text" || type === "image" || type === "audio" || type === "video" || type === "fileRef" || type === "hostContext";
4921
5043
  }
4922
5044
  function normalizePromptInput(input) {
4923
5045
  if (typeof input === "string") {
@@ -5629,7 +5751,7 @@ function toolOutcomeKind(event) {
5629
5751
  return typeof kind === "string" ? kind : void 0;
5630
5752
  }
5631
5753
  function isCommandNonzero(event) {
5632
- return event.toolName === "bash" && toolOutcomeKind(event) === "command_nonzero";
5754
+ return toolOutcomeKind(event) === "command_nonzero";
5633
5755
  }
5634
5756
  function isStateChangingSuccess(event) {
5635
5757
  if (event.isError) return false;
@@ -5637,7 +5759,7 @@ function isStateChangingSuccess(event) {
5637
5759
  if (outcomeKind === "command_nonzero" || outcomeKind === "timeout" || outcomeKind === "signal") return false;
5638
5760
  if (event.toolName === "edit_file" || event.toolName === "write_file") return true;
5639
5761
  const details = event.result && typeof event.result === "object" ? event.result.details : void 0;
5640
- return event.toolName === "bash" && details?.commandClass === "filesystem_write";
5762
+ return details?.commandClass === "filesystem_write";
5641
5763
  }
5642
5764
  var AgentSessionRuntimeGuard = class {
5643
5765
  constructor(trigger, advise) {
@@ -7915,14 +8037,22 @@ var SessionTraceSnapshotWriter = class {
7915
8037
 
7916
8038
  // ../../packages/agent-framework/src/delegation.ts
7917
8039
  var DELEGATION_REPORT_MAX_CHARS = 24e3;
7918
- var DELEGATION_REPORT_INSTRUCTION = 'Return your final response once as a JSON object: {"summary":string,"result":string,"remainingWork"?:string[],"evidenceRefs"?:string[]}. Do not make an extra tool call to report. Evidence references are your claims, not runtime verification.';
8040
+ var DELEGATION_REPORT_INSTRUCTION = 'Return your final response once as a JSON object: {"summary":string,"result":string,"remainingWork"?:string[],"evidenceRefs"?:string[]}. Keep the entire JSON response within 24,000 characters: give concise conclusions and bounded evidence references, not repeated drafting notes. Do not make an extra tool call to report. Evidence references are your claims, not runtime verification.';
7919
8041
  function parseDelegationReport(text, runId, truncated = false) {
7920
8042
  const raw = (text ?? "").slice(0, DELEGATION_REPORT_MAX_CHARS);
7921
8043
  const base = { version: 1, runId: runId.slice(0, 160), raw };
7922
- if (truncated || (text?.length ?? 0) > DELEGATION_REPORT_MAX_CHARS) return { ...base, availability: "truncated" };
7923
- if (!raw.trim()) return { ...base, availability: "missing" };
8044
+ const stopReason = typeof truncated === "string" ? truncated.slice(0, 40) : void 0;
8045
+ const reason = stopReason === "length" ? "provider_length" : ["error", "aborted", "deadline", "cancelled", "no_terminal"].includes(stopReason ?? "") ? stopReason : stopReason && stopReason !== "stop" ? "no_terminal" : truncated === true ? "provider_length" : void 0;
8046
+ if (reason) return { ...base, stopReason, reason, availability: raw ? "truncated" : "missing" };
8047
+ if ((text?.length ?? 0) > DELEGATION_REPORT_MAX_CHARS) return { ...base, availability: "truncated", reason: "char_cap" };
8048
+ if (!raw.trim()) return { ...base, availability: "missing", reason: "empty" };
8049
+ let value;
8050
+ try {
8051
+ value = JSON.parse(raw);
8052
+ } catch {
8053
+ return { ...base, availability: "malformed", reason: "invalid_json" };
8054
+ }
7924
8055
  try {
7925
- const value = JSON.parse(raw);
7926
8056
  if (!value || typeof value !== "object" || Array.isArray(value) || typeof value.summary !== "string" || typeof value.result !== "string") throw new Error();
7927
8057
  if (Object.keys(value).some((key) => !["summary", "result", "remainingWork", "evidenceRefs"].includes(key))) throw new Error();
7928
8058
  for (const key of ["remainingWork", "evidenceRefs"]) {
@@ -7930,7 +8060,7 @@ function parseDelegationReport(text, runId, truncated = false) {
7930
8060
  }
7931
8061
  return { ...base, availability: "available", report: value };
7932
8062
  } catch {
7933
- return { ...base, availability: "malformed" };
8063
+ return { ...base, availability: "malformed", reason: "invalid_shape" };
7934
8064
  }
7935
8065
  }
7936
8066
  function observeDelegationPhase(observation, phase, workActivity = true) {
@@ -7959,6 +8089,58 @@ function observeDelegationTool(observation, event) {
7959
8089
  if (observation.receipts.length > 32) observation.receipts.shift();
7960
8090
  }
7961
8091
 
8092
+ // ../../packages/shared-headless-capabilities/src/subagent-usage.ts
8093
+ function createSubagentUsage(sessionId, runId) {
8094
+ return { sessionId, runId, attempts: 0, reportedAttempts: 0, unknownAttempts: 0, pendingAttempts: 0, status: "pending", reportedTokens: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cacheWriteLong: 0, totalTokens: 0 }, estimatedCost: null };
8095
+ }
8096
+ function settleSubagentUsage(usage, settled) {
8097
+ usage.status = !settled || usage.pendingAttempts > 0 ? "pending" : usage.attempts === 0 || usage.reportedAttempts === 0 ? "unknown" : usage.unknownAttempts > 0 ? "partial" : "complete";
8098
+ }
8099
+ function beginSubagentUsage(usage, model) {
8100
+ usage.attempts++;
8101
+ usage.pendingAttempts++;
8102
+ let ended = false;
8103
+ return (message) => {
8104
+ if (ended) return;
8105
+ ended = true;
8106
+ usage.pendingAttempts--;
8107
+ const values = message?.usage;
8108
+ const known = message?.usageReported === true && values && [values.input, values.output, values.cacheRead, values.cacheWrite, values.totalTokens].every((n) => Number.isFinite(n) && n >= 0);
8109
+ if (known) {
8110
+ usage.reportedAttempts++;
8111
+ for (const key of Object.keys(usage.reportedTokens)) usage.reportedTokens[key] += values[key] ?? 0;
8112
+ } else usage.unknownAttempts++;
8113
+ const priced = known && ["input", "output", "cacheRead", "cacheWrite"].every((key) => typeof model?.cost?.[key] === "number" && Number.isFinite(model.cost[key]) && model.cost[key] >= 0) && Object.values(model.cost).some((value) => typeof value === "number" && value > 0) && Number.isFinite(values.cost?.total) && values.cost.total >= 0;
8114
+ if (usage.attempts === 1 && priced) usage.estimatedCost = values.cost.total;
8115
+ else if (priced && usage.estimatedCost !== null) usage.estimatedCost += values.cost.total;
8116
+ else usage.estimatedCost = null;
8117
+ };
8118
+ }
8119
+ function restoreSubagentUsageRuns(value) {
8120
+ if (!Array.isArray(value)) return void 0;
8121
+ return value.slice(-4).flatMap((item) => {
8122
+ if (!item || typeof item !== "object" || typeof item.sessionId !== "string" || typeof item.runId !== "string" || item.sessionId.length > 160 || item.runId.length > 160 || !["pending", "partial", "complete", "unknown"].includes(item.status)) return [];
8123
+ if (![item.attempts, item.reportedAttempts, item.unknownAttempts, item.pendingAttempts].every((n) => Number.isSafeInteger(n) && n >= 0)) return [];
8124
+ if (item.reportedAttempts + item.unknownAttempts + item.pendingAttempts !== item.attempts) return [];
8125
+ const tokens = item.reportedTokens;
8126
+ const keys = ["input", "output", "cacheRead", "cacheWrite", "cacheWriteLong", "totalTokens"];
8127
+ if (!tokens || !keys.every((key) => Number.isFinite(tokens[key]) && tokens[key] >= 0)) return [];
8128
+ const expectedStatus = item.pendingAttempts > 0 ? "pending" : item.reportedAttempts === 0 ? "unknown" : item.unknownAttempts > 0 ? "partial" : "complete";
8129
+ if (item.status !== expectedStatus && !(item.status === "pending" && item.attempts === 0)) return [];
8130
+ return [{
8131
+ sessionId: item.sessionId,
8132
+ runId: item.runId,
8133
+ attempts: item.attempts,
8134
+ reportedAttempts: item.reportedAttempts,
8135
+ unknownAttempts: item.unknownAttempts,
8136
+ pendingAttempts: item.pendingAttempts,
8137
+ status: item.status,
8138
+ reportedTokens: Object.fromEntries(keys.map((key) => [key, tokens[key]])),
8139
+ estimatedCost: item.reportedAttempts > 0 && item.unknownAttempts === 0 && item.pendingAttempts === 0 && typeof item.estimatedCost === "number" && Number.isFinite(item.estimatedCost) && item.estimatedCost >= 0 ? item.estimatedCost : null
8140
+ }];
8141
+ });
8142
+ }
8143
+
7962
8144
  // ../../packages/shared-headless-capabilities/src/subagent-stream.ts
7963
8145
  var SUBAGENT_FINALIZATION_HINT = "The run's soft deadline has arrived. Do not start new tools. Return the requested final report now, including remaining work; already-running tools may finish.";
7964
8146
  function subagentSoftDeadlineMs(budgetMs) {
@@ -7969,6 +8151,10 @@ function withSubagentRunContext(stream, hooks) {
7969
8151
  if (hooks.hardDeadlineAt !== void 0 && Date.now() >= hooks.hardDeadlineAt) throw new Error("Subagent hard deadline reached");
7970
8152
  if (hooks.softDeadlineAt !== void 0 && Date.now() >= hooks.softDeadlineAt) hooks.finalizing = true;
7971
8153
  if (hooks.observation) observeDelegationPhase(hooks.observation, hooks.finalizing ? "finalizing" : "request");
8154
+ try {
8155
+ hooks.onPhase?.(hooks.finalizing ? "finalizing" : "request");
8156
+ } catch {
8157
+ }
7972
8158
  return stream(model, hooks.finalizing ? { ...context, systemPrompt: `${context.systemPrompt ?? ""}
7973
8159
 
7974
8160
  ${SUBAGENT_FINALIZATION_HINT}` } : context, options);
@@ -7992,11 +8178,17 @@ function cancellableBackoff(ms, signal) {
7992
8178
  if (signal?.aborted) finish();
7993
8179
  });
7994
8180
  }
7995
- function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivity) {
8181
+ function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivity, hooks) {
7996
8182
  return async (model, context, options) => {
7997
8183
  for (let attempt = 0; ; attempt++) {
8184
+ if (hooks) {
8185
+ hooks.terminalText = void 0;
8186
+ hooks.terminalStopReason = void 0;
8187
+ }
7998
8188
  if (options?.signal?.aborted) throw new Error("Subagent aborted by parent");
8189
+ if (hooks?.hardDeadlineAt !== void 0 && Date.now() >= hooks.hardDeadlineAt) throw new Error("Subagent hard deadline reached");
7999
8190
  let message;
8191
+ const finishUsage = hooks?.usage ? beginSubagentUsage(hooks.usage, model) : void 0;
8000
8192
  try {
8001
8193
  const response = await stream(model, context, options);
8002
8194
  let terminal;
@@ -8009,8 +8201,19 @@ function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivi
8009
8201
  onActivity?.(next.value.type);
8010
8202
  } catch {
8011
8203
  }
8012
- if (next.value.type === "done") terminal = next.value.message;
8013
- if (next.value.type === "error") terminal = next.value.error;
8204
+ if (next.value.type === "done") {
8205
+ terminal = next.value.message;
8206
+ finishUsage?.(terminal);
8207
+ }
8208
+ if (next.value.type === "error") {
8209
+ terminal = next.value.error;
8210
+ finishUsage?.(terminal);
8211
+ }
8212
+ if (hooks && (next.value.type === "done" || next.value.type === "error")) {
8213
+ const reportTerminal = terminal && ["stop", "length", "error", "aborted"].includes(terminal.stopReason) && !terminal.content.some((block) => block.type === "toolCall");
8214
+ hooks.terminalStopReason = reportTerminal && terminal ? terminal.stopReason : void 0;
8215
+ hooks.terminalText = reportTerminal && terminal ? terminal.content.filter((block) => block.type === "text").map((block) => block.text).join("\n").slice(0, 24001) : void 0;
8216
+ }
8014
8217
  }
8015
8218
  } finally {
8016
8219
  try {
@@ -8021,6 +8224,7 @@ function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivi
8021
8224
  if (!terminal) throw new Error("Provider protocol error: response ended without a terminal event");
8022
8225
  message = terminal;
8023
8226
  } catch (error) {
8227
+ finishUsage?.();
8024
8228
  if (!options?.signal?.aborted && attempt < 2 && isRetryableSubagentFailure(error instanceof Error ? error.message : String(error))) {
8025
8229
  try {
8026
8230
  onRetry?.();
@@ -8110,6 +8314,7 @@ function toSessionRecord(session, messages) {
8110
8314
  runCount: session.runCount,
8111
8315
  revision: session.revision,
8112
8316
  reports: session.reports?.slice(-4),
8317
+ usageRuns: session.usageRuns?.slice(-4).map((usage) => ({ ...usage, reportedTokens: { ...usage.reportedTokens } })),
8113
8318
  messages
8114
8319
  };
8115
8320
  }
@@ -8184,6 +8389,7 @@ var POWERSHELL_DESTRUCTIVE_PATTERNS = [
8184
8389
  { pattern: /\bRemove-Item\b[^;\n|]*(?:HKLM:|HKCU:|Registry::)/i, warning: "may remove registry entries", commandClass: "infra_destructive" },
8185
8390
  { pattern: /\b(Set-ExecutionPolicy|Start-Process\b[^;\n|]*-Verb\s+RunAs)\b/i, warning: "may change execution policy or request elevation", commandClass: "privilege_escalation" },
8186
8391
  { pattern: /\b(Stop-Computer|Restart-Computer)\b/i, warning: "may stop or restart the machine", commandClass: "infra_destructive" },
8392
+ { pattern: /(^|[;|&\n])\s*(?:Invoke-Expression|iex)\b/i, warning: "evaluates a dynamically constructed string as code", commandClass: "privilege_escalation" },
8187
8393
  { pattern: /\bgit\s+reset\s+--hard\b/i, warning: "may discard uncommitted changes", commandClass: "git_destructive" },
8188
8394
  { pattern: /\bgit\s+push\b[^;&|\n]*[ \t](--force|--force-with-lease|-f)\b/i, warning: "may overwrite remote history", commandClass: "git_destructive" }
8189
8395
  ];
@@ -8602,13 +8808,13 @@ function wrapBashGuard(tool, plan) {
8602
8808
  return {
8603
8809
  ...tool,
8604
8810
  description: `${tool.description}
8605
- Subagent guarded mode uses the same bash risk policy as the parent agent. Destructive commands are blocked; normal diagnostic, search, test, and build commands are allowed.`,
8811
+ Subagent guarded mode blocks destructive shell commands while preserving the parent's execution checks. Destructive commands are blocked; normal diagnostic, search, test, and build commands are allowed.`,
8606
8812
  execute: async (toolCallId, params, signal, onUpdate) => {
8607
8813
  const command = typeof params?.command === "string" ? params.command : "";
8608
8814
  const classification = classifyBashCommand(command);
8609
8815
  if (classification.destructive) {
8610
- const reason = `destructive bash command blocked for subagent: ${classification.riskWarnings.join("; ")}`;
8611
- plan.toolsExcluded.push({ name: "bash", reason });
8816
+ const reason = `destructive shell command blocked for subagent: ${classification.riskWarnings.join("; ")}`;
8817
+ plan.toolsExcluded.push({ name: tool.name, reason });
8612
8818
  return {
8613
8819
  content: [{ type: "text", text: reason }],
8614
8820
  details: {
@@ -8636,10 +8842,6 @@ function filterToolsForSubagent(runtimeTools, parentTools, plan, mode) {
8636
8842
  plan.toolsExcluded.push({ name: tool.name, reason: "not available in parent tool set" });
8637
8843
  continue;
8638
8844
  }
8639
- if (tool.name === "bash") {
8640
- filtered.push(wrapBashGuard(tool, plan));
8641
- continue;
8642
- }
8643
8845
  if (mode === "edit" && (tool.name === "write_file" || tool.name === "edit_file")) {
8644
8846
  filtered.push(tool);
8645
8847
  continue;
@@ -8649,7 +8851,7 @@ function filterToolsForSubagent(runtimeTools, parentTools, plan, mode) {
8649
8851
  plan.toolsExcluded.push({ name: tool.name, reason: policy.reason || "not allowed for subagent" });
8650
8852
  continue;
8651
8853
  }
8652
- filtered.push(tool);
8854
+ filtered.push(getToolCapabilityMetadata(tool)?.executesShell === true ? wrapBashGuard(tool, plan) : tool);
8653
8855
  }
8654
8856
  return filtered;
8655
8857
  }
@@ -8745,12 +8947,13 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingL
8745
8947
  }
8746
8948
  }), hooks), deps.transientRetryBackoffMs, () => {
8747
8949
  if (hooks.observation) observeDelegationPhase(hooks.observation, "response_retry");
8950
+ hooks.onPhase?.("response_retry");
8748
8951
  }, () => {
8749
8952
  if (hooks.observation) {
8750
8953
  hooks.observation.lastWorkAt = Date.now();
8751
8954
  hooks.observation.lastActivity = "response_event";
8752
8955
  }
8753
- });
8956
+ }, hooks);
8754
8957
  if (deps.createAgent) {
8755
8958
  const agent2 = deps.createAgent({
8756
8959
  streamFn,
@@ -8780,7 +8983,7 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingL
8780
8983
  return agent;
8781
8984
  }
8782
8985
  function isParentHandoffRequired(task) {
8783
- return task.mode === "edit" || task.status === "timeout" || task.status === "failed" || task.confidenceSignals.some((signal) => signal.type === "tool_error" || signal.type === "no_tool_use" || signal.type === "no_text_report");
8986
+ return task.report?.availability !== "available" || task.mode === "edit" || task.status === "timeout" || task.status === "failed" || task.confidenceSignals.some((signal) => signal.type === "tool_error" || signal.type === "no_tool_use" || signal.type === "no_text_report");
8784
8987
  }
8785
8988
  function shellFromRecord(record) {
8786
8989
  return {
@@ -8794,7 +8997,12 @@ function shellFromRecord(record) {
8794
8997
  timeoutSeconds: record.timeoutSeconds,
8795
8998
  agent: null,
8796
8999
  pendingMessages: record.messages,
8797
- reports: Array.isArray(record.reports) ? record.reports.slice(-4).map((report) => parseDelegationReport(typeof report?.raw === "string" ? report.raw : void 0, typeof report?.runId === "string" ? report.runId : "legacy", report?.availability === "truncated")) : void 0,
9000
+ reports: Array.isArray(record.reports) ? record.reports.slice(-4).map((report) => {
9001
+ const parsed = parseDelegationReport(typeof report?.raw === "string" ? report.raw : void 0, typeof report?.runId === "string" ? report.runId : "legacy", report?.stopReason ?? report?.availability === "truncated");
9002
+ if (["empty", "invalid_json", "invalid_shape", "char_cap", "provider_length", "error", "aborted", "deadline", "cancelled", "no_terminal"].includes(report?.reason ?? "")) parsed.reason = report.reason;
9003
+ return parsed;
9004
+ }) : void 0,
9005
+ usageRuns: restoreSubagentUsageRuns(record.usageRuns),
8798
9006
  createdAt: record.createdAt,
8799
9007
  lastUsedAt: record.lastUsedAt,
8800
9008
  runCount: record.runCount,
@@ -8876,7 +9084,7 @@ async function persistSubagentSession(deps, session, task) {
8876
9084
  if (task.status === "completed" && task.result && transcriptChars > SESSION_TRANSCRIPT_WARN_CHARS) {
8877
9085
  task.result += `
8878
9086
 
8879
- [Session growth warning: session ${session.id} now carries ~${Math.round(transcriptChars / 4)} tokens of transcript; every recall pays for the whole history. For the next round, consider a fresh subagent with a compact brief instead of recalling.]`;
9087
+ [Session growth warning: session ${session.id} now carries approximately ${transcriptChars} JSON characters of transcript (not billing tokens); full recall carries that history, report recall excludes it. Cost is unknown. For the next round, consider a fresh subagent with a compact brief instead of recalling.]`;
8880
9088
  }
8881
9089
  if (!deps.sessionStore) return;
8882
9090
  if (transcriptChars > SESSION_RECORD_MAX_CHARS) {
@@ -8908,6 +9116,13 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
8908
9116
  let heartbeat;
8909
9117
  let session;
8910
9118
  let runStarted = false;
9119
+ let runUsage;
9120
+ const shownPhases = /* @__PURE__ */ new Set();
9121
+ const phaseProgress = (phase) => {
9122
+ if (shownPhases.has(phase) || shownPhases.size >= 16) return;
9123
+ shownPhases.add(phase);
9124
+ report({ message: `[${task.name}] Phase: ${phase}` });
9125
+ };
8911
9126
  let baseline = 0;
8912
9127
  let hardDeadlineAt;
8913
9128
  let pendingRun;
@@ -8916,7 +9131,9 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
8916
9131
  if (!runStarted || !session?.agent) return;
8917
9132
  const last = [...session.agent.state.messages.slice(baseline)].reverse().find((m) => m?.role === "assistant");
8918
9133
  const terminal = isReportTerminal(last) ? last : void 0;
8919
- task.report = parseDelegationReport(terminal ? collectLastAssistantText([terminal]) || void 0 : void 0, `${task.id}:${session.runCount + 1}`, ["length", "error", "aborted"].includes(terminal?.stopReason));
9134
+ const hooks = agentRunHooks.get(session.agent);
9135
+ const capturedText = terminal && hooks?.terminalStopReason === terminal.stopReason ? hooks?.terminalText : void 0;
9136
+ task.report = parseDelegationReport(terminal ? collectLastAssistantText([terminal]) || capturedText || void 0 : void 0, `${task.id}:${session.runCount + 1}`, terminal?.stopReason ?? (timedOut ? "deadline" : signal?.aborted ? "cancelled" : "no_terminal"));
8920
9137
  };
8921
9138
  let agentSettled = true;
8922
9139
  let releaseLease;
@@ -8959,7 +9176,12 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
8959
9176
  }
8960
9177
  const nextModelOverride = task.modelOverride ?? session.modelOverride;
8961
9178
  const nextThinking = task.thinkingLevel ?? session.thinkingLevel;
8962
- if (task.resumeMode === "report" && session.reports?.at(-1)?.availability !== "available") throw new Error("Report recall unavailable: the latest run has no valid report.");
9179
+ const latestReport = session.reports?.at(-1);
9180
+ if (task.resumeMode === "report" && latestReport?.availability !== "available") throw new Error(`Report recall unavailable: session=${session.id}, run=${latestReport?.runId ?? session.runCount}, availability=${latestReport?.availability ?? "missing"}, reason=${latestReport?.reason ?? "legacy_or_missing"}. Explicitly choose resumeMode:"full" (full history; cost unknown), or spawn a new bounded task. No older report or transcript fallback was used.`);
9181
+ const history = session.agent?.state.messages ?? session.pendingMessages ?? [];
9182
+ const historyChars = task.resumeMode === "report" ? 0 : estimateTranscriptChars(history);
9183
+ task.recallInput = { mode: task.resumeMode ?? "full", messageCount: task.resumeMode === "report" ? 0 : history.length, jsonChars: historyChars, warning: historyChars > SESSION_TRANSCRIPT_WARN_CHARS, cost: "unknown" };
9184
+ report({ message: task.resumeMode === "report" ? `[${task.name}] Report recall: old transcript is not carried into the prompt; cost unknown.` : `[${task.name}] Full recall input: ${task.recallInput.messageCount} historical messages, approximately ${task.recallInput.jsonChars} JSON characters (not billing tokens); cost unknown.${task.recallInput.warning ? " Large history: context risk; consider report recall or a new bounded task." : ""}` });
8963
9185
  const mustRebuild = task.resumeMode === "report" || session.agent === null || task.requestedMode !== void 0 || task.modelOverride !== void 0 || task.thinkingLevel !== void 0;
8964
9186
  if (!mustRebuild) {
8965
9187
  subagent = session.agent;
@@ -9063,6 +9285,14 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
9063
9285
  if (sessions) retainLiveSession(sessions, session, Math.max(1, deps.maxLiveSessions ?? DEFAULT_MAX_LIVE_SESSIONS));
9064
9286
  if (signal?.aborted || sessions?.disposed) throw new Error("Subagent capability disposed or aborted by parent");
9065
9287
  const hooks = agentRunHooks.get(subagent);
9288
+ runUsage = createSubagentUsage(session.id, `${task.id}:${session.runCount + 1}`);
9289
+ (task.usageRuns ??= []).push(runUsage);
9290
+ if (hooks) {
9291
+ hooks.usage = runUsage;
9292
+ hooks.onPhase = phaseProgress;
9293
+ hooks.terminalText = void 0;
9294
+ hooks.terminalStopReason = void 0;
9295
+ }
9066
9296
  hardDeadlineAt = Date.now() + runTimeoutSeconds * 1e3;
9067
9297
  if (hooks) {
9068
9298
  hooks.observation = task.observation;
@@ -9086,6 +9316,7 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
9086
9316
  softTimeout = setTimeout(() => {
9087
9317
  if (hooks) hooks.finalizing = true;
9088
9318
  observeDelegationPhase(task.observation, "finalizing", false);
9319
+ phaseProgress("finalizing");
9089
9320
  }, subagentSoftDeadlineMs(runTimeoutSeconds * 1e3));
9090
9321
  timeout = setTimeout(() => {
9091
9322
  timedOut = true;
@@ -9189,7 +9420,7 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
9189
9420
  const terminalStopReason = lastAssistant?.stopReason;
9190
9421
  const terminalError = typeof lastAssistant?.errorMessage === "string" ? lastAssistant.errorMessage : void 0;
9191
9422
  const collectedResponse = isReportTerminal(lastAssistant) ? collectLastAssistantText([lastAssistant]) || void 0 : void 0;
9192
- task.report = parseDelegationReport(collectedResponse, `${task.id}:${(session?.runCount ?? 0) + 1}`, terminalStopReason === "length" || terminalStopReason === "error" || terminalStopReason === "aborted");
9423
+ task.report = parseDelegationReport(collectedResponse, `${task.id}:${(session?.runCount ?? 0) + 1}`, terminalStopReason ?? "no_terminal");
9193
9424
  const streamInterrupted = terminalStopReason === "error" || terminalStopReason === "aborted" || terminalError || !collectedResponse && terminalStopReason !== "stop" || terminalStopReason === "length" && !messageHasOwnText(lastAssistant);
9194
9425
  if (streamInterrupted) {
9195
9426
  if (terminalStopReason === "length") {
@@ -9238,6 +9469,7 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
9238
9469
  refreshReport();
9239
9470
  task.status = timedOut ? "timeout" : signal?.aborted ? "cancelled" : "failed";
9240
9471
  observeDelegationPhase(task.observation, timedOut ? "deadline" : signal?.aborted ? "cancelled" : "failed");
9472
+ phaseProgress(task.observation.phase);
9241
9473
  task.error = errorMessage.slice(0, 2e3);
9242
9474
  task.report ??= parseDelegationReport(void 0, task.id);
9243
9475
  task.parentHandoffRequired = isParentHandoffRequired(task);
@@ -9247,14 +9479,21 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
9247
9479
  if (heartbeat) {
9248
9480
  clearInterval(heartbeat);
9249
9481
  }
9482
+ if (runUsage) settleSubagentUsage(runUsage, agentSettled);
9250
9483
  const finalize = async () => {
9484
+ if (runUsage) settleSubagentUsage(runUsage, true);
9251
9485
  try {
9252
9486
  if (session) {
9253
9487
  const hooks = session.agent ? agentRunHooks.get(session.agent) : void 0;
9254
- if (hooks && hooks.observation === task.observation) hooks.observation = void 0;
9488
+ if (hooks && hooks.observation === task.observation) {
9489
+ hooks.observation = void 0;
9490
+ hooks.onPhase = void 0;
9491
+ hooks.usage = void 0;
9492
+ }
9255
9493
  if (runStarted) {
9256
9494
  refreshReport();
9257
9495
  session.runCount++;
9496
+ if (runUsage) session.usageRuns = [...session.usageRuns ?? [], runUsage].slice(-4);
9258
9497
  session.reports = [...session.reports ?? [], task.report ?? parseDelegationReport(void 0, task.id)].slice(-4);
9259
9498
  }
9260
9499
  session.lastUsedAt = Date.now();
@@ -9305,7 +9544,9 @@ function buildParallelResult(tasks, totalDuration) {
9305
9544
  if (task.details) {
9306
9545
  resultText += `, ${task.details.durationMs}ms, ${task.details.toolCalls} tools`;
9307
9546
  }
9308
- resultText += `, report=${task.report?.availability ?? "missing"})
9547
+ resultText += `, report=${task.report?.availability ?? "missing"}${task.report?.reason ? ` (${task.report.reason})` : ""})
9548
+ `;
9549
+ for (const usage of task.usageRuns ?? []) resultText += `Child usage ${usage.sessionId}/${usage.runId}: ${usage.status}, ${usage.attempts} attempts (${usage.reportedAttempts} reported, ${usage.unknownAttempts} unknown, ${usage.pendingAttempts} pending); reported token subtotal=${usage.reportedTokens.totalTokens}; estimated cost=${usage.estimatedCost ?? "unknown"}. Not added to parent ledger.
9309
9550
  `;
9310
9551
  if (task.observation) resultText += `Phase: ${task.observation.phase}; last activity: ${task.observation.lastActivity} at ${task.observation.lastWorkAt}
9311
9552
  `;
@@ -9501,7 +9742,7 @@ Default mode="read" is for investigation, search, review, or triage and cannot e
9501
9742
  thinkingLevel: Type.Optional(Type.Union([Type.Literal("off"), Type.Literal("minimal"), Type.Literal("low"), Type.Literal("medium"), Type.Literal("high"), Type.Literal("xhigh")], { description: "off|minimal|low|medium|high|xhigh. Default medium; override only when the user asks or for cheap lookups (off)." })),
9502
9743
  timeout: Type.Optional(Type.Number({ description: "Seconds. Default 1200; set higher for long tasks." })),
9503
9744
  resumeMode: Type.Optional(Type.Union([Type.Literal("full"), Type.Literal("report")], { description: "Default full retains prior transcript. Explicit report rebuilds with current tools/model/credentials and only the latest valid historical report as data plus the new task; fails if unavailable." })),
9504
- sessionId: Type.Optional(Type.String({ description: "Continue a previous subagent session by id (from an earlier result's Session line); accumulated context makes iteration cheaper. Optional mode/model/thinkingLevel reconfigure it; one task at a time; recalls never replay on failure and must target an idle session; prefer a fresh task for independent reviews." }))
9745
+ sessionId: Type.Optional(Type.String({ description: "Continue a previous subagent session by id (from an earlier result's Session line); full mode retains historical input with unknown cost. Optional mode/model/thinkingLevel reconfigure it; one task at a time; recalls never replay on failure and must target an idle session; prefer a fresh task for independent reviews." }))
9505
9746
  }
9506
9747
  // No additionalProperties lock: legacy callers may send task aliases
9507
9748
  // (description/prompt/objective); normalizeTaskDefs resolves them at
@@ -9631,6 +9872,8 @@ ${SPAWN_USAGE_HINT}` }],
9631
9872
  reportedEvidenceCount: task.reportedEvidence.length,
9632
9873
  confidenceSignalCount: task.confidenceSignals.length,
9633
9874
  report: task.report,
9875
+ recallInput: task.recallInput,
9876
+ usageRuns: task.usageRuns?.map((usage) => ({ ...usage, reportedTokens: { ...usage.reportedTokens } })),
9634
9877
  observation: task.observation,
9635
9878
  parentHandoffRequired: task.parentHandoffRequired,
9636
9879
  failureReason: task.error,
@@ -10978,7 +11221,7 @@ function createReadTool(cwd, options) {
10978
11221
  label: "read",
10979
11222
  description: `Read a file's contents. Use this before editing, and use offset/limit for large files, or tail=N to read the last N lines when the line count is unknown. Images are attached for the current model when it supports vision; otherwise a configured file-understanding service analyzes them. Video, audio, and documents require a configured understanding service. Pass question to specify what to focus on; it does not force a separate model request. Example: read_file path='Scripts/PlayerController.cs' or read_file path='Data/config.json'. ${pathResolutionDescription} For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). When you need the full file, continue with a larger offset until complete.`,
10980
11223
  parameters: readSchema,
10981
- execute: async (_toolCallId, params, signal) => {
11224
+ execute: async (_toolCallId, params, signal, _onUpdate) => {
10982
11225
  const { path: path3, root, question } = params;
10983
11226
  const tail = params.tail;
10984
11227
  let offset = params.offset;
@@ -11005,7 +11248,7 @@ function createReadTool(cwd, options) {
11005
11248
  const message = error instanceof Error ? error.message : String(error);
11006
11249
  if (/outside sandbox|outside root|escapes sandbox/i.test(message)) {
11007
11250
  return createReadErrorResult(
11008
- `${message}. read_file is workspace-scoped; for intentional runtime logs or temporary files outside the workspace, use bash with a bounded command such as head, tail, sed -n, or cat on that path.`
11251
+ `${message}. read_file is workspace-scoped; for intentional runtime logs or temporary files outside the workspace, use the shell tool with a bounded command such as head, tail, sed -n, or cat on that path.`
11009
11252
  );
11010
11253
  }
11011
11254
  return createReadErrorResult(message);
@@ -16914,7 +17157,7 @@ function unavailableResult(query, requestedMode, reason) {
16914
17157
  text: [
16915
17158
  `Web search is unavailable for "${query}".`,
16916
17159
  reason,
16917
- "Do not use bash, curl, Python, or DuckDuckGo scraping as a fallback; report that web_search is unavailable or ask the user to configure a provider that supports native web search."
17160
+ "Do not use shell, curl, Python, or DuckDuckGo scraping as a fallback; report that web_search is unavailable or ask the user to configure a provider that supports native web search."
16918
17161
  ].join("\n")
16919
17162
  }],
16920
17163
  details: {
@@ -17422,7 +17665,7 @@ function createSharedWebSearchTool(deps) {
17422
17665
  return {
17423
17666
  name: "web_search",
17424
17667
  label: "web_search",
17425
- description: "Search the public web using a provider-native web search capability. Use for current information, online research, or documentation outside the local workspace. Results include sources. Do not use bash/curl/python as a web-search fallback. Only set domain filters when the user explicitly asks to limit sources.",
17668
+ description: "Search the public web using a provider-native web search capability. Use for current information, online research, or documentation outside the local workspace. Results include sources. Do not use shell/curl/python as a web-search fallback. Only set domain filters when the user explicitly asks to limit sources.",
17426
17669
  parameters: webSearchSchema,
17427
17670
  execute: async (_toolCallId, rawParams, signal) => {
17428
17671
  const input = rawParams;
@@ -18013,7 +18256,7 @@ function createSharedWebFetchTool(deps = {}) {
18013
18256
  return {
18014
18257
  name: "web_fetch",
18015
18258
  label: "web_fetch",
18016
- description: "Fetch and read a specific public web URL. Use web_search to discover sources, then web_fetch to inspect a chosen URL. Do not use bash/curl/Python as a fallback for web page fetching.",
18259
+ description: "Fetch and read a specific public web URL. Use web_search to discover sources, then web_fetch to inspect a chosen URL. Do not use shell/curl/Python as a fallback for web page fetching.",
18017
18260
  parameters: webFetchSchema,
18018
18261
  capabilityMetadata: {
18019
18262
  riskClass: "network",
@@ -18637,7 +18880,7 @@ function createSharedWebResearchTool(deps) {
18637
18880
  return {
18638
18881
  name: "web_research",
18639
18882
  label: "web_research",
18640
- description: "Canonical web tool. For normal research, pass query. To read a known page, pass url. For low-level search results only, pass query with mode='search'. Use for current information, official docs, news, releases, issues, and webpage summaries. Do not use bash/curl/Python as a web fallback.",
18883
+ description: "Canonical web tool. For normal research, pass query. To read a known page, pass url. For low-level search results only, pass query with mode='search'. Use for current information, official docs, news, releases, issues, and webpage summaries. Do not use shell/curl/Python as a web fallback.",
18641
18884
  parameters: webResearchSchema,
18642
18885
  capabilityMetadata: {
18643
18886
  riskClass: "network",
@@ -19208,6 +19451,9 @@ export {
19208
19451
  findFirstKeptEntrySummaryId,
19209
19452
  createCompactionSummary,
19210
19453
  generateEntryId,
19454
+ createHostEnvelopeProjectorRegistry,
19455
+ projectHostEnvelopes,
19456
+ isHostContextBlock,
19211
19457
  FileSessionStore,
19212
19458
  createSessionManager,
19213
19459
  prepareSessionCompaction,
@@ -19248,6 +19494,7 @@ export {
19248
19494
  supersedeExecutionState,
19249
19495
  shouldPreserveExecutionStateForUserText,
19250
19496
  BUILTIN_TOOL_CAPABILITY_METADATA,
19497
+ getToolCapabilityMetadata,
19251
19498
  isToolAllowedInPlanMode,
19252
19499
  extractPlanTodoItems,
19253
19500
  isPlanModeSafeCommand,