@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.
- 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 +11 -5
- 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-E6F4BTNN.js} +325 -56
- package/dist/chunks/{chunk-YWWLRZSG.js → chunk-P22SYVGO.js} +291 -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 +494 -325
- 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,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
|
-
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
-
|
|
7923
|
-
|
|
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")
|
|
8013
|
-
|
|
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
|
|
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
|
|
8611
|
-
plan.toolsExcluded.push({ name:
|
|
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) =>
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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)
|
|
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);
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|