@sema-agent/core 5.65.0 → 6.0.0
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/CHANGELOG.md +46 -0
- package/dist/agents/subagent.d.ts +2 -2
- package/dist/agents/subagent.js +11 -0
- package/dist/agents/verify.d.ts +1 -1
- package/dist/brain/anthropic.js +1 -1
- package/dist/brain/errors.d.ts +29 -0
- package/dist/brain/errors.js +20 -0
- package/dist/brain/open-responses.js +2 -2
- package/dist/brain/route-adjudicator.d.ts +8 -1
- package/dist/brain/route-adjudicator.js +1 -0
- package/dist/brain/status-sink.js +12 -1
- package/dist/brain/stream-engine.js +17 -6
- package/dist/core/auto-compaction.d.ts +26 -0
- package/dist/core/auto-compaction.js +7 -2
- package/dist/core/auto-mode-arming.d.ts +138 -0
- package/dist/core/auto-mode-arming.js +181 -0
- package/dist/core/auto-mode-defaults.d.ts +13 -0
- package/dist/core/auto-mode-defaults.js +5 -0
- package/dist/core/auto-mode-prompt.d.ts +14 -3
- package/dist/core/auto-mode-prompt.js +10 -7
- package/dist/core/auto-mode-rebuild.d.ts +75 -0
- package/dist/core/auto-mode-rebuild.js +41 -0
- package/dist/core/auto-mode.d.ts +15 -0
- package/dist/core/auto-mode.js +4 -2
- package/dist/core/checkpoint-store.d.ts +18 -0
- package/dist/core/context-edit.d.ts +47 -5
- package/dist/core/context-guard.d.ts +1 -1
- package/dist/core/file-history-retention.d.ts +106 -0
- package/dist/core/file-history-retention.js +36 -0
- package/dist/core/file-history-store.d.ts +768 -0
- package/dist/core/file-history-store.js +880 -0
- package/dist/core/governance-codes.d.ts +2 -1
- package/dist/core/governance-codes.js +14 -0
- package/dist/core/hooks.d.ts +39 -7
- package/dist/core/hooks.js +38 -21
- package/dist/core/lsp.d.ts +2 -2
- package/dist/core/mcp.d.ts +29 -7
- package/dist/core/memory-engine/consolidation-driver.d.ts +11 -0
- package/dist/core/memory-engine/consolidation-driver.js +71 -4
- package/dist/core/memory-engine/consolidation.d.ts +25 -2
- package/dist/core/memory-engine/consolidation.js +4 -1
- package/dist/core/memory-engine/distiller.d.ts +84 -1
- package/dist/core/memory-engine/distiller.js +68 -0
- package/dist/core/memory-engine/dual-root.js +3 -0
- package/dist/core/memory-engine/engine.d.ts +328 -15
- package/dist/core/memory-engine/engine.js +355 -29
- package/dist/core/memory-engine/file-backend.d.ts +30 -0
- package/dist/core/memory-engine/file-backend.js +14 -13
- package/dist/core/memory-engine/frontmatter.d.ts +22 -1
- package/dist/core/memory-engine/frontmatter.js +3 -0
- package/dist/core/memory-engine/header-hints.d.ts +5 -0
- package/dist/core/memory-engine/index.d.ts +5 -4
- package/dist/core/memory-engine/index.js +5 -4
- package/dist/core/memory-engine/layout.d.ts +88 -2
- package/dist/core/memory-engine/layout.js +112 -3
- package/dist/core/memory-engine/provenance-wording.d.ts +7 -0
- package/dist/core/memory-engine/provenance-wording.js +3 -0
- package/dist/core/memory-engine/tools.d.ts +89 -8
- package/dist/core/memory-engine/tools.js +263 -22
- package/dist/core/memory-engine/types.d.ts +64 -1
- package/dist/core/memory-recall.d.ts +6 -0
- package/dist/core/memory.d.ts +27 -1
- package/dist/core/memory.js +16 -2
- package/dist/core/permission-rule-consent.d.ts +20 -0
- package/dist/core/permission-rule-consent.js +12 -3
- package/dist/core/permission-rule-model.d.ts +67 -7
- package/dist/core/permission-rule-model.js +53 -7
- package/dist/core/permission-rule-store.js +15 -10
- package/dist/core/permission-rule-sync.js +15 -11
- package/dist/core/retention-policy.d.ts +9 -0
- package/dist/core/retention-policy.js +5 -2
- package/dist/core/retention.d.ts +13 -2
- package/dist/core/runner/assemble-result.d.ts +19 -1
- package/dist/core/runner/assemble-result.js +17 -2
- package/dist/core/runner/compaction-call-options.d.ts +93 -0
- package/dist/core/runner/compaction-call-options.js +3 -0
- package/dist/core/runner/memory-capture-optout.d.ts +80 -0
- package/dist/core/runner/memory-capture-optout.js +53 -0
- package/dist/core/runner/prepare-config-doors.d.ts +5 -0
- package/dist/core/runner/prepare-config-doors.js +16 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +110 -5
- package/dist/core/runner/prepare-hands-readface.js +99 -7
- package/dist/core/runner/prepare-memory.d.ts +88 -0
- package/dist/core/runner/prepare-memory.js +305 -24
- package/dist/core/runner/prepare-task.d.ts +141 -1
- package/dist/core/runner/prepare-task.js +443 -79
- package/dist/core/runner/runtask.d.ts +9 -20
- package/dist/core/runner/runtask.js +133 -96
- package/dist/core/runner/session-file-state-replay.d.ts +18 -10
- package/dist/core/runner/session-file-state-replay.js +52 -1
- package/dist/core/runner/tool-disclosure.js +2 -1
- package/dist/core/runner/turn-attachments.d.ts +22 -12
- package/dist/core/session-store.d.ts +1 -1
- package/dist/core/session-store.js +6 -1
- package/dist/core/session.d.ts +34 -1
- package/dist/core/store-contracts/file-history-store-contract.d.ts +3 -0
- package/dist/core/store-contracts/file-history-store-contract.js +720 -0
- package/dist/core/task-registry-shared.js +11 -1
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +172 -1
- package/dist/core/tool-policy.js +32 -1
- package/dist/core/tool-result-store.js +2 -1
- package/dist/core/trace.d.ts +24 -0
- package/dist/core/types.d.ts +784 -89
- package/dist/core/types.js +4 -3
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/untrusted-text.js +8 -0
- package/dist/core/workflow-run-store-contract.js +6 -2
- package/dist/core/workflow-run-store.d.ts +4 -1
- package/dist/engine/compaction/compaction.d.ts +88 -10
- package/dist/engine/compaction/compaction.js +109 -30
- package/dist/engine/execution-env/node-execution-env.d.ts +9 -1
- package/dist/engine/execution-env/node-execution-env.js +28 -0
- package/dist/engine/harness/agent-harness.d.ts +52 -1
- package/dist/engine/harness/agent-harness.js +36 -1
- package/dist/engine/harness/types.d.ts +26 -1
- package/dist/engine/llm/types.d.ts +50 -4
- package/dist/engine/loop/agent-loop.d.ts +5 -1
- package/dist/engine/loop/agent-loop.js +25 -0
- package/dist/engine/loop/types.d.ts +19 -0
- package/dist/engine/lsp/node-lsp-manager.d.ts +1 -1
- package/dist/engine/session/session.js +1 -1
- package/dist/index.d.ts +18 -8
- package/dist/index.js +14 -6
- package/dist/orchestration/run-workflow-tool.d.ts +20 -2
- package/dist/orchestration/run-workflow-tool.js +22 -3
- package/dist/orchestration/workflow-governance.d.ts +59 -1
- package/dist/orchestration/workflow-governance.js +61 -8
- package/dist/orchestration/workflow-meta.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +56 -13
- package/dist/orchestration/workflow-types.d.ts +78 -2
- package/dist/orchestration/workflow.d.ts +20 -0
- package/dist/orchestration/workflow.js +163 -14
- package/dist/prompt-assembly/event-registry.js +1 -1
- package/dist/prompts/default.d.ts +7 -7
- package/dist/stores/file/file-history-store.d.ts +368 -0
- package/dist/stores/file/file-history-store.js +1248 -0
- package/dist/stores/file/index.d.ts +22 -13
- package/dist/stores/file/index.js +4 -4
- package/dist/stores/file/permission-rule-store.js +1 -0
- package/dist/stores/file/strategy-store.d.ts +3 -3
- package/dist/tools/fs/bash-readonly-classifier.d.ts +87 -3
- package/dist/tools/fs/bash-readonly-classifier.js +106 -4
- package/dist/tools/fs/fs-bash.js +9 -5
- package/dist/tools/fs/fs-shared.d.ts +52 -1
- package/dist/tools/fs/fs-shared.js +14 -0
- package/dist/tools/fs/fs-write.d.ts +5 -5
- package/dist/tools/fs/fs-write.js +71 -14
- package/dist/tools/fs/index.d.ts +6 -1
- package/dist/tools/fs/index.js +1 -1
- package/dist/tools/web.js +2 -1
- package/package.json +5 -1
- package/test/export-surface.snapshot.json +155 -23
- package/dist/core/file-snapshot-store.d.ts +0 -165
- package/dist/core/file-snapshot-store.js +0 -259
- package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +0 -13
- package/dist/core/store-contracts/file-snapshot-store-contract.js +0 -134
- package/dist/stores/file/file-snapshot-store.d.ts +0 -58
- package/dist/stores/file/file-snapshot-store.js +0 -353
|
@@ -17,6 +17,7 @@ import { delimitUntrusted } from "../core/untrusted-text.js";
|
|
|
17
17
|
import { OUTPUT_TOOL_NAME } from "../core/runner/synthetic-tools.js";
|
|
18
18
|
import { compileOutputSchema } from "../core/runner/strict-output-schema.js";
|
|
19
19
|
import { WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentBlockedError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowMaxAgentsError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } from "./workflow-types.js";
|
|
20
|
+
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
20
21
|
export * from "./workflow-types.js";
|
|
21
22
|
const MAX_TRANSCRIPT_CHARS = 4000;
|
|
22
23
|
const WORKFLOW_RESULT_MAX = 4000;
|
|
@@ -201,9 +202,94 @@ function currentWorkflowDepth() {
|
|
|
201
202
|
return workflowDepthStore.getStore()?.depth ?? 0;
|
|
202
203
|
}
|
|
203
204
|
export const MAX_WORKFLOW_ITEMS = 4096;
|
|
205
|
+
function describeFanOutValue(v) {
|
|
206
|
+
if (v === null)
|
|
207
|
+
return "null";
|
|
208
|
+
if (Array.isArray(v))
|
|
209
|
+
return "array";
|
|
210
|
+
if (v instanceof Promise)
|
|
211
|
+
return "a Promise (an already-CALLED agent(...) — wrap it: () => agent(...))";
|
|
212
|
+
return typeof v;
|
|
213
|
+
}
|
|
214
|
+
function assertFanOutCallables(lane, member, list) {
|
|
215
|
+
for (let i = 0; i < list.length; i++) {
|
|
216
|
+
if (typeof list[i] !== "function") {
|
|
217
|
+
throw new WorkflowScriptError(`${lane}() ${member} at index ${i} is not a function (got ${describeFanOutValue(list[i])}) — each ${member} must be a ` +
|
|
218
|
+
`thunk: () => agent(...). Nothing was run: a non-function member is never called, so its slot would fold to null ` +
|
|
219
|
+
`with no agent, no journal row and no error — the whole call is refused instead.`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function assertFanOutArray(lane, what, v) {
|
|
224
|
+
if (!Array.isArray(v)) {
|
|
225
|
+
throw new WorkflowScriptError(`${lane}(): ${what} must be an ARRAY (got ${describeFanOutValue(v)}). Nothing was run.`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function snapshotFanOutList(lane, what, v) {
|
|
229
|
+
assertFanOutArray(lane, what, v);
|
|
230
|
+
const declared = v.length;
|
|
231
|
+
if (typeof declared !== "number" || !Number.isSafeInteger(declared) || declared < 0) {
|
|
232
|
+
throw new WorkflowScriptError(`${lane}(): ${what} does not report a valid array length. Nothing was run.`);
|
|
233
|
+
}
|
|
234
|
+
if (declared > MAX_WORKFLOW_ITEMS)
|
|
235
|
+
throw new Error(`${lane}: too many items (${declared} > ${MAX_WORKFLOW_ITEMS})`);
|
|
236
|
+
const snapshot = [];
|
|
237
|
+
for (let i = 0; i < declared; i++)
|
|
238
|
+
snapshot.push(v[i]);
|
|
239
|
+
return snapshot;
|
|
240
|
+
}
|
|
241
|
+
function assertFanOutOptionsShape(v, position) {
|
|
242
|
+
const looksLikeBag = typeof v === "object" &&
|
|
243
|
+
v !== null &&
|
|
244
|
+
!Array.isArray(v) &&
|
|
245
|
+
Object.keys(v).every((k) => k === "errors") &&
|
|
246
|
+
(v.errors === undefined || Array.isArray(v.errors));
|
|
247
|
+
if (!looksLikeBag) {
|
|
248
|
+
throw new WorkflowScriptError(`pipeline() argument at stage position ${position} is not a function (got ${describeFanOutValue(v)}) and is not the ` +
|
|
249
|
+
`trailing fan-out options bag \`{ errors: [] }\` either — each stage must be a function (prev, item, index) => …. ` +
|
|
250
|
+
`Nothing was run.`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
204
253
|
export const WORKFLOW_AGENT_STALL_MS = 180_000;
|
|
205
254
|
export const WORKFLOW_AGENT_MAX_RETRIES = 5;
|
|
206
255
|
export const WORKFLOW_AGENT_THROTTLE_BACKOFF_MS = 45_000;
|
|
256
|
+
function readLegPendingApproval(result, announce) {
|
|
257
|
+
if (result === undefined)
|
|
258
|
+
return undefined;
|
|
259
|
+
const raw = result.pendingApproval;
|
|
260
|
+
if (raw === undefined)
|
|
261
|
+
return undefined;
|
|
262
|
+
const refuse = (why) => {
|
|
263
|
+
announce(`[approval] a leg result carried a malformed pendingApproval report (${why}) — ignoring it: this run ` +
|
|
264
|
+
`will judge the leg by its progress watchdog alone, exactly as a deployment that reports nothing does. ` +
|
|
265
|
+
`A leg genuinely waiting on a person will be retried and may exhaust its stall budget.`);
|
|
266
|
+
return undefined;
|
|
267
|
+
};
|
|
268
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw))
|
|
269
|
+
return refuse("not an object");
|
|
270
|
+
const { askIds, oldestCreatedAtMs } = raw;
|
|
271
|
+
if (!Array.isArray(askIds))
|
|
272
|
+
return refuse("askIds is not an array");
|
|
273
|
+
const ids = [...askIds];
|
|
274
|
+
if (ids.length === 0)
|
|
275
|
+
return refuse('askIds is empty — "nothing outstanding" is spelled by OMITTING the key');
|
|
276
|
+
if (!ids.every((id) => typeof id === "string" && id !== ""))
|
|
277
|
+
return refuse("askIds holds a non-string or empty id");
|
|
278
|
+
if (typeof oldestCreatedAtMs !== "number" || !Number.isFinite(oldestCreatedAtMs))
|
|
279
|
+
return refuse("oldestCreatedAtMs is not a finite number");
|
|
280
|
+
return { askIds: ids, oldestCreatedAtMs };
|
|
281
|
+
}
|
|
282
|
+
function readLegApprovalWaitedMs(result, announce) {
|
|
283
|
+
const raw = result.approvalWaitedMs;
|
|
284
|
+
if (raw === undefined)
|
|
285
|
+
return undefined;
|
|
286
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw < 0) {
|
|
287
|
+
announce(`[approval] a leg result carried an unreadable approvalWaitedMs (${typeof raw === "number" ? String(raw) : `not a number: ${typeof raw}`}) — ` +
|
|
288
|
+
`dropping it: this run's timeout disclosure will say nothing about approval waiting rather than publish a duration it cannot vouch for.`);
|
|
289
|
+
return undefined;
|
|
290
|
+
}
|
|
291
|
+
return raw;
|
|
292
|
+
}
|
|
207
293
|
export const WORKFLOW_RESUME_CLAIM_FINALIZE_TIMEOUT_MS = 10_000;
|
|
208
294
|
const REAL_WORKFLOW_TIMERS = {
|
|
209
295
|
setTimeout(fn, ms) {
|
|
@@ -527,6 +613,18 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
527
613
|
...(opts.inheritedGate !== undefined ? { inheritedGate: opts.inheritedGate } : {}),
|
|
528
614
|
...((opts.rootSessionId ?? opts.originatingSessionId) !== undefined ? { rootSessionId: opts.rootSessionId ?? opts.originatingSessionId } : {}),
|
|
529
615
|
...(opts.placementRoot !== undefined ? { placementRoot: opts.placementRoot } : {}),
|
|
616
|
+
...(opts.originatingSessionId !== undefined ? { parentSessionId: opts.originatingSessionId } : {}),
|
|
617
|
+
};
|
|
618
|
+
const captureFloorSeatsNow = () => {
|
|
619
|
+
const s = opts.parentMemoryCaptureState?.();
|
|
620
|
+
if (s === undefined)
|
|
621
|
+
return {};
|
|
622
|
+
return {
|
|
623
|
+
...(s.optedOut === true ? { memoryCaptureFloor: true } : {}),
|
|
624
|
+
...(s.optedOut !== true && s.indeterminate === true ? { memoryCaptureFloorIndeterminate: true } : {}),
|
|
625
|
+
...(s.controlDir !== undefined ? { memoryCaptureQueryDir: s.controlDir } : {}),
|
|
626
|
+
...(s.ancestors !== undefined ? { memoryCaptureAncestors: s.ancestors } : {}),
|
|
627
|
+
};
|
|
530
628
|
};
|
|
531
629
|
const bceSink = opts.onBackgroundChildEvent;
|
|
532
630
|
const bceEmit = (e) => {
|
|
@@ -788,6 +886,37 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
788
886
|
return;
|
|
789
887
|
emitLogLine(message);
|
|
790
888
|
};
|
|
889
|
+
const setLegRunId = (rec, from) => {
|
|
890
|
+
if (from.runId !== undefined && from.runId !== "")
|
|
891
|
+
rec.taskRunId = from.runId;
|
|
892
|
+
else
|
|
893
|
+
delete rec.taskRunId;
|
|
894
|
+
};
|
|
895
|
+
const foldLegApprovalReport = (rec, result) => {
|
|
896
|
+
const report = readLegPendingApproval(result, emitRunLog);
|
|
897
|
+
if (report !== undefined)
|
|
898
|
+
rec.pendingApproval = report;
|
|
899
|
+
else
|
|
900
|
+
delete rec.pendingApproval;
|
|
901
|
+
const waited = readLegApprovalWaitedMs(result, emitRunLog);
|
|
902
|
+
if (waited !== undefined)
|
|
903
|
+
rec.approvalWaitedMs = waited;
|
|
904
|
+
return report;
|
|
905
|
+
};
|
|
906
|
+
let unbackstoppedWaiverAnnounced = false;
|
|
907
|
+
const approvalWaiverBackstopArmed = () => {
|
|
908
|
+
if (totalTimeoutMs !== undefined) {
|
|
909
|
+
return !finalized && timeoutController?.signal.aborted !== true;
|
|
910
|
+
}
|
|
911
|
+
if (!unbackstoppedWaiverAnnounced) {
|
|
912
|
+
unbackstoppedWaiverAnnounced = true;
|
|
913
|
+
emitRunLog(`[approval] an agent reported outstanding human approvals, but this run arms no totalTimeoutMs — so the ` +
|
|
914
|
+
`stall-budget waiver is WITHHELD and approval-blocked attempts are charged exactly as before. Waiving them ` +
|
|
915
|
+
`would leave the retry loop with no ceiling at all (the token budget and maxAgents gate new ctx.agent ` +
|
|
916
|
+
`calls, not one call's attempts). Set runWorkflow's totalTimeoutMs to let this run wait for people.`);
|
|
917
|
+
}
|
|
918
|
+
return false;
|
|
919
|
+
};
|
|
791
920
|
const stampBudgetOvershoot = (unsettledTokens) => {
|
|
792
921
|
if (budgetTotal === null || run.budgetOvershoot !== undefined)
|
|
793
922
|
return;
|
|
@@ -809,6 +938,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
809
938
|
let agentsCompleted = 0;
|
|
810
939
|
let agentsFailed = 0;
|
|
811
940
|
let agentsInFlight = 0;
|
|
941
|
+
let approvalWaitedMs;
|
|
812
942
|
for (const a of run.agents) {
|
|
813
943
|
if (a.status === "completed")
|
|
814
944
|
agentsCompleted++;
|
|
@@ -816,8 +946,10 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
816
946
|
agentsFailed++;
|
|
817
947
|
else
|
|
818
948
|
agentsInFlight++;
|
|
949
|
+
if (a.approvalWaitedMs !== undefined && (approvalWaitedMs === undefined || a.approvalWaitedMs > approvalWaitedMs))
|
|
950
|
+
approvalWaitedMs = a.approvalWaitedMs;
|
|
819
951
|
}
|
|
820
|
-
run.timeoutInterruption = { timeoutMs: totalTimeoutMs, agentsCompleted, agentsFailed, agentsInFlight };
|
|
952
|
+
run.timeoutInterruption = { timeoutMs: totalTimeoutMs, agentsCompleted, agentsFailed, agentsInFlight, ...(approvalWaitedMs !== undefined ? { approvalWaitedMs } : {}) };
|
|
821
953
|
};
|
|
822
954
|
let divergenceNoted = false;
|
|
823
955
|
const noteDivergence = (ordinal, reason) => {
|
|
@@ -989,6 +1121,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
989
1121
|
rec.taskStatus = result.status;
|
|
990
1122
|
if (result.sessionId)
|
|
991
1123
|
rec.sessionId = result.sessionId;
|
|
1124
|
+
setLegRunId(rec, result);
|
|
992
1125
|
rec.endedAt = now();
|
|
993
1126
|
rec.stats = { tokens: s.tokens ?? 0, turns: s.turns ?? 0, costMicroUsd: s.costMicroUsd };
|
|
994
1127
|
const output = settleAgentError(rec, result, rec.label, boundedRedactedSummary(result.structuredOutput ?? result.result, MAX_TRANSCRIPT_CHARS));
|
|
@@ -996,6 +1129,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
996
1129
|
rec.toolCalls = result.stats.toolCalls;
|
|
997
1130
|
if (activityTail.length > 0)
|
|
998
1131
|
rec.activity = activityTail.slice();
|
|
1132
|
+
foldLegApprovalReport(rec, result);
|
|
999
1133
|
emit({ type: "agent_end", runId, label: rec.label, phase: rec.phase, ...(rec.groupId !== undefined ? { groupId: rec.groupId } : {}), status: rec.status, output, ...(rec.errorCode !== undefined ? { errorCode: rec.errorCode } : {}), ...(result.stats.toolCalls !== undefined ? { toolCalls: result.stats.toolCalls } : {}), ...(result.model !== undefined ? { modelResolved: result.model } : {}), ts: rec.endedAt });
|
|
1000
1134
|
void persist("update");
|
|
1001
1135
|
bceTerminal(rec.callKey, rec.status === "completed" ? "completed" : "failed", output, result.sessionId || undefined, rec.stats);
|
|
@@ -1038,6 +1172,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1038
1172
|
status: r.status === "completed" ? "completed" : "failed",
|
|
1039
1173
|
taskStatus: r.status,
|
|
1040
1174
|
...(r.sessionId ? { sessionId: r.sessionId } : {}),
|
|
1175
|
+
...(r.runId ? { taskRunId: r.runId } : {}),
|
|
1041
1176
|
queuedAt: at,
|
|
1042
1177
|
startedAt: at,
|
|
1043
1178
|
endedAt: at,
|
|
@@ -1112,10 +1247,11 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1112
1247
|
opts.onForwardEvent(e.type === "task_progress" ? { ...e, workflowRunId: runId, workflowAgentLabel: label } : e);
|
|
1113
1248
|
}
|
|
1114
1249
|
: undefined;
|
|
1115
|
-
const baseInternals = { ...(agentOpts.isolation ? { isolation: agentOpts.isolation } : {}), ...(opts.parentCwd !== undefined ? { parentCwd: opts.parentCwd } : {}), ...spawnAttribution, ...(enrichedForward !== undefined ? { onForwardEvent: enrichedForward } : {}), delegationTaskType: "workflow", agentName: label, onWorkspaceResolved: createWorkspaceObserver(rec) };
|
|
1250
|
+
const baseInternals = { ...(agentOpts.isolation ? { isolation: agentOpts.isolation } : {}), ...(opts.parentCwd !== undefined ? { parentCwd: opts.parentCwd } : {}), ...spawnAttribution, ...captureFloorSeatsNow(), ...(enrichedForward !== undefined ? { onForwardEvent: enrichedForward } : {}), delegationTaskType: "workflow", agentName: label, onWorkspaceResolved: createWorkspaceObserver(rec) };
|
|
1116
1251
|
let attempts = 0;
|
|
1117
1252
|
let throttleRetried = false;
|
|
1118
1253
|
let lastAttemptReason;
|
|
1254
|
+
let approvalWaivedAttempts = 0;
|
|
1119
1255
|
for (;;) {
|
|
1120
1256
|
attempts += 1;
|
|
1121
1257
|
const attemptStart = now();
|
|
@@ -1234,11 +1370,19 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1234
1370
|
if (stallFired && attemptResult?.status !== "completed") {
|
|
1235
1371
|
if (attemptResult !== undefined && !finalized)
|
|
1236
1372
|
accumulateStats(attemptResult, true);
|
|
1237
|
-
if (
|
|
1238
|
-
|
|
1373
|
+
if (attemptResult !== undefined && !finalized)
|
|
1374
|
+
setLegRunId(rec, attemptResult);
|
|
1375
|
+
const reported = attemptResult !== undefined && !finalized ? foldLegApprovalReport(rec, attemptResult) : undefined;
|
|
1376
|
+
const pendingApproval = reported !== undefined && approvalWaiverBackstopArmed() ? reported : undefined;
|
|
1377
|
+
if (pendingApproval !== undefined)
|
|
1378
|
+
approvalWaivedAttempts += 1;
|
|
1379
|
+
if (attempts - approvalWaivedAttempts <= agentMaxRetries && !throttleRetried) {
|
|
1380
|
+
lastAttemptReason = pendingApproval !== undefined ? "awaiting_approval" : "stalled";
|
|
1239
1381
|
if (!finalized)
|
|
1240
1382
|
void persist("update");
|
|
1241
|
-
emitRunLog(
|
|
1383
|
+
emitRunLog(pendingApproval !== undefined
|
|
1384
|
+
? `[approval] agent "${label}" made no progress for ${Math.round(stallMs / 1000)}s while ${pendingApproval.askIds.length} approval(s) raised by it were still outstanding — retrying WITHOUT charging the stall budget (${attempts - approvalWaivedAttempts}/${agentMaxRetries} charged)`
|
|
1385
|
+
: `[stall] agent "${label}" stalled (no progress for ${Math.round(stallMs / 1000)}s) — retrying (${attempts - approvalWaivedAttempts}/${agentMaxRetries})`);
|
|
1242
1386
|
continue;
|
|
1243
1387
|
}
|
|
1244
1388
|
throw new WorkflowAgentStalledError(attempts, stallMs, attemptResult);
|
|
@@ -1257,6 +1401,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1257
1401
|
lastAttemptReason = "throttled";
|
|
1258
1402
|
emitRunLog(`[${label}] throttled response (${(result.result ?? "").trim().length} chars in ${Math.round(durationMs / 1000)}s) — sleeping ${Math.round(throttleBackoffMs / 1000)}s before retry`);
|
|
1259
1403
|
if (!finalized) {
|
|
1404
|
+
setLegRunId(rec, result);
|
|
1260
1405
|
accumulateStats(result, true);
|
|
1261
1406
|
void persist("update");
|
|
1262
1407
|
}
|
|
@@ -1291,10 +1436,13 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1291
1436
|
rec.status = "failed";
|
|
1292
1437
|
rec.endedAt = now();
|
|
1293
1438
|
const salvaged = err instanceof WorkflowAgentStalledError ? err.lastResult : undefined;
|
|
1439
|
+
if (salvaged?.runId === undefined)
|
|
1440
|
+
delete rec.taskRunId;
|
|
1294
1441
|
if (salvaged !== undefined) {
|
|
1295
1442
|
rec.taskStatus = salvaged.status;
|
|
1296
1443
|
if (salvaged.sessionId)
|
|
1297
1444
|
rec.sessionId = salvaged.sessionId;
|
|
1445
|
+
setLegRunId(rec, salvaged);
|
|
1298
1446
|
if (salvaged.errorCode !== undefined)
|
|
1299
1447
|
rec.errorCode = salvaged.errorCode;
|
|
1300
1448
|
if (salvaged.errorMessage !== undefined && salvaged.errorMessage !== "")
|
|
@@ -1418,6 +1566,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1418
1566
|
...(agentOpts.isolation ? { isolation: agentOpts.isolation } : {}),
|
|
1419
1567
|
...(opts.parentCwd !== undefined ? { parentCwd: opts.parentCwd } : {}),
|
|
1420
1568
|
...spawnAttribution,
|
|
1569
|
+
...captureFloorSeatsNow(),
|
|
1421
1570
|
...(enrichedForwardS !== undefined ? { onForwardEvent: enrichedForwardS } : {}),
|
|
1422
1571
|
delegationTaskType: "workflow",
|
|
1423
1572
|
agentName: label,
|
|
@@ -1519,31 +1668,31 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1519
1668
|
return { runId, label, callKey, steer, result: () => completion };
|
|
1520
1669
|
},
|
|
1521
1670
|
async parallel(thunks, fanOutOpts) {
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
}
|
|
1671
|
+
const list = snapshotFanOutList("parallel", "the thunk list", thunks);
|
|
1672
|
+
assertFanOutCallables("parallel", "item", list);
|
|
1525
1673
|
const errorsOut = fanOutOpts?.errors;
|
|
1526
|
-
const settled = await Promise.all(
|
|
1674
|
+
const settled = await Promise.all(list.map((t, i) => Promise.resolve()
|
|
1527
1675
|
.then(t)
|
|
1528
1676
|
.then((v) => ({ ok: true, v }), (e) => ({ ok: false, e, i }))));
|
|
1529
1677
|
return foldFanOutSettled(settled, "parallel", errorsOut, emitRunLog);
|
|
1530
1678
|
},
|
|
1531
1679
|
async pipeline(items, ...stagesAndOpts) {
|
|
1532
|
-
|
|
1533
|
-
throw new Error(`pipeline: too many items (${items.length} > ${MAX_WORKFLOW_ITEMS})`);
|
|
1534
|
-
}
|
|
1680
|
+
const itemList = snapshotFanOutList("pipeline", "the item list", items);
|
|
1535
1681
|
for (let i = 0; i < stagesAndOpts.length - 1; i++) {
|
|
1536
1682
|
if (typeof stagesAndOpts[i] !== "function") {
|
|
1537
|
-
throw new
|
|
1683
|
+
throw new WorkflowScriptError(`pipeline: fan-out options must be the last argument (non-function argument at stage position ${i})`);
|
|
1538
1684
|
}
|
|
1539
1685
|
}
|
|
1540
1686
|
const trailing = stagesAndOpts.length > 0 ? stagesAndOpts[stagesAndOpts.length - 1] : undefined;
|
|
1687
|
+
if (trailing !== undefined && typeof trailing !== "function")
|
|
1688
|
+
assertFanOutOptionsShape(trailing, stagesAndOpts.length - 1);
|
|
1541
1689
|
const fanOutOpts = trailing !== undefined && typeof trailing !== "function" ? trailing : undefined;
|
|
1542
1690
|
const stages = (fanOutOpts !== undefined ? stagesAndOpts.slice(0, -1) : stagesAndOpts);
|
|
1691
|
+
assertFanOutCallables("pipeline", "stage", stages);
|
|
1543
1692
|
const errorsOut = fanOutOpts?.errors;
|
|
1544
1693
|
noteDivergence(run.agents.length, "ctx.pipeline ordinals are latency-dependent, so its calls always run live on a resume");
|
|
1545
1694
|
diverged = true;
|
|
1546
|
-
const settled = await Promise.all(
|
|
1695
|
+
const settled = await Promise.all(itemList.map((item, index) => stages
|
|
1547
1696
|
.reduce((acc, stage) => acc.then((prev) => stage(prev, item, index)), Promise.resolve(item))
|
|
1548
1697
|
.then((v) => ({ ok: true, v }), (e) => ({ ok: false, e, i: index }))));
|
|
1549
1698
|
return foldFanOutSettled(settled, "pipeline", errorsOut, emitRunLog);
|
|
@@ -8,7 +8,7 @@ export const EVENT_PROMPT_REGISTRY = new Map([
|
|
|
8
8
|
{ kind: "instructions_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", maxBytes: 512, defaultPolicy: "always", rendererRef: "turn-attachments.ts#collectInstructionsChange" },
|
|
9
9
|
{ kind: "workflow_size_guideline_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "runtask.ts#workflowSizeGuidelineChangeNotice" },
|
|
10
10
|
{ kind: "budget_usd", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderBudgetUsd" },
|
|
11
|
-
{ kind: "total_tokens_reminder", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "
|
|
11
|
+
{ kind: "total_tokens_reminder", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderTotalTokensReminder" },
|
|
12
12
|
{ kind: "background_tasks", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderBackgroundTasks" },
|
|
13
13
|
{ kind: "tools_delta", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderToolsDelta" },
|
|
14
14
|
{ kind: "agent_listing", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderAgentListingDelta" },
|
|
@@ -12,7 +12,7 @@ import type { AgentTool } from "../internal/harness-types.js";
|
|
|
12
12
|
*
|
|
13
13
|
* Disposition against the CURRENT base (220 corpus, `../cc-decoded/pretty220.js`): the whole
|
|
14
14
|
* `# Output efficiency` section is GONE upstream. Its surviving descendant is one bullet of the
|
|
15
|
-
* `# Tone and style` group — `vMy` @596730-596738, item @596733: "Your responses should be short and
|
|
15
|
+
* `# Tone and style` group — `vMy` @596730-596738, item @596733 (cli250.js:44501): "Your responses should be short and
|
|
16
16
|
* concise." sema keeps the sharper 88 formulation deliberately (the bare "short and concise" is the
|
|
17
17
|
* instruction this block exists to beat), so this is an ACTIVE divergence, not stale porting.
|
|
18
18
|
*/
|
|
@@ -57,7 +57,7 @@ export declare const DEFAULT_SYSTEM_PROMPT = "You are a capable AI agent that ac
|
|
|
57
57
|
export declare const SUBAGENT_PROMPT = "You are a sub-agent launched by another agent to work on a delegated task. Given the caller's message, you should use the tools available to complete the task. Complete the task fully\u2014don't gold-plate, but don't leave it half-done. When you complete the task, respond with a concise report covering what was done and any key findings \u2014 the caller will relay this to the user, so it only needs the essentials.\n\nYour strengths:\n- Searching for code, configurations, and patterns across large codebases\n- Analyzing multiple files to understand system architecture\n- Investigating complex questions that require exploring many files\n- Performing multi-step research tasks\n\nGuidelines:\n- For file searches: search broadly when you don't know where something lives. Read the file directly when you know the specific file path.\n- For analysis: Start broad and narrow down. Use multiple search strategies if the first doesn't yield results.\n- Be thorough: Check multiple locations, consider different naming conventions, look for related files.\n- NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one.\n- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested.\n- You are already the dedicated agent for this task. Do the work directly \u2014 do not re-delegate your entire assignment to another single subagent.";
|
|
58
58
|
/**
|
|
59
59
|
* RB-326 (CC 2.1.220 `Von` @597010, the notes-assembler's `Notes:` element (@597011-597016)) — the delegated child's
|
|
60
|
-
* DELIVERY contract: absolute paths in the final response (@597013) and no report-file deliverable
|
|
60
|
+
* DELIVERY contract: absolute paths in the final response (@597013 (cli250.js:44539)) and no report-file deliverable
|
|
61
61
|
* (@597016). Both are byte-adapted from `Von`'s array; the CC-harness-specific notes in the same block
|
|
62
62
|
* (cwd reset between bash calls / no emoji / no colon before tool calls) stay intentionally UNCLAIMED
|
|
63
63
|
* (§6.3 — don't claim harness behavior sema doesn't have).
|
|
@@ -130,7 +130,7 @@ export declare const NO_PERSISTENT_MEMORY_NOTICE = "# Memory\n\nYou have no pers
|
|
|
130
130
|
/**
|
|
131
131
|
* Security boundary (design/64 §6.2 B — CC's `cyberRiskInstruction.ts`, Safeguards-owned, verbatim).
|
|
132
132
|
* Always injected: our base prompts only say "don't introduce vulns" (write secure code); this is the
|
|
133
|
-
* orthogonal **refuse-
|
|
133
|
+
* orthogonal **refuse-harmful-use** boundary that distinguishes authorized security work from abuse.
|
|
134
134
|
* STABLE / cacheable; safety blocks are never feature-gated.
|
|
135
135
|
*/
|
|
136
136
|
export declare const CYBER_RISK = "IMPORTANT: Assist with authorized security testing, defensive security, CTF challenges, and educational contexts. Refuse requests for destructive techniques, DoS attacks, mass targeting, supply chain compromise, or detection evasion for malicious purposes. Dual-use security tools (C2 frameworks, credential testing, exploit development) require clear authorization context: pentesting engagements, CTF competitions, security research, or defensive use cases.";
|
|
@@ -178,7 +178,7 @@ export declare const EXECUTION_ENVIRONMENT_OPEN_READS: string;
|
|
|
178
178
|
*/
|
|
179
179
|
export declare const WORKTREE_NOTICE = "# Isolated worktree\nThis task runs in its own isolated git worktree \u2014 a separate working copy whose root is the working directory shown in # Environment, NOT the repository's main checkout. Any absolute path you were given that points at the main checkout (or another worktree) refers to a DIFFERENT copy; translate it to the same relative path under this worktree's root before reading or writing, and operate only within this worktree. A file's content here may differ from the main checkout, so re-read a file in this worktree before editing it rather than assuming an earlier or external view is current.";
|
|
180
180
|
/**
|
|
181
|
-
* RB-314 — CC 2.1.220 `atp` (@597127) VERBATIM. Rides the variable `# Environment` tail (see
|
|
181
|
+
* RB-314 — CC 2.1.220 `atp` (@597127 (cli250.js:44534)) VERBATIM. Rides the variable `# Environment` tail (see
|
|
182
182
|
* {@link buildEnvironmentContext}), which is exactly where 220 emits it: both env-block assemblers
|
|
183
183
|
* (@596927 `IMy`, @596976 `OMy`) push `worktree ? atp : null` directly after the isolated-copy
|
|
184
184
|
* directive. Deliberately NOT folded into {@link WORKTREE_NOTICE}: that block is composed only for
|
|
@@ -191,7 +191,7 @@ export declare const WORKTREE_NOTICE = "# Isolated worktree\nThis task runs in i
|
|
|
191
191
|
*/
|
|
192
192
|
export declare const WORKTREE_STASH_WARNING: string;
|
|
193
193
|
/**
|
|
194
|
-
* RB-204 (form-one audit, CC 2.1.220 `Von` @597021 (the string element inside `Von` @597010), the assembler's first unconditional array
|
|
194
|
+
* RB-204 (form-one audit, CC 2.1.220 `Von` @597021 (cli250.js:44542) (the string element inside `Von` @597010), the assembler's first unconditional array
|
|
195
195
|
* element — verified present at both non-fork subagent call sites, @407444-407451 and @466602-466618,
|
|
196
196
|
* and ALSO applied over a custom/marketplace agent's own `getSystemPrompt()` output, not just the
|
|
197
197
|
* built-in persona): composed (via {@link PromptRuntimeFacts.isSubagent}) only for a delegated,
|
|
@@ -251,7 +251,7 @@ export declare const PROJECT_CONTEXT_FRAMING = "# Project context\nThe `<user_me
|
|
|
251
251
|
* relation to the specific tool results or user messages in which they appear."
|
|
252
252
|
* - LEAN (`wMy` @596743, heading **`# Harness`**) → "`<system-reminder>` tags in messages and tool
|
|
253
253
|
* results are injected by the harness, not the user."
|
|
254
|
-
* - THIRD ARM (`itp`'s `otp(model)` short-circuit → `gMy` @597111): "The system may send updates,
|
|
254
|
+
* - THIRD ARM (`itp`'s `otp(model)` short-circuit → `gMy` @597111 (cli250.js:44459)): "The system may send updates,
|
|
255
255
|
* reminders, or modifications to rules via mid-conversation system turns. These are
|
|
256
256
|
* system-controlled, unlike function results." sema has NO counterpart and does not need one — the
|
|
257
257
|
* arm is selected by a per-model latch (`otp` @597208) over CC's own model registry, which a BYOM
|
|
@@ -407,7 +407,7 @@ export declare const GIT_SNAPSHOT_CC_PREAMBLE = "This is the git status at the s
|
|
|
407
407
|
* `# Environment` system-prompt section — the template body itself stays CC-verbatim.
|
|
408
408
|
*
|
|
409
409
|
* Sanitization (deliberate CC deviation — CC injects raw): status/log/branch/user are REPO-controlled
|
|
410
|
-
* text (filenames, commit subjects,
|
|
410
|
+
* text (filenames, commit subjects, an untrusted clone's config) landing in the TRUSTED prompt region →
|
|
411
411
|
* multi-line fields are tag-neutralized (`sanitizeUntrustedText`), single-line fields additionally
|
|
412
412
|
* fold newlines (`inlineUntrusted`), same as the rest of the `# Environment` git facts.
|
|
413
413
|
*/
|