@cydm/pie 2.7.6 → 2.7.7
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/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +6 -4
- package/dist/builtin/extensions/subagent/index.js +4 -4
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/chrome-devtools-axi/SKILL.md +2 -2
- package/dist/builtin/skills/computer-use-axi/SKILL.md +1 -1
- package/dist/builtin/skills/tui-use/SKILL.md +1 -1
- package/dist/chunks/{chunk-ZF5FHTES.js → chunk-2FEDB5GR.js} +22 -0
- package/dist/chunks/{chunk-GAUIKMBA.js → chunk-IU5L5DED.js} +325 -56
- package/dist/chunks/{chunk-YWWLRZSG.js → chunk-UPGEXDEQ.js} +288 -44
- package/dist/chunks/{chunk-5YWEUFLM.js → chunk-W5B3OXHQ.js} +1 -1
- package/dist/chunks/{src-6WK5KYWQ.js → src-C2CBPEUY.js} +2 -2
- package/dist/chunks/{test-stream-7EH7BGY6.js → test-stream-LDVUVSUP.js} +10 -1
- package/dist/cli.js +157 -111
- package/package.json +6 -5
|
@@ -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-
|
|
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-
|
|
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,107 @@ 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 projectHostEnvelopes(messages, registry, onProjection) {
|
|
2006
|
+
let changed = false;
|
|
2007
|
+
const next = [];
|
|
2008
|
+
for (const message of messages) {
|
|
2009
|
+
const block = leadingHostContextBlock(message);
|
|
2010
|
+
if (!block) {
|
|
2011
|
+
next.push(message);
|
|
2012
|
+
continue;
|
|
2013
|
+
}
|
|
2014
|
+
const outcome = projectHostContextBlock(block, registry);
|
|
2015
|
+
onProjection?.(outcome);
|
|
2016
|
+
const content = message.content;
|
|
2017
|
+
const rest = content.slice(1);
|
|
2018
|
+
const first = rest[0];
|
|
2019
|
+
let projectedContent;
|
|
2020
|
+
if (first && first.type === "text" && typeof first.text === "string") {
|
|
2021
|
+
const merged = first.text.trim().length > 0 ? `${outcome.text}
|
|
2022
|
+
|
|
2023
|
+
${first.text}` : outcome.text;
|
|
2024
|
+
projectedContent = [{ ...first, text: merged }, ...rest.slice(1)];
|
|
2025
|
+
} else {
|
|
2026
|
+
projectedContent = [{ type: "text", text: outcome.text }, ...rest];
|
|
2027
|
+
}
|
|
2028
|
+
next.push({ ...message, content: projectedContent });
|
|
2029
|
+
changed = true;
|
|
2030
|
+
}
|
|
2031
|
+
return changed ? next : messages;
|
|
2032
|
+
}
|
|
2033
|
+
function isHostContextBlock(value) {
|
|
2034
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
2035
|
+
const block = value;
|
|
2036
|
+
const version = block.version;
|
|
2037
|
+
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);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
1935
2040
|
// ../../packages/agent-framework/src/session/store.ts
|
|
1936
2041
|
import { createRequire } from "node:module";
|
|
1937
2042
|
import { fileURLToPath } from "node:url";
|
|
@@ -2972,7 +3077,19 @@ function normalizeSessionDisplayName(raw) {
|
|
|
2972
3077
|
}
|
|
2973
3078
|
function isSyntheticEnvelopePreview(preview) {
|
|
2974
3079
|
const trimmed = preview.trimStart();
|
|
2975
|
-
|
|
3080
|
+
if (trimmed.startsWith("<environment_context>") || trimmed.startsWith("<turn_aborted>") || trimmed.startsWith("# AGENTS.md instructions") || trimmed.startsWith("## Project Context\nProject-specific instructions from AGENTS.md")) {
|
|
3081
|
+
return true;
|
|
3082
|
+
}
|
|
3083
|
+
const runtimeMatch = trimmed.match(/^<runtime-mode-context>[\s\S]*?<\/runtime-mode-context>/);
|
|
3084
|
+
if (runtimeMatch) {
|
|
3085
|
+
const rest = trimmed.slice(runtimeMatch[0].length).trim();
|
|
3086
|
+
if (rest.length === 0) return true;
|
|
3087
|
+
return false;
|
|
3088
|
+
}
|
|
3089
|
+
if (trimmed.startsWith("<runtime-mode-context>")) {
|
|
3090
|
+
return true;
|
|
3091
|
+
}
|
|
3092
|
+
return /^HE_INPUT kind=(?:USER_REQUEST|QUEUE_WAKE) source=/.test(trimmed);
|
|
2976
3093
|
}
|
|
2977
3094
|
function isAutoGeneratedSessionName(name) {
|
|
2978
3095
|
return /^Session (\d|[a-z0-9]{6,8}$)/i.test(name.trim());
|
|
@@ -2986,7 +3103,10 @@ function userEntryPreview(entry) {
|
|
|
2986
3103
|
if (!message) return "";
|
|
2987
3104
|
if (typeof message.content === "string") return message.content;
|
|
2988
3105
|
if (!Array.isArray(message.content)) return "";
|
|
2989
|
-
return message.content.map((block) =>
|
|
3106
|
+
return message.content.map((block) => {
|
|
3107
|
+
if (isRecord2(block) && block.type === "hostContext") return "";
|
|
3108
|
+
return isRecord2(block) && block.type === "text" && typeof block.text === "string" ? block.text : "";
|
|
3109
|
+
}).join(" ").trim();
|
|
2990
3110
|
}
|
|
2991
3111
|
function entryJsonBytes(entry) {
|
|
2992
3112
|
try {
|
|
@@ -4917,7 +5037,7 @@ function isUserContentBlock(value) {
|
|
|
4917
5037
|
return false;
|
|
4918
5038
|
}
|
|
4919
5039
|
const type = value.type;
|
|
4920
|
-
return type === "text" || type === "image" || type === "audio" || type === "video" || type === "fileRef";
|
|
5040
|
+
return type === "text" || type === "image" || type === "audio" || type === "video" || type === "fileRef" || type === "hostContext";
|
|
4921
5041
|
}
|
|
4922
5042
|
function normalizePromptInput(input) {
|
|
4923
5043
|
if (typeof input === "string") {
|
|
@@ -5629,7 +5749,7 @@ function toolOutcomeKind(event) {
|
|
|
5629
5749
|
return typeof kind === "string" ? kind : void 0;
|
|
5630
5750
|
}
|
|
5631
5751
|
function isCommandNonzero(event) {
|
|
5632
|
-
return
|
|
5752
|
+
return toolOutcomeKind(event) === "command_nonzero";
|
|
5633
5753
|
}
|
|
5634
5754
|
function isStateChangingSuccess(event) {
|
|
5635
5755
|
if (event.isError) return false;
|
|
@@ -5637,7 +5757,7 @@ function isStateChangingSuccess(event) {
|
|
|
5637
5757
|
if (outcomeKind === "command_nonzero" || outcomeKind === "timeout" || outcomeKind === "signal") return false;
|
|
5638
5758
|
if (event.toolName === "edit_file" || event.toolName === "write_file") return true;
|
|
5639
5759
|
const details = event.result && typeof event.result === "object" ? event.result.details : void 0;
|
|
5640
|
-
return
|
|
5760
|
+
return details?.commandClass === "filesystem_write";
|
|
5641
5761
|
}
|
|
5642
5762
|
var AgentSessionRuntimeGuard = class {
|
|
5643
5763
|
constructor(trigger, advise) {
|
|
@@ -7915,14 +8035,22 @@ var SessionTraceSnapshotWriter = class {
|
|
|
7915
8035
|
|
|
7916
8036
|
// ../../packages/agent-framework/src/delegation.ts
|
|
7917
8037
|
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.';
|
|
8038
|
+
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
8039
|
function parseDelegationReport(text, runId, truncated = false) {
|
|
7920
8040
|
const raw = (text ?? "").slice(0, DELEGATION_REPORT_MAX_CHARS);
|
|
7921
8041
|
const base = { version: 1, runId: runId.slice(0, 160), raw };
|
|
7922
|
-
|
|
7923
|
-
|
|
8042
|
+
const stopReason = typeof truncated === "string" ? truncated.slice(0, 40) : void 0;
|
|
8043
|
+
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;
|
|
8044
|
+
if (reason) return { ...base, stopReason, reason, availability: raw ? "truncated" : "missing" };
|
|
8045
|
+
if ((text?.length ?? 0) > DELEGATION_REPORT_MAX_CHARS) return { ...base, availability: "truncated", reason: "char_cap" };
|
|
8046
|
+
if (!raw.trim()) return { ...base, availability: "missing", reason: "empty" };
|
|
8047
|
+
let value;
|
|
8048
|
+
try {
|
|
8049
|
+
value = JSON.parse(raw);
|
|
8050
|
+
} catch {
|
|
8051
|
+
return { ...base, availability: "malformed", reason: "invalid_json" };
|
|
8052
|
+
}
|
|
7924
8053
|
try {
|
|
7925
|
-
const value = JSON.parse(raw);
|
|
7926
8054
|
if (!value || typeof value !== "object" || Array.isArray(value) || typeof value.summary !== "string" || typeof value.result !== "string") throw new Error();
|
|
7927
8055
|
if (Object.keys(value).some((key) => !["summary", "result", "remainingWork", "evidenceRefs"].includes(key))) throw new Error();
|
|
7928
8056
|
for (const key of ["remainingWork", "evidenceRefs"]) {
|
|
@@ -7930,7 +8058,7 @@ function parseDelegationReport(text, runId, truncated = false) {
|
|
|
7930
8058
|
}
|
|
7931
8059
|
return { ...base, availability: "available", report: value };
|
|
7932
8060
|
} catch {
|
|
7933
|
-
return { ...base, availability: "malformed" };
|
|
8061
|
+
return { ...base, availability: "malformed", reason: "invalid_shape" };
|
|
7934
8062
|
}
|
|
7935
8063
|
}
|
|
7936
8064
|
function observeDelegationPhase(observation, phase, workActivity = true) {
|
|
@@ -7959,6 +8087,58 @@ function observeDelegationTool(observation, event) {
|
|
|
7959
8087
|
if (observation.receipts.length > 32) observation.receipts.shift();
|
|
7960
8088
|
}
|
|
7961
8089
|
|
|
8090
|
+
// ../../packages/shared-headless-capabilities/src/subagent-usage.ts
|
|
8091
|
+
function createSubagentUsage(sessionId, runId) {
|
|
8092
|
+
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 };
|
|
8093
|
+
}
|
|
8094
|
+
function settleSubagentUsage(usage, settled) {
|
|
8095
|
+
usage.status = !settled || usage.pendingAttempts > 0 ? "pending" : usage.attempts === 0 || usage.reportedAttempts === 0 ? "unknown" : usage.unknownAttempts > 0 ? "partial" : "complete";
|
|
8096
|
+
}
|
|
8097
|
+
function beginSubagentUsage(usage, model) {
|
|
8098
|
+
usage.attempts++;
|
|
8099
|
+
usage.pendingAttempts++;
|
|
8100
|
+
let ended = false;
|
|
8101
|
+
return (message) => {
|
|
8102
|
+
if (ended) return;
|
|
8103
|
+
ended = true;
|
|
8104
|
+
usage.pendingAttempts--;
|
|
8105
|
+
const values = message?.usage;
|
|
8106
|
+
const known = message?.usageReported === true && values && [values.input, values.output, values.cacheRead, values.cacheWrite, values.totalTokens].every((n) => Number.isFinite(n) && n >= 0);
|
|
8107
|
+
if (known) {
|
|
8108
|
+
usage.reportedAttempts++;
|
|
8109
|
+
for (const key of Object.keys(usage.reportedTokens)) usage.reportedTokens[key] += values[key] ?? 0;
|
|
8110
|
+
} else usage.unknownAttempts++;
|
|
8111
|
+
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;
|
|
8112
|
+
if (usage.attempts === 1 && priced) usage.estimatedCost = values.cost.total;
|
|
8113
|
+
else if (priced && usage.estimatedCost !== null) usage.estimatedCost += values.cost.total;
|
|
8114
|
+
else usage.estimatedCost = null;
|
|
8115
|
+
};
|
|
8116
|
+
}
|
|
8117
|
+
function restoreSubagentUsageRuns(value) {
|
|
8118
|
+
if (!Array.isArray(value)) return void 0;
|
|
8119
|
+
return value.slice(-4).flatMap((item) => {
|
|
8120
|
+
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 [];
|
|
8121
|
+
if (![item.attempts, item.reportedAttempts, item.unknownAttempts, item.pendingAttempts].every((n) => Number.isSafeInteger(n) && n >= 0)) return [];
|
|
8122
|
+
if (item.reportedAttempts + item.unknownAttempts + item.pendingAttempts !== item.attempts) return [];
|
|
8123
|
+
const tokens = item.reportedTokens;
|
|
8124
|
+
const keys = ["input", "output", "cacheRead", "cacheWrite", "cacheWriteLong", "totalTokens"];
|
|
8125
|
+
if (!tokens || !keys.every((key) => Number.isFinite(tokens[key]) && tokens[key] >= 0)) return [];
|
|
8126
|
+
const expectedStatus = item.pendingAttempts > 0 ? "pending" : item.reportedAttempts === 0 ? "unknown" : item.unknownAttempts > 0 ? "partial" : "complete";
|
|
8127
|
+
if (item.status !== expectedStatus && !(item.status === "pending" && item.attempts === 0)) return [];
|
|
8128
|
+
return [{
|
|
8129
|
+
sessionId: item.sessionId,
|
|
8130
|
+
runId: item.runId,
|
|
8131
|
+
attempts: item.attempts,
|
|
8132
|
+
reportedAttempts: item.reportedAttempts,
|
|
8133
|
+
unknownAttempts: item.unknownAttempts,
|
|
8134
|
+
pendingAttempts: item.pendingAttempts,
|
|
8135
|
+
status: item.status,
|
|
8136
|
+
reportedTokens: Object.fromEntries(keys.map((key) => [key, tokens[key]])),
|
|
8137
|
+
estimatedCost: item.reportedAttempts > 0 && item.unknownAttempts === 0 && item.pendingAttempts === 0 && typeof item.estimatedCost === "number" && Number.isFinite(item.estimatedCost) && item.estimatedCost >= 0 ? item.estimatedCost : null
|
|
8138
|
+
}];
|
|
8139
|
+
});
|
|
8140
|
+
}
|
|
8141
|
+
|
|
7962
8142
|
// ../../packages/shared-headless-capabilities/src/subagent-stream.ts
|
|
7963
8143
|
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
8144
|
function subagentSoftDeadlineMs(budgetMs) {
|
|
@@ -7969,6 +8149,10 @@ function withSubagentRunContext(stream, hooks) {
|
|
|
7969
8149
|
if (hooks.hardDeadlineAt !== void 0 && Date.now() >= hooks.hardDeadlineAt) throw new Error("Subagent hard deadline reached");
|
|
7970
8150
|
if (hooks.softDeadlineAt !== void 0 && Date.now() >= hooks.softDeadlineAt) hooks.finalizing = true;
|
|
7971
8151
|
if (hooks.observation) observeDelegationPhase(hooks.observation, hooks.finalizing ? "finalizing" : "request");
|
|
8152
|
+
try {
|
|
8153
|
+
hooks.onPhase?.(hooks.finalizing ? "finalizing" : "request");
|
|
8154
|
+
} catch {
|
|
8155
|
+
}
|
|
7972
8156
|
return stream(model, hooks.finalizing ? { ...context, systemPrompt: `${context.systemPrompt ?? ""}
|
|
7973
8157
|
|
|
7974
8158
|
${SUBAGENT_FINALIZATION_HINT}` } : context, options);
|
|
@@ -7992,11 +8176,17 @@ function cancellableBackoff(ms, signal) {
|
|
|
7992
8176
|
if (signal?.aborted) finish();
|
|
7993
8177
|
});
|
|
7994
8178
|
}
|
|
7995
|
-
function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivity) {
|
|
8179
|
+
function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivity, hooks) {
|
|
7996
8180
|
return async (model, context, options) => {
|
|
7997
8181
|
for (let attempt = 0; ; attempt++) {
|
|
8182
|
+
if (hooks) {
|
|
8183
|
+
hooks.terminalText = void 0;
|
|
8184
|
+
hooks.terminalStopReason = void 0;
|
|
8185
|
+
}
|
|
7998
8186
|
if (options?.signal?.aborted) throw new Error("Subagent aborted by parent");
|
|
8187
|
+
if (hooks?.hardDeadlineAt !== void 0 && Date.now() >= hooks.hardDeadlineAt) throw new Error("Subagent hard deadline reached");
|
|
7999
8188
|
let message;
|
|
8189
|
+
const finishUsage = hooks?.usage ? beginSubagentUsage(hooks.usage, model) : void 0;
|
|
8000
8190
|
try {
|
|
8001
8191
|
const response = await stream(model, context, options);
|
|
8002
8192
|
let terminal;
|
|
@@ -8009,8 +8199,19 @@ function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivi
|
|
|
8009
8199
|
onActivity?.(next.value.type);
|
|
8010
8200
|
} catch {
|
|
8011
8201
|
}
|
|
8012
|
-
if (next.value.type === "done")
|
|
8013
|
-
|
|
8202
|
+
if (next.value.type === "done") {
|
|
8203
|
+
terminal = next.value.message;
|
|
8204
|
+
finishUsage?.(terminal);
|
|
8205
|
+
}
|
|
8206
|
+
if (next.value.type === "error") {
|
|
8207
|
+
terminal = next.value.error;
|
|
8208
|
+
finishUsage?.(terminal);
|
|
8209
|
+
}
|
|
8210
|
+
if (hooks && (next.value.type === "done" || next.value.type === "error")) {
|
|
8211
|
+
const reportTerminal = terminal && ["stop", "length", "error", "aborted"].includes(terminal.stopReason) && !terminal.content.some((block) => block.type === "toolCall");
|
|
8212
|
+
hooks.terminalStopReason = reportTerminal && terminal ? terminal.stopReason : void 0;
|
|
8213
|
+
hooks.terminalText = reportTerminal && terminal ? terminal.content.filter((block) => block.type === "text").map((block) => block.text).join("\n").slice(0, 24001) : void 0;
|
|
8214
|
+
}
|
|
8014
8215
|
}
|
|
8015
8216
|
} finally {
|
|
8016
8217
|
try {
|
|
@@ -8021,6 +8222,7 @@ function withSubagentResponseRecovery(stream, backoffMs = 2e3, onRetry, onActivi
|
|
|
8021
8222
|
if (!terminal) throw new Error("Provider protocol error: response ended without a terminal event");
|
|
8022
8223
|
message = terminal;
|
|
8023
8224
|
} catch (error) {
|
|
8225
|
+
finishUsage?.();
|
|
8024
8226
|
if (!options?.signal?.aborted && attempt < 2 && isRetryableSubagentFailure(error instanceof Error ? error.message : String(error))) {
|
|
8025
8227
|
try {
|
|
8026
8228
|
onRetry?.();
|
|
@@ -8110,6 +8312,7 @@ function toSessionRecord(session, messages) {
|
|
|
8110
8312
|
runCount: session.runCount,
|
|
8111
8313
|
revision: session.revision,
|
|
8112
8314
|
reports: session.reports?.slice(-4),
|
|
8315
|
+
usageRuns: session.usageRuns?.slice(-4).map((usage) => ({ ...usage, reportedTokens: { ...usage.reportedTokens } })),
|
|
8113
8316
|
messages
|
|
8114
8317
|
};
|
|
8115
8318
|
}
|
|
@@ -8184,6 +8387,7 @@ var POWERSHELL_DESTRUCTIVE_PATTERNS = [
|
|
|
8184
8387
|
{ pattern: /\bRemove-Item\b[^;\n|]*(?:HKLM:|HKCU:|Registry::)/i, warning: "may remove registry entries", commandClass: "infra_destructive" },
|
|
8185
8388
|
{ 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
8389
|
{ pattern: /\b(Stop-Computer|Restart-Computer)\b/i, warning: "may stop or restart the machine", commandClass: "infra_destructive" },
|
|
8390
|
+
{ pattern: /(^|[;|&\n])\s*(?:Invoke-Expression|iex)\b/i, warning: "evaluates a dynamically constructed string as code", commandClass: "privilege_escalation" },
|
|
8187
8391
|
{ pattern: /\bgit\s+reset\s+--hard\b/i, warning: "may discard uncommitted changes", commandClass: "git_destructive" },
|
|
8188
8392
|
{ pattern: /\bgit\s+push\b[^;&|\n]*[ \t](--force|--force-with-lease|-f)\b/i, warning: "may overwrite remote history", commandClass: "git_destructive" }
|
|
8189
8393
|
];
|
|
@@ -8602,13 +8806,13 @@ function wrapBashGuard(tool, plan) {
|
|
|
8602
8806
|
return {
|
|
8603
8807
|
...tool,
|
|
8604
8808
|
description: `${tool.description}
|
|
8605
|
-
Subagent guarded mode
|
|
8809
|
+
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
8810
|
execute: async (toolCallId, params, signal, onUpdate) => {
|
|
8607
8811
|
const command = typeof params?.command === "string" ? params.command : "";
|
|
8608
8812
|
const classification = classifyBashCommand(command);
|
|
8609
8813
|
if (classification.destructive) {
|
|
8610
|
-
const reason = `destructive
|
|
8611
|
-
plan.toolsExcluded.push({ name:
|
|
8814
|
+
const reason = `destructive shell command blocked for subagent: ${classification.riskWarnings.join("; ")}`;
|
|
8815
|
+
plan.toolsExcluded.push({ name: tool.name, reason });
|
|
8612
8816
|
return {
|
|
8613
8817
|
content: [{ type: "text", text: reason }],
|
|
8614
8818
|
details: {
|
|
@@ -8636,10 +8840,6 @@ function filterToolsForSubagent(runtimeTools, parentTools, plan, mode) {
|
|
|
8636
8840
|
plan.toolsExcluded.push({ name: tool.name, reason: "not available in parent tool set" });
|
|
8637
8841
|
continue;
|
|
8638
8842
|
}
|
|
8639
|
-
if (tool.name === "bash") {
|
|
8640
|
-
filtered.push(wrapBashGuard(tool, plan));
|
|
8641
|
-
continue;
|
|
8642
|
-
}
|
|
8643
8843
|
if (mode === "edit" && (tool.name === "write_file" || tool.name === "edit_file")) {
|
|
8644
8844
|
filtered.push(tool);
|
|
8645
8845
|
continue;
|
|
@@ -8649,7 +8849,7 @@ function filterToolsForSubagent(runtimeTools, parentTools, plan, mode) {
|
|
|
8649
8849
|
plan.toolsExcluded.push({ name: tool.name, reason: policy.reason || "not allowed for subagent" });
|
|
8650
8850
|
continue;
|
|
8651
8851
|
}
|
|
8652
|
-
filtered.push(tool);
|
|
8852
|
+
filtered.push(getToolCapabilityMetadata(tool)?.executesShell === true ? wrapBashGuard(tool, plan) : tool);
|
|
8653
8853
|
}
|
|
8654
8854
|
return filtered;
|
|
8655
8855
|
}
|
|
@@ -8745,12 +8945,13 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingL
|
|
|
8745
8945
|
}
|
|
8746
8946
|
}), hooks), deps.transientRetryBackoffMs, () => {
|
|
8747
8947
|
if (hooks.observation) observeDelegationPhase(hooks.observation, "response_retry");
|
|
8948
|
+
hooks.onPhase?.("response_retry");
|
|
8748
8949
|
}, () => {
|
|
8749
8950
|
if (hooks.observation) {
|
|
8750
8951
|
hooks.observation.lastWorkAt = Date.now();
|
|
8751
8952
|
hooks.observation.lastActivity = "response_event";
|
|
8752
8953
|
}
|
|
8753
|
-
});
|
|
8954
|
+
}, hooks);
|
|
8754
8955
|
if (deps.createAgent) {
|
|
8755
8956
|
const agent2 = deps.createAgent({
|
|
8756
8957
|
streamFn,
|
|
@@ -8780,7 +8981,7 @@ function createAgentInstance(deps, systemPrompt, tools, model, apiKey, thinkingL
|
|
|
8780
8981
|
return agent;
|
|
8781
8982
|
}
|
|
8782
8983
|
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");
|
|
8984
|
+
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
8985
|
}
|
|
8785
8986
|
function shellFromRecord(record) {
|
|
8786
8987
|
return {
|
|
@@ -8794,7 +8995,12 @@ function shellFromRecord(record) {
|
|
|
8794
8995
|
timeoutSeconds: record.timeoutSeconds,
|
|
8795
8996
|
agent: null,
|
|
8796
8997
|
pendingMessages: record.messages,
|
|
8797
|
-
reports: Array.isArray(record.reports) ? record.reports.slice(-4).map((report) =>
|
|
8998
|
+
reports: Array.isArray(record.reports) ? record.reports.slice(-4).map((report) => {
|
|
8999
|
+
const parsed = parseDelegationReport(typeof report?.raw === "string" ? report.raw : void 0, typeof report?.runId === "string" ? report.runId : "legacy", report?.stopReason ?? report?.availability === "truncated");
|
|
9000
|
+
if (["empty", "invalid_json", "invalid_shape", "char_cap", "provider_length", "error", "aborted", "deadline", "cancelled", "no_terminal"].includes(report?.reason ?? "")) parsed.reason = report.reason;
|
|
9001
|
+
return parsed;
|
|
9002
|
+
}) : void 0,
|
|
9003
|
+
usageRuns: restoreSubagentUsageRuns(record.usageRuns),
|
|
8798
9004
|
createdAt: record.createdAt,
|
|
8799
9005
|
lastUsedAt: record.lastUsedAt,
|
|
8800
9006
|
runCount: record.runCount,
|
|
@@ -8876,7 +9082,7 @@ async function persistSubagentSession(deps, session, task) {
|
|
|
8876
9082
|
if (task.status === "completed" && task.result && transcriptChars > SESSION_TRANSCRIPT_WARN_CHARS) {
|
|
8877
9083
|
task.result += `
|
|
8878
9084
|
|
|
8879
|
-
[Session growth warning: session ${session.id} now carries
|
|
9085
|
+
[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
9086
|
}
|
|
8881
9087
|
if (!deps.sessionStore) return;
|
|
8882
9088
|
if (transcriptChars > SESSION_RECORD_MAX_CHARS) {
|
|
@@ -8908,6 +9114,13 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
|
|
|
8908
9114
|
let heartbeat;
|
|
8909
9115
|
let session;
|
|
8910
9116
|
let runStarted = false;
|
|
9117
|
+
let runUsage;
|
|
9118
|
+
const shownPhases = /* @__PURE__ */ new Set();
|
|
9119
|
+
const phaseProgress = (phase) => {
|
|
9120
|
+
if (shownPhases.has(phase) || shownPhases.size >= 16) return;
|
|
9121
|
+
shownPhases.add(phase);
|
|
9122
|
+
report({ message: `[${task.name}] Phase: ${phase}` });
|
|
9123
|
+
};
|
|
8911
9124
|
let baseline = 0;
|
|
8912
9125
|
let hardDeadlineAt;
|
|
8913
9126
|
let pendingRun;
|
|
@@ -8916,7 +9129,9 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
|
|
|
8916
9129
|
if (!runStarted || !session?.agent) return;
|
|
8917
9130
|
const last = [...session.agent.state.messages.slice(baseline)].reverse().find((m) => m?.role === "assistant");
|
|
8918
9131
|
const terminal = isReportTerminal(last) ? last : void 0;
|
|
8919
|
-
|
|
9132
|
+
const hooks = agentRunHooks.get(session.agent);
|
|
9133
|
+
const capturedText = terminal && hooks?.terminalStopReason === terminal.stopReason ? hooks?.terminalText : void 0;
|
|
9134
|
+
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
9135
|
};
|
|
8921
9136
|
let agentSettled = true;
|
|
8922
9137
|
let releaseLease;
|
|
@@ -8959,7 +9174,12 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
|
|
|
8959
9174
|
}
|
|
8960
9175
|
const nextModelOverride = task.modelOverride ?? session.modelOverride;
|
|
8961
9176
|
const nextThinking = task.thinkingLevel ?? session.thinkingLevel;
|
|
8962
|
-
|
|
9177
|
+
const latestReport = session.reports?.at(-1);
|
|
9178
|
+
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.`);
|
|
9179
|
+
const history = session.agent?.state.messages ?? session.pendingMessages ?? [];
|
|
9180
|
+
const historyChars = task.resumeMode === "report" ? 0 : estimateTranscriptChars(history);
|
|
9181
|
+
task.recallInput = { mode: task.resumeMode ?? "full", messageCount: task.resumeMode === "report" ? 0 : history.length, jsonChars: historyChars, warning: historyChars > SESSION_TRANSCRIPT_WARN_CHARS, cost: "unknown" };
|
|
9182
|
+
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
9183
|
const mustRebuild = task.resumeMode === "report" || session.agent === null || task.requestedMode !== void 0 || task.modelOverride !== void 0 || task.thinkingLevel !== void 0;
|
|
8964
9184
|
if (!mustRebuild) {
|
|
8965
9185
|
subagent = session.agent;
|
|
@@ -9063,6 +9283,14 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
|
|
|
9063
9283
|
if (sessions) retainLiveSession(sessions, session, Math.max(1, deps.maxLiveSessions ?? DEFAULT_MAX_LIVE_SESSIONS));
|
|
9064
9284
|
if (signal?.aborted || sessions?.disposed) throw new Error("Subagent capability disposed or aborted by parent");
|
|
9065
9285
|
const hooks = agentRunHooks.get(subagent);
|
|
9286
|
+
runUsage = createSubagentUsage(session.id, `${task.id}:${session.runCount + 1}`);
|
|
9287
|
+
(task.usageRuns ??= []).push(runUsage);
|
|
9288
|
+
if (hooks) {
|
|
9289
|
+
hooks.usage = runUsage;
|
|
9290
|
+
hooks.onPhase = phaseProgress;
|
|
9291
|
+
hooks.terminalText = void 0;
|
|
9292
|
+
hooks.terminalStopReason = void 0;
|
|
9293
|
+
}
|
|
9066
9294
|
hardDeadlineAt = Date.now() + runTimeoutSeconds * 1e3;
|
|
9067
9295
|
if (hooks) {
|
|
9068
9296
|
hooks.observation = task.observation;
|
|
@@ -9086,6 +9314,7 @@ async function runSubagentWithProgress(deps, task, reportProgress, signal, sessi
|
|
|
9086
9314
|
softTimeout = setTimeout(() => {
|
|
9087
9315
|
if (hooks) hooks.finalizing = true;
|
|
9088
9316
|
observeDelegationPhase(task.observation, "finalizing", false);
|
|
9317
|
+
phaseProgress("finalizing");
|
|
9089
9318
|
}, subagentSoftDeadlineMs(runTimeoutSeconds * 1e3));
|
|
9090
9319
|
timeout = setTimeout(() => {
|
|
9091
9320
|
timedOut = true;
|
|
@@ -9189,7 +9418,7 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
|
|
|
9189
9418
|
const terminalStopReason = lastAssistant?.stopReason;
|
|
9190
9419
|
const terminalError = typeof lastAssistant?.errorMessage === "string" ? lastAssistant.errorMessage : void 0;
|
|
9191
9420
|
const collectedResponse = isReportTerminal(lastAssistant) ? collectLastAssistantText([lastAssistant]) || void 0 : void 0;
|
|
9192
|
-
task.report = parseDelegationReport(collectedResponse, `${task.id}:${(session?.runCount ?? 0) + 1}`, terminalStopReason
|
|
9421
|
+
task.report = parseDelegationReport(collectedResponse, `${task.id}:${(session?.runCount ?? 0) + 1}`, terminalStopReason ?? "no_terminal");
|
|
9193
9422
|
const streamInterrupted = terminalStopReason === "error" || terminalStopReason === "aborted" || terminalError || !collectedResponse && terminalStopReason !== "stop" || terminalStopReason === "length" && !messageHasOwnText(lastAssistant);
|
|
9194
9423
|
if (streamInterrupted) {
|
|
9195
9424
|
if (terminalStopReason === "length") {
|
|
@@ -9238,6 +9467,7 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
|
|
|
9238
9467
|
refreshReport();
|
|
9239
9468
|
task.status = timedOut ? "timeout" : signal?.aborted ? "cancelled" : "failed";
|
|
9240
9469
|
observeDelegationPhase(task.observation, timedOut ? "deadline" : signal?.aborted ? "cancelled" : "failed");
|
|
9470
|
+
phaseProgress(task.observation.phase);
|
|
9241
9471
|
task.error = errorMessage.slice(0, 2e3);
|
|
9242
9472
|
task.report ??= parseDelegationReport(void 0, task.id);
|
|
9243
9473
|
task.parentHandoffRequired = isParentHandoffRequired(task);
|
|
@@ -9247,14 +9477,21 @@ ${DELEGATION_REPORT_INSTRUCTION}`;
|
|
|
9247
9477
|
if (heartbeat) {
|
|
9248
9478
|
clearInterval(heartbeat);
|
|
9249
9479
|
}
|
|
9480
|
+
if (runUsage) settleSubagentUsage(runUsage, agentSettled);
|
|
9250
9481
|
const finalize = async () => {
|
|
9482
|
+
if (runUsage) settleSubagentUsage(runUsage, true);
|
|
9251
9483
|
try {
|
|
9252
9484
|
if (session) {
|
|
9253
9485
|
const hooks = session.agent ? agentRunHooks.get(session.agent) : void 0;
|
|
9254
|
-
if (hooks && hooks.observation === task.observation)
|
|
9486
|
+
if (hooks && hooks.observation === task.observation) {
|
|
9487
|
+
hooks.observation = void 0;
|
|
9488
|
+
hooks.onPhase = void 0;
|
|
9489
|
+
hooks.usage = void 0;
|
|
9490
|
+
}
|
|
9255
9491
|
if (runStarted) {
|
|
9256
9492
|
refreshReport();
|
|
9257
9493
|
session.runCount++;
|
|
9494
|
+
if (runUsage) session.usageRuns = [...session.usageRuns ?? [], runUsage].slice(-4);
|
|
9258
9495
|
session.reports = [...session.reports ?? [], task.report ?? parseDelegationReport(void 0, task.id)].slice(-4);
|
|
9259
9496
|
}
|
|
9260
9497
|
session.lastUsedAt = Date.now();
|
|
@@ -9305,7 +9542,9 @@ function buildParallelResult(tasks, totalDuration) {
|
|
|
9305
9542
|
if (task.details) {
|
|
9306
9543
|
resultText += `, ${task.details.durationMs}ms, ${task.details.toolCalls} tools`;
|
|
9307
9544
|
}
|
|
9308
|
-
resultText += `, report=${task.report?.availability ?? "missing"})
|
|
9545
|
+
resultText += `, report=${task.report?.availability ?? "missing"}${task.report?.reason ? ` (${task.report.reason})` : ""})
|
|
9546
|
+
`;
|
|
9547
|
+
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
9548
|
`;
|
|
9310
9549
|
if (task.observation) resultText += `Phase: ${task.observation.phase}; last activity: ${task.observation.lastActivity} at ${task.observation.lastWorkAt}
|
|
9311
9550
|
`;
|
|
@@ -9501,7 +9740,7 @@ Default mode="read" is for investigation, search, review, or triage and cannot e
|
|
|
9501
9740
|
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
9741
|
timeout: Type.Optional(Type.Number({ description: "Seconds. Default 1200; set higher for long tasks." })),
|
|
9503
9742
|
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);
|
|
9743
|
+
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
9744
|
}
|
|
9506
9745
|
// No additionalProperties lock: legacy callers may send task aliases
|
|
9507
9746
|
// (description/prompt/objective); normalizeTaskDefs resolves them at
|
|
@@ -9631,6 +9870,8 @@ ${SPAWN_USAGE_HINT}` }],
|
|
|
9631
9870
|
reportedEvidenceCount: task.reportedEvidence.length,
|
|
9632
9871
|
confidenceSignalCount: task.confidenceSignals.length,
|
|
9633
9872
|
report: task.report,
|
|
9873
|
+
recallInput: task.recallInput,
|
|
9874
|
+
usageRuns: task.usageRuns?.map((usage) => ({ ...usage, reportedTokens: { ...usage.reportedTokens } })),
|
|
9634
9875
|
observation: task.observation,
|
|
9635
9876
|
parentHandoffRequired: task.parentHandoffRequired,
|
|
9636
9877
|
failureReason: task.error,
|
|
@@ -10978,7 +11219,7 @@ function createReadTool(cwd, options) {
|
|
|
10978
11219
|
label: "read",
|
|
10979
11220
|
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
11221
|
parameters: readSchema,
|
|
10981
|
-
execute: async (_toolCallId, params, signal) => {
|
|
11222
|
+
execute: async (_toolCallId, params, signal, _onUpdate) => {
|
|
10982
11223
|
const { path: path3, root, question } = params;
|
|
10983
11224
|
const tail = params.tail;
|
|
10984
11225
|
let offset = params.offset;
|
|
@@ -11005,7 +11246,7 @@ function createReadTool(cwd, options) {
|
|
|
11005
11246
|
const message = error instanceof Error ? error.message : String(error);
|
|
11006
11247
|
if (/outside sandbox|outside root|escapes sandbox/i.test(message)) {
|
|
11007
11248
|
return createReadErrorResult(
|
|
11008
|
-
`${message}. read_file is workspace-scoped; for intentional runtime logs or temporary files outside the workspace, use
|
|
11249
|
+
`${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
11250
|
);
|
|
11010
11251
|
}
|
|
11011
11252
|
return createReadErrorResult(message);
|
|
@@ -16914,7 +17155,7 @@ function unavailableResult(query, requestedMode, reason) {
|
|
|
16914
17155
|
text: [
|
|
16915
17156
|
`Web search is unavailable for "${query}".`,
|
|
16916
17157
|
reason,
|
|
16917
|
-
"Do not use
|
|
17158
|
+
"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
17159
|
].join("\n")
|
|
16919
17160
|
}],
|
|
16920
17161
|
details: {
|
|
@@ -17422,7 +17663,7 @@ function createSharedWebSearchTool(deps) {
|
|
|
17422
17663
|
return {
|
|
17423
17664
|
name: "web_search",
|
|
17424
17665
|
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
|
|
17666
|
+
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
17667
|
parameters: webSearchSchema,
|
|
17427
17668
|
execute: async (_toolCallId, rawParams, signal) => {
|
|
17428
17669
|
const input = rawParams;
|
|
@@ -18013,7 +18254,7 @@ function createSharedWebFetchTool(deps = {}) {
|
|
|
18013
18254
|
return {
|
|
18014
18255
|
name: "web_fetch",
|
|
18015
18256
|
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
|
|
18257
|
+
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
18258
|
parameters: webFetchSchema,
|
|
18018
18259
|
capabilityMetadata: {
|
|
18019
18260
|
riskClass: "network",
|
|
@@ -18637,7 +18878,7 @@ function createSharedWebResearchTool(deps) {
|
|
|
18637
18878
|
return {
|
|
18638
18879
|
name: "web_research",
|
|
18639
18880
|
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
|
|
18881
|
+
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
18882
|
parameters: webResearchSchema,
|
|
18642
18883
|
capabilityMetadata: {
|
|
18643
18884
|
riskClass: "network",
|
|
@@ -19208,6 +19449,8 @@ export {
|
|
|
19208
19449
|
findFirstKeptEntrySummaryId,
|
|
19209
19450
|
createCompactionSummary,
|
|
19210
19451
|
generateEntryId,
|
|
19452
|
+
createHostEnvelopeProjectorRegistry,
|
|
19453
|
+
projectHostEnvelopes,
|
|
19211
19454
|
FileSessionStore,
|
|
19212
19455
|
createSessionManager,
|
|
19213
19456
|
prepareSessionCompaction,
|
|
@@ -19248,6 +19491,7 @@ export {
|
|
|
19248
19491
|
supersedeExecutionState,
|
|
19249
19492
|
shouldPreserveExecutionStateForUserText,
|
|
19250
19493
|
BUILTIN_TOOL_CAPABILITY_METADATA,
|
|
19494
|
+
getToolCapabilityMetadata,
|
|
19251
19495
|
isToolAllowedInPlanMode,
|
|
19252
19496
|
extractPlanTodoItems,
|
|
19253
19497
|
isPlanModeSafeCommand,
|