@sema-agent/core 3.0.0 → 5.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 +2382 -0
- package/dist/agents/cascade.d.ts +3 -1
- package/dist/agents/cascade.js +31 -32
- package/dist/agents/cumulative-stats.d.ts +29 -0
- package/dist/agents/cumulative-stats.js +29 -0
- package/dist/agents/observer.d.ts +4 -0
- package/dist/agents/observer.js +11 -10
- package/dist/agents/repair-loop.d.ts +2 -0
- package/dist/agents/repair-loop.js +48 -24
- package/dist/agents/retain-ledger.d.ts +2 -0
- package/dist/agents/retain-ledger.js +6 -5
- package/dist/agents/roster-store.d.ts +1 -0
- package/dist/agents/roster-store.js +3 -5
- package/dist/agents/send-message-tool.d.ts +1 -0
- package/dist/agents/send-message-tool.js +2 -0
- package/dist/agents/subagent.d.ts +3 -1
- package/dist/agents/subagent.js +79 -94
- package/dist/agents/teacher.d.ts +1 -9
- package/dist/agents/teacher.js +21 -24
- package/dist/agents/tool-filter.js +6 -7
- package/dist/agents/verify.d.ts +1 -0
- package/dist/agents/verify.js +15 -14
- package/dist/brain/anthropic.js +24 -21
- package/dist/brain/openai.js +24 -21
- package/dist/brain/stream-engine.js +5 -2
- package/dist/brain/stream-shared.d.ts +1 -0
- package/dist/brain/stream-shared.js +14 -0
- package/dist/brain/terminal-cause.d.ts +4 -0
- package/dist/brain/terminal-cause.js +12 -0
- package/dist/brain/tool-call-id.d.ts +1 -0
- package/dist/brain/tool-call-id.js +3 -0
- package/dist/brain/tool-call-repair.js +2 -1
- package/dist/core/arg-summary.d.ts +21 -1
- package/dist/core/arg-summary.js +61 -14
- package/dist/core/auto-compaction.d.ts +1 -0
- package/dist/core/auto-compaction.js +16 -25
- package/dist/core/background-agent-store.d.ts +22 -22
- package/dist/core/background-agent-store.js +19 -23
- package/dist/core/checkpoint-store.d.ts +6 -13
- package/dist/core/checkpoint-store.js +11 -5
- package/dist/core/file-snapshot-store.d.ts +8 -0
- package/dist/core/file-snapshot-store.js +4 -3
- package/dist/core/fs-write-gate-policy.js +2 -3
- package/dist/core/hooks.d.ts +4 -1
- package/dist/core/hooks.js +8 -18
- package/dist/core/lsp.js +4 -3
- package/dist/core/mailbox-store.d.ts +7 -10
- package/dist/core/mcp.d.ts +7 -10
- package/dist/core/mcp.js +7 -9
- package/dist/core/memory-engine/engine.d.ts +0 -1
- package/dist/core/memory-engine/engine.js +24 -34
- package/dist/core/memory-engine/file-backend.d.ts +1 -2
- package/dist/core/memory-engine/file-backend.js +25 -36
- package/dist/core/memory-engine/layout.d.ts +8 -0
- package/dist/core/memory-engine/layout.js +60 -4
- package/dist/core/memory-engine/scope-contract.js +9 -3
- package/dist/core/memory-engine/types.d.ts +1 -1
- package/dist/core/permission-rules.js +2 -3
- package/dist/core/runner/active-skill-scope.d.ts +0 -1
- package/dist/core/runner/active-skill-scope.js +2 -17
- package/dist/core/runner/assemble-result.d.ts +2 -7
- package/dist/core/runner/assemble-result.js +3 -4
- package/dist/core/runner/compaction-call-options.d.ts +7 -0
- package/dist/core/runner/compaction-call-options.js +30 -0
- package/dist/core/runner/prepare-task.d.ts +6 -23
- package/dist/core/runner/prepare-task.js +36 -61
- package/dist/core/runner/runtask.d.ts +1 -0
- package/dist/core/runner/runtask.js +84 -172
- package/dist/core/runner/session-rule-policy.js +7 -5
- package/dist/core/runner/teardown-bounded.d.ts +7 -0
- package/dist/core/runner/teardown-bounded.js +36 -0
- package/dist/core/runner/tool-disclosure.d.ts +2 -5
- package/dist/core/runner/turn-attachments.d.ts +5 -15
- package/dist/core/runner/turn-attachments.js +1 -1
- package/dist/core/safe-notify.d.ts +17 -0
- package/dist/core/safe-notify.js +59 -0
- package/dist/core/sensitive-path-policy.js +4 -4
- package/dist/core/session-reconcile.js +1 -2
- package/dist/core/skill-tool-specifier.js +2 -3
- package/dist/core/skills-directory.js +2 -3
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/stub-env.d.ts +2 -6
- package/dist/core/surrogate-safe-slice.d.ts +4 -0
- package/dist/core/surrogate-safe-slice.js +18 -0
- package/dist/core/task-registry-monitor.js +8 -13
- package/dist/core/task-registry-shared.d.ts +23 -1
- package/dist/core/task-registry-shared.js +16 -0
- package/dist/core/task-registry.d.ts +6 -1
- package/dist/core/task-registry.js +52 -87
- package/dist/core/task-tool-shape.d.ts +0 -2
- package/dist/core/task-tool-shape.js +2 -5
- package/dist/core/tool-errors.js +5 -4
- package/dist/core/tool-name-aliases.d.ts +1 -2
- package/dist/core/tool-name-aliases.js +42 -59
- package/dist/core/tool-policy.js +21 -17
- package/dist/core/tool-result-store.d.ts +1 -0
- package/dist/core/tool-result-store.js +17 -1
- package/dist/core/trace.d.ts +9 -9
- package/dist/core/types.d.ts +15 -12
- package/dist/core/untrusted-egress.d.ts +4 -2
- package/dist/core/untrusted-egress.js +28 -14
- package/dist/core/workflow-journal-store.d.ts +9 -20
- package/dist/core/workflow-run-store.d.ts +11 -10
- package/dist/core/workflow-run-store.js +22 -16
- package/dist/engine/compaction/utils.js +4 -2
- package/dist/engine/execution-env/node-execution-env.d.ts +2 -24
- package/dist/engine/execution-env/node-execution-env.js +1 -1
- package/dist/engine/harness/agent-harness.d.ts +1 -0
- package/dist/engine/harness/agent-harness.js +13 -33
- package/dist/engine/harness/types.d.ts +29 -67
- package/dist/engine/llm/types.d.ts +1 -1
- package/dist/engine/loop/agent-loop.js +12 -14
- package/dist/engine/loop/types.d.ts +11 -9
- package/dist/engine/session/memory-repo.d.ts +2 -6
- package/dist/engine/session/session.d.ts +5 -30
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -3
- package/dist/internal/harness-types.d.ts +3 -1
- package/dist/orchestration/run-spec.js +6 -4
- package/dist/orchestration/run-workflow-tool.js +3 -36
- package/dist/orchestration/workflow-governance.js +2 -1
- package/dist/orchestration/workflow.d.ts +4 -11
- package/dist/orchestration/workflow.js +164 -204
- package/dist/prompt-assembly/packs/sema-default.js +1 -3
- package/dist/prompt-assembly/tool-catalog.d.ts +10 -9
- package/dist/prompt-assembly/turn-snapshot.d.ts +2 -5
- package/dist/prompts/default.js +1 -3
- package/dist/prompts/simple-sections.d.ts +0 -1
- package/dist/prompts/simple-sections.js +0 -1
- package/dist/stores/file/background-agent-store.d.ts +3 -12
- package/dist/stores/file/background-agent-store.js +3 -41
- package/dist/stores/file/checkpoint-store.js +6 -6
- package/dist/stores/file/mailbox-store.d.ts +2 -6
- package/dist/stores/file/session-policy-store.js +15 -1
- package/dist/stores/file/session-store.d.ts +2 -6
- package/dist/stores/file/workflow-journal-store.d.ts +3 -11
- package/dist/stores/file/workflow-run-store.d.ts +3 -7
- package/dist/stores/file/workflow-run-store.js +4 -17
- package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -0
- package/dist/tools/fs/bash-readonly-classifier.js +60 -25
- package/dist/tools/fs/fs-bash.js +330 -104
- package/dist/tools/fs/fs-pdf.d.ts +2 -12
- package/dist/tools/fs/fs-shared.js +2 -2
- package/dist/tools/fs/fs-write.js +0 -1
- package/dist/tools/fs/notebook.d.ts +2 -5
- package/dist/tools/fs/safety.d.ts +3 -0
- package/dist/tools/fs/safety.js +43 -14
- package/dist/tools/fs/search.js +5 -5
- package/dist/tools/monitor.d.ts +1 -0
- package/dist/tools/monitor.js +7 -5
- package/dist/tools/worktree.d.ts +2 -7
- package/dist/tools/worktree.js +3 -1
- package/package.json +6 -2
|
@@ -6,6 +6,7 @@ import { uuidv7 } from "../internal/harness.js";
|
|
|
6
6
|
import { builtinAgentDefinitions } from "../agents/builtin-agents.js";
|
|
7
7
|
import { GENERAL_PURPOSE_SUBAGENT_TYPE } from "../agents/subagent.js";
|
|
8
8
|
import { combinePolicies, createAllowDenyPolicy } from "../core/tool-policy.js";
|
|
9
|
+
import { createSafeNotifier } from "../core/safe-notify.js";
|
|
9
10
|
import { callKeyOrdinal, oversizeJournalResult, journalOversizeTombstone, JOURNAL_OVERSIZE_ERROR_CODE, MAX_JOURNAL_RESULT_BYTES } from "../core/workflow-journal-store.js";
|
|
10
11
|
import { isWorkflowRunActive, closeWorkflowChannel, markWorkflowActive, publishWorkflowEvent } from "./workflow-observe.js";
|
|
11
12
|
import { isDurablePause, mapNestedSuspend } from "../agents/suspend-guard.js";
|
|
@@ -66,8 +67,9 @@ export function applyWorkflowAgentType(spec, agentType, registry) {
|
|
|
66
67
|
out.model = def.model;
|
|
67
68
|
if (out.thinking === undefined && def.thinking !== undefined)
|
|
68
69
|
out.thinking = def.thinking;
|
|
69
|
-
if (out.limits?.maxTurns === undefined && def.maxTurns
|
|
70
|
+
if (out.limits?.maxTurns === undefined && typeof def.maxTurns === "number" && Number.isFinite(def.maxTurns) && def.maxTurns > 0) {
|
|
70
71
|
out.limits = { ...out.limits, maxTurns: def.maxTurns };
|
|
72
|
+
}
|
|
71
73
|
if (out.skills === undefined && def.skills !== undefined)
|
|
72
74
|
out.skills = def.skills;
|
|
73
75
|
if (out.memory === undefined && def.memory !== undefined)
|
|
@@ -124,6 +126,27 @@ function rethrowIfMaxAgents(e) {
|
|
|
124
126
|
throw e;
|
|
125
127
|
return null;
|
|
126
128
|
}
|
|
129
|
+
function foldFanOutSettled(settled, lane, errorsOut, emitRunLog) {
|
|
130
|
+
let dropped = 0;
|
|
131
|
+
const droppedSlots = [];
|
|
132
|
+
const results = settled.map((s) => {
|
|
133
|
+
if (s.ok)
|
|
134
|
+
return s.v;
|
|
135
|
+
if (s.e instanceof WorkflowBudgetExceededError) {
|
|
136
|
+
dropped++;
|
|
137
|
+
droppedSlots.push(s.i);
|
|
138
|
+
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
rethrowIfMaxAgents(s.e);
|
|
142
|
+
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
143
|
+
emitRunLog(`${lane}[${s.i}] failed: ${boundedRedactedSummary(s.e instanceof Error ? s.e.message : String(s.e), 300)}`);
|
|
144
|
+
return null;
|
|
145
|
+
});
|
|
146
|
+
if (dropped > 0)
|
|
147
|
+
emitRunLog(`${lane}: ${dropped} ${dropped === 1 ? "slot" : "slots"} dropped — token budget exceeded (${dropped === 1 ? "slot" : "slots"} ${droppedSlots.join(", ")})`);
|
|
148
|
+
return results;
|
|
149
|
+
}
|
|
127
150
|
function workflowFanOutSlotError(index, e) {
|
|
128
151
|
const code = e?.code;
|
|
129
152
|
const kind = typeof code === "string" && code.length > 0 ? code : e instanceof Error ? e.name : "Error";
|
|
@@ -191,6 +214,14 @@ function normalizeConcurrency(c) {
|
|
|
191
214
|
}
|
|
192
215
|
return Math.floor(c);
|
|
193
216
|
}
|
|
217
|
+
function normalizeWorkflowHardCap(name, v) {
|
|
218
|
+
if (v === undefined)
|
|
219
|
+
return undefined;
|
|
220
|
+
if (!Number.isFinite(v) || v < 0) {
|
|
221
|
+
throw new Error(`runWorkflow: ${name} must be a finite number ≥ 0 (got ${v})`);
|
|
222
|
+
}
|
|
223
|
+
return v;
|
|
224
|
+
}
|
|
194
225
|
function createSemaphore(max) {
|
|
195
226
|
let active = 0;
|
|
196
227
|
const waiters = [];
|
|
@@ -273,8 +304,9 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
273
304
|
const concurrency = normalizeConcurrency(opts.concurrency);
|
|
274
305
|
const agentRegistry = workflowAgentRegistry(opts);
|
|
275
306
|
const store = opts.store;
|
|
276
|
-
const maxAgents = opts.maxAgents;
|
|
277
|
-
const maxLogChars = opts.maxLogChars;
|
|
307
|
+
const maxAgents = normalizeWorkflowHardCap("maxAgents", opts.maxAgents);
|
|
308
|
+
const maxLogChars = normalizeWorkflowHardCap("maxLogChars", opts.maxLogChars);
|
|
309
|
+
const maxResultChars = normalizeWorkflowHardCap("maxResultChars", opts.maxResultChars);
|
|
278
310
|
const stallMs = opts.stallMs ?? WORKFLOW_AGENT_STALL_MS;
|
|
279
311
|
const agentMaxRetries = opts.agentMaxRetries ?? WORKFLOW_AGENT_MAX_RETRIES;
|
|
280
312
|
const throttleBackoffMs = opts.throttleBackoffMs ?? WORKFLOW_AGENT_THROTTLE_BACKOFF_MS;
|
|
@@ -289,13 +321,10 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
289
321
|
const workflowSignal = signalSources.length === 1 ? signalSources[0] : AbortSignal.any(signalSources);
|
|
290
322
|
let timeoutTimer;
|
|
291
323
|
let storeRev = 0;
|
|
324
|
+
const notifier = createSafeNotifier(opts.onNotifyError !== undefined ? { onError: opts.onNotifyError } : undefined);
|
|
292
325
|
const emit = (e) => {
|
|
293
326
|
publishWorkflowEvent(runId, e);
|
|
294
|
-
|
|
295
|
-
opts.onEvent?.(e);
|
|
296
|
-
}
|
|
297
|
-
catch {
|
|
298
|
-
}
|
|
327
|
+
notifier.notify(() => opts.onEvent?.(e), "workflow.onEvent");
|
|
299
328
|
};
|
|
300
329
|
let persistTail = Promise.resolve();
|
|
301
330
|
const persist = (mode) => {
|
|
@@ -445,12 +474,9 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
445
474
|
};
|
|
446
475
|
const bceSink = opts.onBackgroundChildEvent;
|
|
447
476
|
const bceEmit = (e) => {
|
|
448
|
-
|
|
449
|
-
bceSink?.(e);
|
|
450
|
-
}
|
|
451
|
-
catch {
|
|
452
|
-
}
|
|
477
|
+
notifier.notify(() => bceSink?.(e), "workflow.onBackgroundChildEvent");
|
|
453
478
|
};
|
|
479
|
+
const bceParentToolCall = opts.parentToolCallId !== undefined ? { parentToolCallId: opts.parentToolCallId } : {};
|
|
454
480
|
const waIdOf = (callKey) => `wa${createHash("sha256").update(`${runId}:${callKey}`).digest("hex").slice(0, 16)}`;
|
|
455
481
|
const bceLive = new Map();
|
|
456
482
|
const bceSpawn = (callKey, label, agentType, replayed, sessionId) => {
|
|
@@ -463,6 +489,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
463
489
|
taskId: id,
|
|
464
490
|
sessionScoped: false,
|
|
465
491
|
owner: runId,
|
|
492
|
+
...bceParentToolCall,
|
|
466
493
|
...(sessionId !== undefined ? { sessionId, transcriptId: sessionId } : {}),
|
|
467
494
|
...(scope !== undefined ? { scope } : {}),
|
|
468
495
|
description: replayed ? `${label} (replayed)` : label,
|
|
@@ -494,6 +521,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
494
521
|
taskId: id,
|
|
495
522
|
sessionScoped: false,
|
|
496
523
|
owner: runId,
|
|
524
|
+
...bceParentToolCall,
|
|
497
525
|
workflowRunId: runId,
|
|
498
526
|
...(scope !== undefined ? { scope } : {}),
|
|
499
527
|
...(row.agentType !== undefined ? { agentType: row.agentType } : { agentType: "workflow-agent" }),
|
|
@@ -518,6 +546,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
518
546
|
taskId: id,
|
|
519
547
|
sessionScoped: false,
|
|
520
548
|
owner: runId,
|
|
549
|
+
...bceParentToolCall,
|
|
521
550
|
workflowRunId: runId,
|
|
522
551
|
...(scope !== undefined ? { scope } : {}),
|
|
523
552
|
...(coord !== undefined ? { sessionId: coord, transcriptId: coord } : {}),
|
|
@@ -574,6 +603,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
574
603
|
});
|
|
575
604
|
};
|
|
576
605
|
let journalTail = Promise.resolve();
|
|
606
|
+
const JOURNAL_DRAIN_MAX_MS = 5_000;
|
|
577
607
|
const journalAppend = async (callKey, result, label) => {
|
|
578
608
|
const dbg = typeof process !== "undefined" && process.env?.SEMA_DEBUG_WORKFLOW_JOURNAL === "1";
|
|
579
609
|
if (!journalStore) {
|
|
@@ -712,6 +742,94 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
712
742
|
rec.output = output;
|
|
713
743
|
return output;
|
|
714
744
|
};
|
|
745
|
+
const assertAgentSpawnAllowed = (lane, spec, agentOpts) => {
|
|
746
|
+
if (finalized) {
|
|
747
|
+
throw new Error(`workflow run already finalized — ${lane} cannot be called after the script returned`);
|
|
748
|
+
}
|
|
749
|
+
const effectiveSignal = spec.signal ?? agentOpts.signal ?? workflowSignal;
|
|
750
|
+
if (effectiveSignal?.aborted)
|
|
751
|
+
throw new Error("workflow aborted");
|
|
752
|
+
if (maxAgents !== undefined && run.agents.length >= maxAgents) {
|
|
753
|
+
throw new WorkflowMaxAgentsError(maxAgents);
|
|
754
|
+
}
|
|
755
|
+
return effectiveSignal;
|
|
756
|
+
};
|
|
757
|
+
const prepareAgentCall = (spec, agentOpts) => {
|
|
758
|
+
if (agentOpts.schema) {
|
|
759
|
+
const compiled = compileOutputSchema(agentOpts.schema);
|
|
760
|
+
if ("error" in compiled)
|
|
761
|
+
throw new TypeError(`agent({schema}) received an invalid JSON Schema: ${compiled.error}`);
|
|
762
|
+
}
|
|
763
|
+
assertSupportedAgentIsolation(agentOpts.isolation);
|
|
764
|
+
const label = agentOpts.label ?? `agent-${run.agents.length + 1}`;
|
|
765
|
+
const phase = agentOpts.phase ?? currentPhase?.title;
|
|
766
|
+
const phaseInstance = resolveAgentPhase(agentOpts.phase);
|
|
767
|
+
const groupId = currentGroup;
|
|
768
|
+
const typeDefModel = agentOpts.agentType !== undefined ? agentRegistry.find((d) => d.name === agentOpts.agentType)?.model : undefined;
|
|
769
|
+
const inheritedModelSnap = spec.model === undefined && typeDefModel === undefined ? opts.defaultModel?.() : undefined;
|
|
770
|
+
const specForIdentity = inheritedModelSnap !== undefined ? { ...spec, model: inheritedModelSnap } : spec;
|
|
771
|
+
const callKey = workflowAgentCallKey(run.agents.length, specForIdentity, agentOpts);
|
|
772
|
+
const prompt = boundedRedactedSummary(spec.systemPrompt ? `${spec.systemPrompt}\n\n${spec.objective}` : spec.objective, MAX_TRANSCRIPT_CHARS);
|
|
773
|
+
const model = workflowModelLabel(specForIdentity);
|
|
774
|
+
return { label, phase, phaseInstance, groupId, inheritedModelSnap, callKey, prompt, model };
|
|
775
|
+
};
|
|
776
|
+
const createUsageBeat = (rec) => {
|
|
777
|
+
let beatTokens = 0;
|
|
778
|
+
let beatTurns = 0;
|
|
779
|
+
let beatCostMicroUsd = 0;
|
|
780
|
+
const rollbackUsageBeat = () => {
|
|
781
|
+
if (beatTurns === 0 && beatTokens === 0 && beatCostMicroUsd === 0)
|
|
782
|
+
return false;
|
|
783
|
+
run.stats.tokens -= beatTokens;
|
|
784
|
+
run.stats.turns -= beatTurns;
|
|
785
|
+
run.stats.costMicroUsd -= beatCostMicroUsd;
|
|
786
|
+
beatTokens = 0;
|
|
787
|
+
beatTurns = 0;
|
|
788
|
+
beatCostMicroUsd = 0;
|
|
789
|
+
return true;
|
|
790
|
+
};
|
|
791
|
+
const onTurnEndUsage = (usage) => {
|
|
792
|
+
if (finalized)
|
|
793
|
+
return;
|
|
794
|
+
const turnTokens = usage ? usage.totalInputTokens + usage.outputTokens : 0;
|
|
795
|
+
const turnCost = usage?.costMicroUsd ?? 0;
|
|
796
|
+
beatTokens += turnTokens;
|
|
797
|
+
beatTurns += 1;
|
|
798
|
+
beatCostMicroUsd += turnCost;
|
|
799
|
+
run.stats.tokens += turnTokens;
|
|
800
|
+
run.stats.turns += 1;
|
|
801
|
+
run.stats.costMicroUsd += turnCost;
|
|
802
|
+
rec.stats = { tokens: beatTokens, turns: beatTurns, costMicroUsd: beatCostMicroUsd };
|
|
803
|
+
void persist("update");
|
|
804
|
+
};
|
|
805
|
+
return { onTurnEndUsage, rollbackUsageBeat };
|
|
806
|
+
};
|
|
807
|
+
const settleAgentResult = async (rec, result, activityTail, agentOpts, journal) => {
|
|
808
|
+
const s = result.stats;
|
|
809
|
+
accumulateStats(result, true);
|
|
810
|
+
rec.status = result.status === "completed" ? "completed" : "failed";
|
|
811
|
+
rec.taskStatus = result.status;
|
|
812
|
+
if (result.sessionId)
|
|
813
|
+
rec.sessionId = result.sessionId;
|
|
814
|
+
rec.endedAt = now();
|
|
815
|
+
rec.stats = { tokens: s.tokens ?? 0, turns: s.turns ?? 0, costMicroUsd: s.costMicroUsd };
|
|
816
|
+
const output = settleAgentError(rec, result, rec.label, boundedRedactedSummary(result.structuredOutput ?? result.result, MAX_TRANSCRIPT_CHARS));
|
|
817
|
+
if (result.stats.toolCalls !== undefined)
|
|
818
|
+
rec.toolCalls = result.stats.toolCalls;
|
|
819
|
+
if (activityTail.length > 0)
|
|
820
|
+
rec.activity = activityTail.slice();
|
|
821
|
+
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 } : {}), ts: rec.endedAt });
|
|
822
|
+
void persist("update");
|
|
823
|
+
bceTerminal(rec.callKey, rec.status === "completed" ? "completed" : "failed", output, result.sessionId || undefined, rec.stats);
|
|
824
|
+
if (journal === "awaited")
|
|
825
|
+
await journalAppend(rec.callKey, result, rec.label);
|
|
826
|
+
else {
|
|
827
|
+
void journalAppend(rec.callKey, result, rec.label).catch(() => undefined);
|
|
828
|
+
}
|
|
829
|
+
if (agentOpts.schema && result.status === "completed" && result.structuredOutput === undefined) {
|
|
830
|
+
throw new WorkflowAgentSchemaError(rec.label, result);
|
|
831
|
+
}
|
|
832
|
+
};
|
|
715
833
|
const ctx = {
|
|
716
834
|
runId,
|
|
717
835
|
budget,
|
|
@@ -720,31 +838,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
720
838
|
emitRunLog(message);
|
|
721
839
|
},
|
|
722
840
|
async agent(spec, agentOpts = {}) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
}
|
|
726
|
-
const effectiveSignal = spec.signal ?? agentOpts.signal ?? workflowSignal;
|
|
727
|
-
if (effectiveSignal?.aborted)
|
|
728
|
-
throw new Error("workflow aborted");
|
|
729
|
-
if (maxAgents !== undefined && run.agents.length >= maxAgents) {
|
|
730
|
-
throw new WorkflowMaxAgentsError(maxAgents);
|
|
731
|
-
}
|
|
732
|
-
if (agentOpts.schema) {
|
|
733
|
-
const compiled = compileOutputSchema(agentOpts.schema);
|
|
734
|
-
if ("error" in compiled)
|
|
735
|
-
throw new TypeError(`agent({schema}) received an invalid JSON Schema: ${compiled.error}`);
|
|
736
|
-
}
|
|
737
|
-
assertSupportedAgentIsolation(agentOpts.isolation);
|
|
738
|
-
const label = agentOpts.label ?? `agent-${run.agents.length + 1}`;
|
|
739
|
-
const phase = agentOpts.phase ?? currentPhase?.title;
|
|
740
|
-
const phaseInstance = resolveAgentPhase(agentOpts.phase);
|
|
741
|
-
const groupId = currentGroup;
|
|
742
|
-
const typeDefModel = agentOpts.agentType !== undefined ? agentRegistry.find((d) => d.name === agentOpts.agentType)?.model : undefined;
|
|
743
|
-
const inheritedModelSnap = spec.model === undefined && typeDefModel === undefined ? opts.defaultModel?.() : undefined;
|
|
744
|
-
const specForIdentity = inheritedModelSnap !== undefined ? { ...spec, model: inheritedModelSnap } : spec;
|
|
745
|
-
const callKey = workflowAgentCallKey(run.agents.length, specForIdentity, agentOpts);
|
|
746
|
-
const prompt = boundedRedactedSummary(spec.systemPrompt ? `${spec.systemPrompt}\n\n${spec.objective}` : spec.objective, MAX_TRANSCRIPT_CHARS);
|
|
747
|
-
const model = workflowModelLabel(specForIdentity);
|
|
841
|
+
const effectiveSignal = assertAgentSpawnAllowed("ctx.agent", spec, agentOpts);
|
|
842
|
+
const { label, phase, phaseInstance, groupId, inheritedModelSnap, callKey, prompt, model } = prepareAgentCall(spec, agentOpts);
|
|
748
843
|
if (opts.resumeFromRunId !== undefined && !diverged) {
|
|
749
844
|
const cached = replayByOrdinal[run.agents.length];
|
|
750
845
|
if (cached && cached.callKey === callKey && cached.result.status === "completed") {
|
|
@@ -913,35 +1008,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
913
1008
|
lastProgressRearm = t;
|
|
914
1009
|
armWatchdog();
|
|
915
1010
|
};
|
|
916
|
-
|
|
917
|
-
let beatTurns = 0;
|
|
918
|
-
let beatCostMicroUsd = 0;
|
|
919
|
-
const rollbackUsageBeat = () => {
|
|
920
|
-
if (beatTurns === 0 && beatTokens === 0 && beatCostMicroUsd === 0)
|
|
921
|
-
return false;
|
|
922
|
-
run.stats.tokens -= beatTokens;
|
|
923
|
-
run.stats.turns -= beatTurns;
|
|
924
|
-
run.stats.costMicroUsd -= beatCostMicroUsd;
|
|
925
|
-
beatTokens = 0;
|
|
926
|
-
beatTurns = 0;
|
|
927
|
-
beatCostMicroUsd = 0;
|
|
928
|
-
return true;
|
|
929
|
-
};
|
|
1011
|
+
const { onTurnEndUsage, rollbackUsageBeat } = createUsageBeat(rec);
|
|
930
1012
|
activeUsageBeats.add(rollbackUsageBeat);
|
|
931
|
-
const onTurnEndUsage = (usage) => {
|
|
932
|
-
if (finalized)
|
|
933
|
-
return;
|
|
934
|
-
const turnTokens = usage ? usage.totalInputTokens + usage.outputTokens : 0;
|
|
935
|
-
const turnCost = usage?.costMicroUsd ?? 0;
|
|
936
|
-
beatTokens += turnTokens;
|
|
937
|
-
beatTurns += 1;
|
|
938
|
-
beatCostMicroUsd += turnCost;
|
|
939
|
-
run.stats.tokens += turnTokens;
|
|
940
|
-
run.stats.turns += 1;
|
|
941
|
-
run.stats.costMicroUsd += turnCost;
|
|
942
|
-
rec.stats = { tokens: beatTokens, turns: beatTurns, costMicroUsd: beatCostMicroUsd };
|
|
943
|
-
void persist("update");
|
|
944
|
-
};
|
|
945
1013
|
try {
|
|
946
1014
|
attemptResult = await workflowDepthStore.run({ depth: depth + 1 }, async () => {
|
|
947
1015
|
if (typeof runner.runTaskStream !== "function") {
|
|
@@ -963,8 +1031,11 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
963
1031
|
attemptError = err;
|
|
964
1032
|
}
|
|
965
1033
|
finally {
|
|
966
|
-
rollbackUsageBeat();
|
|
1034
|
+
const attemptHadSpend = rollbackUsageBeat();
|
|
967
1035
|
activeUsageBeats.delete(rollbackUsageBeat);
|
|
1036
|
+
if (attemptError !== undefined && attemptHadSpend && !finalized && rec.stats !== undefined) {
|
|
1037
|
+
accumulateStats({ stats: rec.stats }, true);
|
|
1038
|
+
}
|
|
968
1039
|
disarmWatchdog();
|
|
969
1040
|
effectiveSignal?.removeEventListener("abort", onCallerAbort);
|
|
970
1041
|
}
|
|
@@ -1073,57 +1144,15 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1073
1144
|
if (isDurablePause(result.status)) {
|
|
1074
1145
|
result = mapNestedSuspend(result);
|
|
1075
1146
|
}
|
|
1076
|
-
|
|
1077
|
-
accumulateStats(result, true);
|
|
1078
|
-
rec.status = result.status === "completed" ? "completed" : "failed";
|
|
1079
|
-
rec.taskStatus = result.status;
|
|
1080
|
-
if (result.sessionId)
|
|
1081
|
-
rec.sessionId = result.sessionId;
|
|
1082
|
-
rec.endedAt = now();
|
|
1083
|
-
rec.stats = { tokens: s.tokens ?? 0, turns: s.turns ?? 0, costMicroUsd: s.costMicroUsd };
|
|
1084
|
-
const output = settleAgentError(rec, result, label, boundedRedactedSummary(result.structuredOutput ?? result.result, MAX_TRANSCRIPT_CHARS));
|
|
1085
|
-
if (result.stats.toolCalls !== undefined)
|
|
1086
|
-
rec.toolCalls = result.stats.toolCalls;
|
|
1087
|
-
if (activityTail.length > 0)
|
|
1088
|
-
rec.activity = activityTail.slice();
|
|
1089
|
-
emit({ type: "agent_end", runId, label, phase, ...(groupId !== undefined ? { groupId } : {}), status: rec.status, output, ...(rec.errorCode !== undefined ? { errorCode: rec.errorCode } : {}), ...(result.stats.toolCalls !== undefined ? { toolCalls: result.stats.toolCalls } : {}), ts: rec.endedAt });
|
|
1090
|
-
void persist("update");
|
|
1091
|
-
bceTerminal(callKey, rec.status === "completed" ? "completed" : "failed", output, result.sessionId || undefined, rec.stats);
|
|
1092
|
-
await journalAppend(callKey, result, label);
|
|
1093
|
-
if (agentOpts.schema && result.status === "completed" && result.structuredOutput === undefined) {
|
|
1094
|
-
throw new WorkflowAgentSchemaError(label, result);
|
|
1095
|
-
}
|
|
1147
|
+
await settleAgentResult(rec, result, activityTail, agentOpts, "awaited");
|
|
1096
1148
|
return result;
|
|
1097
1149
|
},
|
|
1098
1150
|
async agentStream(spec, agentOpts = {}) {
|
|
1099
|
-
|
|
1100
|
-
throw new Error("workflow run already finalized — ctx.agentStream cannot be called after the script returned");
|
|
1101
|
-
}
|
|
1102
|
-
const effectiveSignal = spec.signal ?? agentOpts.signal ?? workflowSignal;
|
|
1103
|
-
if (effectiveSignal?.aborted)
|
|
1104
|
-
throw new Error("workflow aborted");
|
|
1105
|
-
if (maxAgents !== undefined && run.agents.length >= maxAgents) {
|
|
1106
|
-
throw new WorkflowMaxAgentsError(maxAgents);
|
|
1107
|
-
}
|
|
1151
|
+
const effectiveSignal = assertAgentSpawnAllowed("ctx.agentStream", spec, agentOpts);
|
|
1108
1152
|
if (budgetTotal !== null && spent() >= budgetTotal) {
|
|
1109
1153
|
throw new WorkflowBudgetExceededError(spent(), budgetTotal);
|
|
1110
1154
|
}
|
|
1111
|
-
|
|
1112
|
-
const compiled = compileOutputSchema(agentOpts.schema);
|
|
1113
|
-
if ("error" in compiled)
|
|
1114
|
-
throw new TypeError(`agent({schema}) received an invalid JSON Schema: ${compiled.error}`);
|
|
1115
|
-
}
|
|
1116
|
-
assertSupportedAgentIsolation(agentOpts.isolation);
|
|
1117
|
-
const label = agentOpts.label ?? `agent-${run.agents.length + 1}`;
|
|
1118
|
-
const phase = agentOpts.phase ?? currentPhase?.title;
|
|
1119
|
-
const phaseInstance = resolveAgentPhase(agentOpts.phase);
|
|
1120
|
-
const groupId = currentGroup;
|
|
1121
|
-
const typeDefModel = agentOpts.agentType !== undefined ? agentRegistry.find((d) => d.name === agentOpts.agentType)?.model : undefined;
|
|
1122
|
-
const inheritedModelSnap = spec.model === undefined && typeDefModel === undefined ? opts.defaultModel?.() : undefined;
|
|
1123
|
-
const specForIdentity = inheritedModelSnap !== undefined ? { ...spec, model: inheritedModelSnap } : spec;
|
|
1124
|
-
const callKey = workflowAgentCallKey(run.agents.length, specForIdentity, agentOpts);
|
|
1125
|
-
const prompt = boundedRedactedSummary(spec.systemPrompt ? `${spec.systemPrompt}\n\n${spec.objective}` : spec.objective, MAX_TRANSCRIPT_CHARS);
|
|
1126
|
-
const model = workflowModelLabel(specForIdentity);
|
|
1155
|
+
const { label, phase, phaseInstance, groupId, inheritedModelSnap, callKey, prompt, model } = prepareAgentCall(spec, agentOpts);
|
|
1127
1156
|
noteDivergence(run.agents.length, "ctx.agentStream results are never replayed");
|
|
1128
1157
|
diverged = true;
|
|
1129
1158
|
const rec = { label, callKey, ...(groupId !== undefined ? { groupId } : {}), phase, prompt, ...(model !== undefined ? { model } : {}), status: "running", queuedAt: now() };
|
|
@@ -1215,35 +1244,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1215
1244
|
await stream.steer(framed, { trusted: true });
|
|
1216
1245
|
return marker;
|
|
1217
1246
|
};
|
|
1218
|
-
|
|
1219
|
-
let beatTurns = 0;
|
|
1220
|
-
let beatCostMicroUsd = 0;
|
|
1221
|
-
const rollbackUsageBeat = () => {
|
|
1222
|
-
if (beatTurns === 0 && beatTokens === 0 && beatCostMicroUsd === 0)
|
|
1223
|
-
return false;
|
|
1224
|
-
run.stats.tokens -= beatTokens;
|
|
1225
|
-
run.stats.turns -= beatTurns;
|
|
1226
|
-
run.stats.costMicroUsd -= beatCostMicroUsd;
|
|
1227
|
-
beatTokens = 0;
|
|
1228
|
-
beatTurns = 0;
|
|
1229
|
-
beatCostMicroUsd = 0;
|
|
1230
|
-
return true;
|
|
1231
|
-
};
|
|
1247
|
+
const { onTurnEndUsage, rollbackUsageBeat } = createUsageBeat(rec);
|
|
1232
1248
|
activeUsageBeats.add(rollbackUsageBeat);
|
|
1233
|
-
const onTurnEndUsage = (usage) => {
|
|
1234
|
-
if (finalized)
|
|
1235
|
-
return;
|
|
1236
|
-
const turnTokens = usage ? usage.totalInputTokens + usage.outputTokens : 0;
|
|
1237
|
-
const turnCost = usage?.costMicroUsd ?? 0;
|
|
1238
|
-
beatTokens += turnTokens;
|
|
1239
|
-
beatTurns += 1;
|
|
1240
|
-
beatCostMicroUsd += turnCost;
|
|
1241
|
-
run.stats.tokens += turnTokens;
|
|
1242
|
-
run.stats.turns += 1;
|
|
1243
|
-
run.stats.costMicroUsd += turnCost;
|
|
1244
|
-
rec.stats = { tokens: beatTokens, turns: beatTurns, costMicroUsd: beatCostMicroUsd };
|
|
1245
|
-
void persist("update");
|
|
1246
|
-
};
|
|
1247
1249
|
const completion = (async () => {
|
|
1248
1250
|
let result;
|
|
1249
1251
|
try {
|
|
@@ -1259,14 +1261,18 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1259
1261
|
catch (err) {
|
|
1260
1262
|
rollbackUsageBeat();
|
|
1261
1263
|
activeUsageBeats.delete(rollbackUsageBeat);
|
|
1264
|
+
const partialSpend = rec.stats;
|
|
1265
|
+
if (!finalized && partialSpend !== undefined && (partialSpend.tokens > 0 || partialSpend.turns > 0 || (partialSpend.costMicroUsd ?? 0) > 0)) {
|
|
1266
|
+
accumulateStats({ stats: partialSpend }, true);
|
|
1267
|
+
}
|
|
1262
1268
|
recordFailed();
|
|
1263
1269
|
releaseOnce();
|
|
1264
|
-
|
|
1270
|
+
void journalAppend(callKey, {
|
|
1265
1271
|
taskId: callKey,
|
|
1266
1272
|
sessionId: "",
|
|
1267
1273
|
status: "failed",
|
|
1268
1274
|
result: boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500),
|
|
1269
|
-
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1275
|
+
stats: { turns: partialSpend?.turns ?? 0, tokens: partialSpend?.tokens ?? 0, costMicroUsd: partialSpend?.costMicroUsd ?? 0 },
|
|
1270
1276
|
}).catch(() => undefined);
|
|
1271
1277
|
bceTerminal(callKey, "failed", err instanceof Error ? err.message : String(err), undefined, rec.stats);
|
|
1272
1278
|
throw err;
|
|
@@ -1279,26 +1285,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1279
1285
|
if (isDurablePause(result.status)) {
|
|
1280
1286
|
result = mapNestedSuspend(result);
|
|
1281
1287
|
}
|
|
1282
|
-
|
|
1283
|
-
accumulateStats(result, true);
|
|
1284
|
-
rec.status = result.status === "completed" ? "completed" : "failed";
|
|
1285
|
-
rec.taskStatus = result.status;
|
|
1286
|
-
if (result.sessionId)
|
|
1287
|
-
rec.sessionId = result.sessionId;
|
|
1288
|
-
rec.endedAt = now();
|
|
1289
|
-
rec.stats = { tokens: s.tokens ?? 0, turns: s.turns ?? 0, costMicroUsd: s.costMicroUsd };
|
|
1290
|
-
const output = settleAgentError(rec, result, label, boundedRedactedSummary(result.structuredOutput ?? result.result, MAX_TRANSCRIPT_CHARS));
|
|
1291
|
-
if (result.stats.toolCalls !== undefined)
|
|
1292
|
-
rec.toolCalls = result.stats.toolCalls;
|
|
1293
|
-
if (activityTail.length > 0)
|
|
1294
|
-
rec.activity = activityTail.slice();
|
|
1295
|
-
emit({ type: "agent_end", runId, label, phase, ...(groupId !== undefined ? { groupId } : {}), status: rec.status, output, ...(rec.errorCode !== undefined ? { errorCode: rec.errorCode } : {}), ...(result.stats.toolCalls !== undefined ? { toolCalls: result.stats.toolCalls } : {}), ts: rec.endedAt });
|
|
1296
|
-
void persist("update");
|
|
1297
|
-
bceTerminal(callKey, rec.status === "completed" ? "completed" : "failed", output, result.sessionId || undefined, rec.stats);
|
|
1298
|
-
await journalAppend(callKey, result, label).catch(() => undefined);
|
|
1299
|
-
if (agentOpts.schema && result.status === "completed" && result.structuredOutput === undefined) {
|
|
1300
|
-
throw new WorkflowAgentSchemaError(label, result);
|
|
1301
|
-
}
|
|
1288
|
+
await settleAgentResult(rec, result, activityTail, agentOpts, "best-effort");
|
|
1302
1289
|
return result;
|
|
1303
1290
|
})();
|
|
1304
1291
|
completion.catch(() => undefined);
|
|
@@ -1312,25 +1299,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1312
1299
|
const settled = await Promise.all(thunks.map((t, i) => Promise.resolve()
|
|
1313
1300
|
.then(t)
|
|
1314
1301
|
.then((v) => ({ ok: true, v }), (e) => ({ ok: false, e, i }))));
|
|
1315
|
-
|
|
1316
|
-
const droppedSlots = [];
|
|
1317
|
-
const results = settled.map((s) => {
|
|
1318
|
-
if (s.ok)
|
|
1319
|
-
return s.v;
|
|
1320
|
-
if (s.e instanceof WorkflowBudgetExceededError) {
|
|
1321
|
-
dropped++;
|
|
1322
|
-
droppedSlots.push(s.i);
|
|
1323
|
-
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
1324
|
-
return null;
|
|
1325
|
-
}
|
|
1326
|
-
rethrowIfMaxAgents(s.e);
|
|
1327
|
-
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
1328
|
-
emitRunLog(`parallel[${s.i}] failed: ${boundedRedactedSummary(s.e instanceof Error ? s.e.message : String(s.e), 300)}`);
|
|
1329
|
-
return null;
|
|
1330
|
-
});
|
|
1331
|
-
if (dropped > 0)
|
|
1332
|
-
emitRunLog(`parallel: ${dropped} ${dropped === 1 ? "slot" : "slots"} dropped — token budget exceeded (${dropped === 1 ? "slot" : "slots"} ${droppedSlots.join(", ")})`);
|
|
1333
|
-
return results;
|
|
1302
|
+
return foldFanOutSettled(settled, "parallel", errorsOut, emitRunLog);
|
|
1334
1303
|
},
|
|
1335
1304
|
async pipeline(items, ...stagesAndOpts) {
|
|
1336
1305
|
if (items.length > MAX_WORKFLOW_ITEMS) {
|
|
@@ -1350,25 +1319,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1350
1319
|
const settled = await Promise.all(items.map((item, index) => stages
|
|
1351
1320
|
.reduce((acc, stage) => acc.then((prev) => stage(prev, item, index)), Promise.resolve(item))
|
|
1352
1321
|
.then((v) => ({ ok: true, v }), (e) => ({ ok: false, e, i: index }))));
|
|
1353
|
-
|
|
1354
|
-
const droppedSlots = [];
|
|
1355
|
-
const results = settled.map((s) => {
|
|
1356
|
-
if (s.ok)
|
|
1357
|
-
return s.v;
|
|
1358
|
-
if (s.e instanceof WorkflowBudgetExceededError) {
|
|
1359
|
-
dropped++;
|
|
1360
|
-
droppedSlots.push(s.i);
|
|
1361
|
-
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
1362
|
-
return null;
|
|
1363
|
-
}
|
|
1364
|
-
rethrowIfMaxAgents(s.e);
|
|
1365
|
-
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
1366
|
-
emitRunLog(`pipeline[${s.i}] failed: ${boundedRedactedSummary(s.e instanceof Error ? s.e.message : String(s.e), 300)}`);
|
|
1367
|
-
return null;
|
|
1368
|
-
});
|
|
1369
|
-
if (dropped > 0)
|
|
1370
|
-
emitRunLog(`pipeline: ${dropped} ${dropped === 1 ? "slot" : "slots"} dropped — token budget exceeded (${dropped === 1 ? "slot" : "slots"} ${droppedSlots.join(", ")})`);
|
|
1371
|
-
return results;
|
|
1322
|
+
return foldFanOutSettled(settled, "pipeline", errorsOut, emitRunLog);
|
|
1372
1323
|
},
|
|
1373
1324
|
async phase(title, body) {
|
|
1374
1325
|
if (finalized)
|
|
@@ -1531,7 +1482,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1531
1482
|
else {
|
|
1532
1483
|
result = await bodyPromise;
|
|
1533
1484
|
}
|
|
1534
|
-
if (
|
|
1485
|
+
if (maxResultChars !== undefined) {
|
|
1535
1486
|
let size = 0;
|
|
1536
1487
|
try {
|
|
1537
1488
|
size = JSON.stringify(result)?.length ?? 0;
|
|
@@ -1539,8 +1490,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1539
1490
|
catch {
|
|
1540
1491
|
size = 0;
|
|
1541
1492
|
}
|
|
1542
|
-
if (size >
|
|
1543
|
-
throw new WorkflowResultTooLargeError(size,
|
|
1493
|
+
if (size > maxResultChars)
|
|
1494
|
+
throw new WorkflowResultTooLargeError(size, maxResultChars);
|
|
1544
1495
|
}
|
|
1545
1496
|
finalized = true;
|
|
1546
1497
|
settleActiveUsageBeats();
|
|
@@ -1587,7 +1538,16 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1587
1538
|
}
|
|
1588
1539
|
finally {
|
|
1589
1540
|
finalized = true;
|
|
1590
|
-
await
|
|
1541
|
+
await new Promise((resolve) => {
|
|
1542
|
+
const t = setTimeout(() => {
|
|
1543
|
+
emitRunLog(`resume-journal: terminal drain did not settle within ${JOURNAL_DRAIN_MAX_MS}ms — tail entries may be missing; a resume from this run re-runs those agents live.`);
|
|
1544
|
+
resolve();
|
|
1545
|
+
}, JOURNAL_DRAIN_MAX_MS);
|
|
1546
|
+
void journalTail.catch(() => undefined).then(() => {
|
|
1547
|
+
clearTimeout(t);
|
|
1548
|
+
resolve();
|
|
1549
|
+
});
|
|
1550
|
+
});
|
|
1591
1551
|
if (resumeClaim !== undefined) {
|
|
1592
1552
|
const granted = await finalizeWithin(timers, resumeClaim.verdict.then((v) => v.granted, () => false), false);
|
|
1593
1553
|
if (granted) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CYBER_RISK, EXECUTION_ENVIRONMENT, URL_SAFETY, SUMMARIZE_TOOL_RESULTS, WORKTREE_NOTICE, SUBAGENT_CONSENT_NOTICE, SUBAGENT_DELIVERY_NOTES, harnessHeadLines, } from "../../prompts/default.js";
|
|
2
2
|
import { GOAL_COMPLETION_GUIDANCE, ORCHESTRATION_AWARENESS, ORCHESTRATION_GUIDANCE, ORCHESTRATION_GUIDANCE_DEFERRED, SUPERVISOR_PROMPT, } from "../../prompts/supervisor.js";
|
|
3
3
|
import { TEAMMATE_COMMUNICATION_ADDENDUM } from "../../prompts/coordinator.js";
|
|
4
|
-
import { SIMPLE_ACTION_CAUTION, SIMPLE_ACT_DONT_REDERIVE, SIMPLE_AUTONOMY_FABLE, SIMPLE_COMMUNICATING_FABLE, SIMPLE_CORRECTIONS_FABLE, SIMPLE_DELIVERING_WORK_FABLE, SIMPLE_COMMUNICATING_LEAN, SIMPLE_CONTEXT_MANAGEMENT,
|
|
4
|
+
import { SIMPLE_ACTION_CAUTION, SIMPLE_ACT_DONT_REDERIVE, SIMPLE_AUTONOMY_FABLE, SIMPLE_COMMUNICATING_FABLE, SIMPLE_CORRECTIONS_FABLE, SIMPLE_DELIVERING_WORK_FABLE, SIMPLE_COMMUNICATING_LEAN, SIMPLE_CONTEXT_MANAGEMENT, SIMPLE_PRONOUNS, SIMPLE_TOOL_PARAM_JSON, SEMA_VERIFY_FRESH, SEMA_EVIDENCE_AUDIT, } from "../../prompts/simple-sections.js";
|
|
5
5
|
function harnessHeadText(inputs) {
|
|
6
6
|
return harnessHeadLines(inputs.facts);
|
|
7
7
|
}
|
|
@@ -47,9 +47,7 @@ export const SEMA_DEFAULT_PACK = {
|
|
|
47
47
|
{ id: "core/simple.communicating", slot: "harness", rank: 250, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: (i) => (i.facts.fableMitigations === true ? SIMPLE_COMMUNICATING_FABLE : SIMPLE_COMMUNICATING_LEAN), legacyBlockId: "harness.context" },
|
|
48
48
|
{ id: "core/simple.pronouns", slot: "harness", rank: 252, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: () => SIMPLE_PRONOUNS, legacyBlockId: "harness.context" },
|
|
49
49
|
{ id: "core/simple.action-caution", slot: "harness", rank: 254, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: () => SIMPLE_ACTION_CAUTION, legacyBlockId: "harness.context" },
|
|
50
|
-
{ id: "core/simple.task-continuity", slot: "harness", rank: 256, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: () => SIMPLE_TASK_CONTINUITY, legacyBlockId: "harness.context" },
|
|
51
50
|
{ id: "core/simple.tool-param-json", slot: "harness", rank: 258, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: () => SIMPLE_TOOL_PARAM_JSON, legacyBlockId: "harness.context" },
|
|
52
|
-
{ id: "core/simple.investigate-first", slot: "harness", rank: 260, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: () => SIMPLE_INVESTIGATE_FIRST, legacyBlockId: "harness.context" },
|
|
53
51
|
{ id: "core/simple.context-management", slot: "harness", rank: 262, ...CORE, admit: (i) => i.facts.promptProfile !== "classic" && i.facts.withinTaskCompactionEnabled, content: () => SIMPLE_CONTEXT_MANAGEMENT, legacyBlockId: "harness.context" },
|
|
54
52
|
{ id: "core/simple.act-dont-rederive", slot: "harness", rank: 264, ...CORE, admit: (i) => i.facts.promptProfile !== "classic", content: () => SIMPLE_ACT_DONT_REDERIVE, legacyBlockId: "harness.context" },
|
|
55
53
|
{ id: "core/simple.delivering-work", slot: "harness", rank: 265, ...CORE, admit: (i) => i.facts.promptProfile !== "classic" && i.facts.fableMitigations === true, content: () => SIMPLE_DELIVERING_WORK_FABLE, legacyBlockId: "harness.context" },
|
|
@@ -11,6 +11,15 @@ export interface ToolContractDescriptor {
|
|
|
11
11
|
wireSchemaDigest: string;
|
|
12
12
|
cardId: string;
|
|
13
13
|
}
|
|
14
|
+
export interface ToolManifestRow {
|
|
15
|
+
wireName: string;
|
|
16
|
+
aliases: string[];
|
|
17
|
+
contractId: string;
|
|
18
|
+
implementationRevision: string;
|
|
19
|
+
cardId: string;
|
|
20
|
+
shapeDigest: string;
|
|
21
|
+
wireSchemaDigest: string;
|
|
22
|
+
}
|
|
14
23
|
export declare function computeShapeDigest(schema: TSchema | undefined): string;
|
|
15
24
|
export declare function computeWireSchemaDigest(schema: TSchema | undefined, description: string): string;
|
|
16
25
|
export interface AttachContractInput {
|
|
@@ -22,15 +31,7 @@ export interface AttachContractInput {
|
|
|
22
31
|
export declare function attachToolContract(tool: AgentTool, input: AttachContractInput): void;
|
|
23
32
|
export declare function getToolContract(tool: AgentTool, fallbackOrigin?: ToolOrigin): ToolContractDescriptor;
|
|
24
33
|
export declare function hasToolContract(tool: AgentTool): boolean;
|
|
25
|
-
export declare function projectToolManifest(tools: AgentTool[], originOf?: (tool: AgentTool) => ToolOrigin):
|
|
26
|
-
wireName: string;
|
|
27
|
-
aliases: string[];
|
|
28
|
-
contractId: string;
|
|
29
|
-
implementationRevision: string;
|
|
30
|
-
cardId: string;
|
|
31
|
-
shapeDigest: string;
|
|
32
|
-
wireSchemaDigest: string;
|
|
33
|
-
}>;
|
|
34
|
+
export declare function projectToolManifest(tools: AgentTool[], originOf?: (tool: AgentTool) => ToolOrigin): ToolManifestRow[];
|
|
34
35
|
export declare function auditToolCollisions(tools: AgentTool[]): {
|
|
35
36
|
yields: Array<{
|
|
36
37
|
name: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ToolFingerprintInput } from "../core/cache-break-detector.js";
|
|
1
2
|
export interface RawPrefixInputs {
|
|
2
3
|
provider: string;
|
|
3
4
|
modelId: string;
|
|
@@ -9,11 +10,7 @@ export interface RawPrefixInputs {
|
|
|
9
10
|
cacheControlBoundary: boolean;
|
|
10
11
|
}>;
|
|
11
12
|
stableSystemText: string;
|
|
12
|
-
toolWire: ReadonlyArray<
|
|
13
|
-
name: string;
|
|
14
|
-
description: string;
|
|
15
|
-
parameters: unknown;
|
|
16
|
-
}>;
|
|
13
|
+
toolWire: ReadonlyArray<ToolFingerprintInput>;
|
|
17
14
|
thinkingLevel: string;
|
|
18
15
|
maxTokens: number | undefined;
|
|
19
16
|
hasOutputSchema: boolean;
|
package/dist/prompts/default.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { inlineUntrusted, sanitizeUntrustedText } from "../core/untrusted-text.js";
|
|
2
2
|
import { GOAL_COMPLETION_GUIDANCE, ORCHESTRATION_AWARENESS, ORCHESTRATION_GUIDANCE, ORCHESTRATION_GUIDANCE_DEFERRED, SUPERVISOR_PROMPT } from "./supervisor.js";
|
|
3
|
-
import { SIMPLE_ACTION_CAUTION, SIMPLE_ACT_DONT_REDERIVE, SIMPLE_AUTONOMY_FABLE, SIMPLE_COMMUNICATING_FABLE, SIMPLE_COMMUNICATING_LEAN, SIMPLE_CONTEXT_MANAGEMENT, SIMPLE_CORRECTIONS_FABLE, SIMPLE_DELIVERING_WORK_FABLE,
|
|
3
|
+
import { SIMPLE_ACTION_CAUTION, SIMPLE_ACT_DONT_REDERIVE, SIMPLE_AUTONOMY_FABLE, SIMPLE_COMMUNICATING_FABLE, SIMPLE_COMMUNICATING_LEAN, SIMPLE_CONTEXT_MANAGEMENT, SIMPLE_CORRECTIONS_FABLE, SIMPLE_DELIVERING_WORK_FABLE, SIMPLE_PRONOUNS, SIMPLE_TOOL_PARAM_JSON, SEMA_VERIFY_FRESH, SEMA_EVIDENCE_AUDIT, } from "./simple-sections.js";
|
|
4
4
|
export const OUTPUT_EFFICIENCY = "If you can say it in one sentence, don't use three. Go straight to the point, don't go in circles, " +
|
|
5
5
|
"don't overdo it. (This does not apply to code or tool calls.)";
|
|
6
6
|
export const DEFAULT_SYSTEM_PROMPT = `You are a capable AI agent that acts through tools.
|
|
@@ -153,9 +153,7 @@ export function harnessContext(ctx) {
|
|
|
153
153
|
blocks.push(ctx.fableMitigations === true ? SIMPLE_COMMUNICATING_FABLE : SIMPLE_COMMUNICATING_LEAN);
|
|
154
154
|
blocks.push(SIMPLE_PRONOUNS);
|
|
155
155
|
blocks.push(SIMPLE_ACTION_CAUTION);
|
|
156
|
-
blocks.push(SIMPLE_TASK_CONTINUITY);
|
|
157
156
|
blocks.push(SIMPLE_TOOL_PARAM_JSON);
|
|
158
|
-
blocks.push(SIMPLE_INVESTIGATE_FIRST);
|
|
159
157
|
if (ctx.withinTaskCompactionEnabled)
|
|
160
158
|
blocks.push(SIMPLE_CONTEXT_MANAGEMENT);
|
|
161
159
|
blocks.push(SIMPLE_ACT_DONT_REDERIVE);
|