@sema-agent/core 7.5.2 → 7.6.1
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 +67 -0
- package/dist/agents/agent-transcript-tool.d.ts +2 -2
- package/dist/agents/cascade.d.ts +4 -5
- package/dist/agents/cascade.js +12 -10
- package/dist/agents/repair-loop.d.ts +7 -5
- package/dist/agents/repair-loop.js +13 -15
- package/dist/agents/retain-ledger.d.ts +2 -3
- package/dist/agents/send-message-tool.d.ts +2 -2
- package/dist/agents/session-util.d.ts +2 -2
- package/dist/agents/subagent.d.ts +27 -46
- package/dist/agents/subagent.js +119 -105
- package/dist/agents/suspend-guard.d.ts +31 -19
- package/dist/agents/suspend-guard.js +14 -8
- package/dist/agents/teacher.d.ts +2 -2
- package/dist/agents/teacher.js +9 -9
- package/dist/agents/team.d.ts +6 -5
- package/dist/agents/team.js +10 -8
- package/dist/agents/verify.d.ts +8 -9
- package/dist/agents/verify.js +17 -17
- package/dist/core/a2a.js +2 -1
- package/dist/core/agent-definition.d.ts +172 -0
- package/dist/core/agent-definition.js +1 -0
- package/dist/core/ask-origin.d.ts +60 -7
- package/dist/core/ask-origin.js +26 -1
- package/dist/core/checkpoint-store.d.ts +78 -76
- package/dist/core/checkpoint-store.js +17 -1
- package/dist/core/delegation-frames.d.ts +298 -0
- package/dist/core/delegation-frames.js +21 -0
- package/dist/core/engine-notice.d.ts +555 -0
- package/dist/core/engine-notice.js +55 -0
- package/dist/core/gate-fold.d.ts +12 -0
- package/dist/core/gate-fold.js +158 -0
- package/dist/core/gate-lanes.d.ts +93 -0
- package/dist/core/gate-lanes.js +626 -0
- package/dist/core/gate-outcome.d.ts +189 -0
- package/dist/core/gate-outcome.js +70 -0
- package/dist/core/hands-band.d.ts +134 -0
- package/dist/core/hands-band.js +1 -0
- package/dist/core/hooks.d.ts +22 -177
- package/dist/core/hooks.js +53 -851
- package/dist/core/mcp-failure.d.ts +142 -0
- package/dist/core/mcp-failure.js +145 -0
- package/dist/core/mcp-server-spec.d.ts +217 -0
- package/dist/core/mcp-server-spec.js +1 -0
- package/dist/core/mcp.d.ts +21 -77
- package/dist/core/mcp.js +76 -150
- package/dist/core/model-seat.d.ts +99 -0
- package/dist/core/model-seat.js +1 -0
- package/dist/core/pause-registry.d.ts +131 -0
- package/dist/core/pause-registry.js +27 -0
- package/dist/core/reminder-mint.d.ts +10 -0
- package/dist/core/reminder-mint.js +3 -0
- package/dist/core/runner/assemble-result.d.ts +32 -41
- package/dist/core/runner/assemble-result.js +55 -74
- package/dist/core/runner/contracts.d.ts +427 -69
- package/dist/core/runner/denial-limit-arms.d.ts +1 -1
- package/dist/core/runner/denial-limit-arms.js +3 -3
- package/dist/core/runner/gate-exit.d.ts +242 -0
- package/dist/core/runner/gate-exit.js +124 -0
- package/dist/core/runner/park-commit.d.ts +17 -23
- package/dist/core/runner/park-commit.js +14 -15
- package/dist/core/runner/prepare-ask-lane.d.ts +0 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -5
- package/dist/core/runner/prepare-boundary-parks.d.ts +3 -6
- package/dist/core/runner/prepare-boundary-parks.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -7
- package/dist/core/runner/prepare-caps-and-workflow.js +1 -1
- package/dist/core/runner/prepare-delegation-surface.d.ts +2 -7
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -7
- package/dist/core/runner/prepare-gate-stations.js +29 -54
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +44 -26
- package/dist/core/runner/prepare-park-ask.d.ts +2 -4
- package/dist/core/runner/prepare-park-ask.js +5 -5
- package/dist/core/runner/prepare-task.d.ts +2 -2
- package/dist/core/runner/prepare-task.js +8 -9
- package/dist/core/runner/prepare-wiring-manifest.d.ts +7 -15
- package/dist/core/runner/prepare-wiring-manifest.js +9 -10
- package/dist/core/runner/runtask.d.ts +20 -102
- package/dist/core/runner/runtask.js +119 -121
- package/dist/core/runner/terminal-projection.d.ts +22 -0
- package/dist/core/runner/terminal-projection.js +28 -0
- package/dist/core/runner-deps.d.ts +1416 -0
- package/dist/core/runner-deps.js +1 -0
- package/dist/core/runtime-caps.d.ts +164 -0
- package/dist/core/runtime-caps.js +1 -0
- package/dist/core/store-contracts/checkpoint-store-contract.d.ts +4 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +8 -2
- package/dist/core/task-event.d.ts +910 -0
- package/dist/core/task-event.js +1 -0
- package/dist/core/task-limits.d.ts +110 -0
- package/dist/core/task-limits.js +1 -0
- package/dist/core/task-result.d.ts +809 -0
- package/dist/core/task-result.js +1 -0
- package/dist/core/task-spec.d.ts +1370 -0
- package/dist/core/task-spec.js +1 -0
- package/dist/core/task-stream.d.ts +382 -0
- package/dist/core/task-stream.js +1 -0
- package/dist/core/terminal-cause.d.ts +137 -0
- package/dist/core/terminal-cause.js +9 -0
- package/dist/core/tool-policy.d.ts +43 -139
- package/dist/core/tool-policy.js +79 -112
- package/dist/core/tool-spec.d.ts +1174 -0
- package/dist/core/tool-spec.js +1 -0
- package/dist/core/types.d.ts +27 -7789
- package/dist/core/types.js +2 -76
- package/dist/core/warm-resume.d.ts +2 -2
- package/dist/core/wiring-manifest.d.ts +6 -3
- package/dist/core/workflow-journal-store.js +3 -4
- package/dist/engine/harness/agent-harness.d.ts +1 -1
- package/dist/index.d.ts +12 -8
- package/dist/index.js +9 -6
- package/dist/orchestration/builtin-workflows.d.ts +2 -2
- package/dist/orchestration/builtin-workflows.js +1 -1
- package/dist/orchestration/goal.d.ts +2 -2
- package/dist/orchestration/goal.js +8 -7
- package/dist/orchestration/run-spec.d.ts +2 -2
- package/dist/orchestration/run-spec.js +5 -3
- package/dist/orchestration/run-workflow-tool.d.ts +4 -4
- package/dist/orchestration/run-workflow-tool.js +4 -4
- package/dist/orchestration/workflow-governance.d.ts +4 -4
- package/dist/orchestration/workflow-governance.js +4 -2
- package/dist/orchestration/workflow-primitives.d.ts +1 -1
- package/dist/orchestration/workflow-primitives.js +1 -1
- package/dist/orchestration/workflow.d.ts +15 -4
- package/dist/orchestration/workflow.js +64 -39
- package/dist/prompts/supervisor.d.ts +1 -1
- package/dist/prompts/supervisor.js +3 -3
- package/dist/scenarios/scenario-registry.d.ts +3 -3
- package/dist/scenarios/scenario-registry.js +1 -1
- package/dist/scenarios/teacher-quickstart.d.ts +2 -2
- package/dist/server/http.d.ts +2 -2
- package/dist/stores/file/fs-atomic.d.ts +88 -12
- package/dist/stores/file/fs-atomic.js +184 -55
- package/dist/stores/file/index.d.ts +1 -0
- package/dist/stores/file/index.js +1 -0
- package/package.json +3 -1
- package/test/export-surface.snapshot.json +82 -22
|
@@ -322,10 +322,10 @@ export async function createRunWorkflowTool(d) {
|
|
|
322
322
|
"• Research/audit workflows: document and file claims are HYPOTHESES, not evidence — add a VERIFY " +
|
|
323
323
|
"stage whose agents EXECUTE (run the command, the test, the reproducer) and cross-check claims " +
|
|
324
324
|
"against actual output before the synthesis stage reports them as fact.\n" +
|
|
325
|
-
"• r.
|
|
326
|
-
"('completed' on success; 'failed'
|
|
327
|
-
"check r.
|
|
328
|
-
"`const impl = await agent({ objective: '…' }, { label: 'implement-fix' }); if (impl.
|
|
325
|
+
"• r.terminal.kind: agent() does NOT throw when the sub-agent FAILS — it RETURNS the result with r.terminal " +
|
|
326
|
+
"({ kind: 'completed' } on success; kind 'failed' (with r.terminal.code / r.terminal.message) / 'blocked' (r.terminal.reason) / 'paused' otherwise, " +
|
|
327
|
+
"with any failure text also in r.result). ALWAYS check r.terminal.kind before building on a result, and GATE later phases on it — e.g. " +
|
|
328
|
+
"`const impl = await agent({ objective: '…' }, { label: 'implement-fix' }); if (impl.terminal.kind !== 'completed') return { failed: 'implement', why: impl.result }` " +
|
|
329
329
|
"— running later phases on a failed prerequisite burns tokens on garbage.\n" +
|
|
330
330
|
"• phase (two forms, both fine): bare marker — phase('Scan'); groups every later agent() under 'Scan' " +
|
|
331
331
|
"until the next phase() call. Scoped — await phase('Fix', async () => { ...agents... }); groups just the " +
|
|
@@ -194,10 +194,10 @@ export interface ResourceClampNote {
|
|
|
194
194
|
* `restoreGatedTools` / `readFace` / … — for exactly the children an untrusted script can route to
|
|
195
195
|
* the overlay (`isolation: "worktree"`), own-`undefined` keys included (a spread copies them; the
|
|
196
196
|
* old `=== null` face drop missed that half). One rule at the one merge point: a new baseline key
|
|
197
|
-
* is safe with no list to extend
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
* wholesale — the documented deployment override.
|
|
197
|
+
* is safe with no list to extend, and there is no exception list — the one key that used to give
|
|
198
|
+
* `null` a meaning of its own (`checkpointStore`, the durable off switch) now spells it as the word
|
|
199
|
+
* `"disabled"`, an ordinary non-nullish value the rule already keeps. Explicit non-nullish overlay
|
|
200
|
+
* values keep winning wholesale — the documented deployment override.
|
|
201
201
|
*
|
|
202
202
|
* ACCEPTED COST, stated (adversarial-review round 2): the rule is direction-blind — a CAPABILITY
|
|
203
203
|
* key's out-of-type overlay `null` used to WITHHOLD the base value by the same spread accident
|
|
@@ -4,6 +4,7 @@ import { sanitizeUntrustedText } from "../core/untrusted-text.js";
|
|
|
4
4
|
import { compileReadDeny } from "../tools/fs/read-deny.js";
|
|
5
5
|
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
6
6
|
import { uuidv7 } from "../engine/session/uuid.js";
|
|
7
|
+
import { retiredCheckpointStoreNull } from "../core/checkpoint-store.js";
|
|
7
8
|
export class WorkflowModelNotAllowedError extends Error {
|
|
8
9
|
modelName;
|
|
9
10
|
code = "workflow.model_not_allowed";
|
|
@@ -79,12 +80,13 @@ export function emitIgnoredAgentOptionsNotice(total, sample, accepted, onNotice)
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
const VALID_THINKING = new Set(["off", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
82
|
-
const NULL_VALUED_BASELINE_KEYS = new Set(["checkpointStore"]);
|
|
83
83
|
export function overlayWorktreeBaseline(base, worktreeBase) {
|
|
84
84
|
let overlay = worktreeBase;
|
|
85
85
|
for (const key of Object.keys(worktreeBase)) {
|
|
86
86
|
const v = worktreeBase[key];
|
|
87
|
-
if (
|
|
87
|
+
if (key === "checkpointStore" && v === null)
|
|
88
|
+
throw retiredCheckpointStoreNull();
|
|
89
|
+
if (v !== undefined && v !== null)
|
|
88
90
|
continue;
|
|
89
91
|
if (overlay === worktreeBase)
|
|
90
92
|
overlay = { ...worktreeBase };
|
|
@@ -33,7 +33,7 @@ export interface WorkflowGovernance {
|
|
|
33
33
|
* `agent` primitive is GOVERNED when `governance` is set (LLM-authored), else a trusted pass-through.
|
|
34
34
|
*/
|
|
35
35
|
export declare function buildWorkflowPrimitives(ctx: WorkflowRunContext, governance?: WorkflowGovernance, onAgentSpawn?: (handle: WorkflowAgentHandle) => void, parentThinking?: () => TaskSpec["thinking"], parentPrincipal?: string,
|
|
36
|
-
/** ruled 2026-08-04 — the host run set `TaskSpec.checkpointStore:
|
|
36
|
+
/** ruled 2026-08-04 — the host run set `TaskSpec.checkpointStore: "disabled"` (the per-run durable off
|
|
37
37
|
* switch). Every agent this workflow spawns inherits it; see the injection below. */
|
|
38
38
|
parentCheckpointStoreDisabled?: boolean,
|
|
39
39
|
/** 5.30 merge-rescan (design/199 parity gap) — the host run's RESOLVED read-face containment
|
|
@@ -83,7 +83,7 @@ export function buildWorkflowPrimitives(ctx, governance, onAgentSpawn, parentThi
|
|
|
83
83
|
childSpec.principal = parentPrincipal;
|
|
84
84
|
}
|
|
85
85
|
if (parentCheckpointStoreDisabled === true) {
|
|
86
|
-
childSpec.checkpointStore =
|
|
86
|
+
childSpec.checkpointStore = "disabled";
|
|
87
87
|
}
|
|
88
88
|
if (parentReadFace) {
|
|
89
89
|
const pf = parentReadFace();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
|
-
import type {
|
|
2
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
3
3
|
import type { AgentDefinition, TaskEvent, TaskResult, TaskSpec } from "../core/types.js";
|
|
4
4
|
import type { WorkflowRunStore } from "../core/workflow-run-store.js";
|
|
5
5
|
import type { WorkflowJournalStore, ResumeClaimArgs } from "../core/workflow-journal-store.js";
|
|
@@ -111,6 +111,17 @@ export declare class WorkflowResultTooLargeError extends Error {
|
|
|
111
111
|
readonly code = "workflow.result_too_large";
|
|
112
112
|
constructor(size: number, max: number);
|
|
113
113
|
}
|
|
114
|
+
/** A resume journal entry whose result carries no terminal cause — a journal written before
|
|
115
|
+
* `TaskResult.terminal` existed, or a malformed entry — is INCOMPATIBLE, and the resume is refused
|
|
116
|
+
* before any work is dispatched. The alternative (letting the entry diverge into a live re-run) would
|
|
117
|
+
* execute the already-completed prefix again, side effects included; a schema mismatch is never a
|
|
118
|
+
* permission to rerun finished work. Start a fresh run instead of resuming such a journal. */
|
|
119
|
+
export declare class WorkflowJournalIncompatibleError extends Error {
|
|
120
|
+
readonly fromRunId: string;
|
|
121
|
+
readonly ordinal: number;
|
|
122
|
+
readonly code = "workflow.journal_incompatible";
|
|
123
|
+
constructor(fromRunId: string, ordinal: number);
|
|
124
|
+
}
|
|
114
125
|
/**
|
|
115
126
|
* A TRUSTED, run-scoped internal channel carrying the workflow **nesting depth** across a process boundary
|
|
116
127
|
* (design/98 §0.1 BLOCKER3). It is NOT a `TaskSpec` field and NOT a `run_workflow` tool param — a worker or
|
|
@@ -441,7 +452,7 @@ export interface RunWorkflowOptions {
|
|
|
441
452
|
* (`RunInternals.inheritedGate`) on both spawn legs (`agent()` and `agentStream()`). Set by the
|
|
442
453
|
* `run_workflow` tool wiring; a directly-started workflow may pass its own. Absent ⇒ children run
|
|
443
454
|
* under only their own gates (pre-seam behavior). TRUSTED: never a script/model argument. */
|
|
444
|
-
inheritedGate?: import("../core/runner/
|
|
455
|
+
inheritedGate?: import("../core/runner/contracts.js").InheritedGate;
|
|
445
456
|
/** RB-201 FO-3 (workflow lane) — the session's auto-mode classifier, consulted BEFORE each script-spawned
|
|
446
457
|
* child starts (objective + toolset + output schema, finalized). The delegation-tool lane reviews its
|
|
447
458
|
* children at one shared point; a workflow's children reach `runner.runTask` through this module instead,
|
|
@@ -542,11 +553,11 @@ export declare const workflowResumeClaimFallback: {
|
|
|
542
553
|
* `done` rejects. `cancel(reason)` aborts the whole run. A nesting/validation violation throws SYNCHRONOUSLY
|
|
543
554
|
* from this call (before any handle exists). Thin composition over `runner.runTask` — no Runner changes.
|
|
544
555
|
*/
|
|
545
|
-
export declare function startWorkflow<T>(runner:
|
|
556
|
+
export declare function startWorkflow<T>(runner: RunnerSelfSeat, fn: (ctx: WorkflowRunContext) => Promise<T>, opts?: RunWorkflowOptions, internals?: WorkflowInternals): WorkflowHandle<T>;
|
|
546
557
|
/**
|
|
547
558
|
* Run a workflow to completion (design/97 S1a) — the thin await over {@link startWorkflow}: returns the
|
|
548
559
|
* script's value + the assembled {@link WorkflowRun}. A synchronous nesting/validation throw from
|
|
549
560
|
* `startWorkflow` becomes a rejected promise here (this function is `async`), preserving the original
|
|
550
561
|
* `runWorkflow` contract (`await runWorkflow(...)` rejects rather than throwing synchronously).
|
|
551
562
|
*/
|
|
552
|
-
export declare function runWorkflow<T>(runner:
|
|
563
|
+
export declare function runWorkflow<T>(runner: RunnerSelfSeat, fn: (ctx: WorkflowRunContext) => Promise<T>, opts?: RunWorkflowOptions, internals?: WorkflowInternals): Promise<RunWorkflowResult<T>>;
|
|
@@ -3,6 +3,8 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
3
3
|
import { createHash, randomUUID } from "node:crypto";
|
|
4
4
|
import { availableParallelism } from "node:os";
|
|
5
5
|
import { uuidv7 } from "../internal/harness.js";
|
|
6
|
+
import { TERMINAL_CAUSE_IS_REPLAYABLE, isTerminalCauseKind } from "../core/terminal-cause.js";
|
|
7
|
+
import { terminalProjection } from "../core/runner/terminal-projection.js";
|
|
6
8
|
import { builtinAgentDefinitions } from "../agents/builtin-agents.js";
|
|
7
9
|
import { GENERAL_PURPOSE_SUBAGENT_TYPE, markerFragment } from "../agents/subagent.js";
|
|
8
10
|
import { combinePolicies, createAllowDenyPolicy } from "../core/tool-policy.js";
|
|
@@ -200,6 +202,19 @@ export class WorkflowResultTooLargeError extends Error {
|
|
|
200
202
|
this.name = "WorkflowResultTooLargeError";
|
|
201
203
|
}
|
|
202
204
|
}
|
|
205
|
+
export class WorkflowJournalIncompatibleError extends Error {
|
|
206
|
+
fromRunId;
|
|
207
|
+
ordinal;
|
|
208
|
+
code = "workflow.journal_incompatible";
|
|
209
|
+
constructor(fromRunId, ordinal) {
|
|
210
|
+
super(`startWorkflow: resume from "${fromRunId}" was REFUSED — journal entry #${ordinal} carries no terminal cause ` +
|
|
211
|
+
"(a journal written before TaskResult.terminal, or a malformed entry). Completed work must not run again; " +
|
|
212
|
+
"start a fresh run instead of resuming this journal.");
|
|
213
|
+
this.fromRunId = fromRunId;
|
|
214
|
+
this.ordinal = ordinal;
|
|
215
|
+
this.name = "WorkflowJournalIncompatibleError";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
203
218
|
const workflowDepthStore = new AsyncLocalStorage();
|
|
204
219
|
function currentWorkflowDepth() {
|
|
205
220
|
return workflowDepthStore.getStore()?.depth ?? 0;
|
|
@@ -768,9 +783,12 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
768
783
|
};
|
|
769
784
|
let journalTail = Promise.resolve();
|
|
770
785
|
const JOURNAL_DRAIN_MAX_MS = 5_000;
|
|
771
|
-
const journalDurableResult = (result) =>
|
|
772
|
-
|
|
773
|
-
|
|
786
|
+
const journalDurableResult = (result) => {
|
|
787
|
+
const t = result.terminal;
|
|
788
|
+
if (t === undefined || t.kind !== "failed" || typeof t.message !== "string" || t.message === "")
|
|
789
|
+
return result;
|
|
790
|
+
return { ...result, terminal: { ...t, message: boundedRedactedSummary(t.message, MAX_TRANSCRIPT_CHARS) } };
|
|
791
|
+
};
|
|
774
792
|
const journalAppend = async (callKey, result, label) => {
|
|
775
793
|
const dbg = typeof process !== "undefined" && process.env?.SEMA_DEBUG_WORKFLOW_JOURNAL === "1";
|
|
776
794
|
if (!journalStore) {
|
|
@@ -972,16 +990,17 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
972
990
|
}
|
|
973
991
|
emitRunLog(`resume: replay stopped at agent #${ordinal} (${reason}) — this call and every later call run live.`);
|
|
974
992
|
};
|
|
975
|
-
const settleAgentError = (rec,
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
993
|
+
const settleAgentError = (rec, terminal, label, rawOutput) => {
|
|
994
|
+
const face = terminalProjection(terminal);
|
|
995
|
+
if (terminal.kind !== "completed") {
|
|
996
|
+
if (face.errorCode !== undefined)
|
|
997
|
+
rec.errorCode = face.errorCode;
|
|
998
|
+
if (face.errorMessage !== undefined && face.errorMessage !== "") {
|
|
999
|
+
rec.errorMessage = boundedRedactedSummary(face.errorMessage, MAX_TRANSCRIPT_CHARS);
|
|
981
1000
|
}
|
|
982
|
-
emitRunLog(`[${label}] ${
|
|
1001
|
+
emitRunLog(`[${label}] ${face.status}${face.errorCode !== undefined ? ` (${face.errorCode})` : ""}${rec.errorMessage !== undefined ? `: ${rec.errorMessage.slice(0, 300)}` : ""}`);
|
|
983
1002
|
}
|
|
984
|
-
const output = rawOutput || (
|
|
1003
|
+
const output = rawOutput || (terminal.kind !== "completed" ? (rec.errorMessage ?? "") : "");
|
|
985
1004
|
rec.output = output;
|
|
986
1005
|
return output;
|
|
987
1006
|
};
|
|
@@ -1128,14 +1147,14 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1128
1147
|
const settleAgentResult = async (rec, result, activityTail, agentOpts, journal) => {
|
|
1129
1148
|
const s = result.stats;
|
|
1130
1149
|
accumulateStats(result, true);
|
|
1131
|
-
rec.status = result.
|
|
1132
|
-
rec.taskStatus = result.status;
|
|
1150
|
+
rec.status = result.terminal.kind === "completed" ? "completed" : "failed";
|
|
1151
|
+
rec.taskStatus = terminalProjection(result.terminal).status;
|
|
1133
1152
|
if (result.sessionId)
|
|
1134
1153
|
rec.sessionId = result.sessionId;
|
|
1135
1154
|
setLegRunId(rec, result);
|
|
1136
1155
|
rec.endedAt = now();
|
|
1137
1156
|
rec.stats = { tokens: s.tokens ?? 0, turns: s.turns ?? 0, costMicroUsd: s.costMicroUsd };
|
|
1138
|
-
const output = settleAgentError(rec, result, rec.label, boundedRedactedSummary(result.structuredOutput ?? result.result, MAX_TRANSCRIPT_CHARS));
|
|
1157
|
+
const output = settleAgentError(rec, result.terminal, rec.label, boundedRedactedSummary(result.structuredOutput ?? result.result, MAX_TRANSCRIPT_CHARS));
|
|
1139
1158
|
if (result.stats.toolCalls !== undefined)
|
|
1140
1159
|
rec.toolCalls = result.stats.toolCalls;
|
|
1141
1160
|
if (activityTail.length > 0)
|
|
@@ -1149,7 +1168,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1149
1168
|
else {
|
|
1150
1169
|
void journalAppend(rec.callKey, result, rec.label).catch(() => undefined);
|
|
1151
1170
|
}
|
|
1152
|
-
if (agentOpts.schema && result.
|
|
1171
|
+
if (agentOpts.schema && result.terminal.kind === "completed" && result.structuredOutput === undefined) {
|
|
1153
1172
|
throw new WorkflowAgentSchemaError(rec.label, result);
|
|
1154
1173
|
}
|
|
1155
1174
|
};
|
|
@@ -1165,7 +1184,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1165
1184
|
const { label, phase, phaseInstance, groupId, inheritedModelSnap, callKey, prompt, model } = prepareAgentCall(spec, agentOpts);
|
|
1166
1185
|
if (opts.resumeFromRunId !== undefined && !diverged) {
|
|
1167
1186
|
const cached = replayByOrdinal[run.agents.length];
|
|
1168
|
-
if (cached && cached.callKey === callKey && cached.result.
|
|
1187
|
+
if (cached && cached.callKey === callKey && TERMINAL_CAUSE_IS_REPLAYABLE[cached.result.terminal.kind]) {
|
|
1169
1188
|
if (finalized)
|
|
1170
1189
|
return cached.result;
|
|
1171
1190
|
const r = cached.result;
|
|
@@ -1181,8 +1200,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1181
1200
|
prompt,
|
|
1182
1201
|
...(replayModel !== undefined ? { model: replayModel } : {}),
|
|
1183
1202
|
replayed: true,
|
|
1184
|
-
status: r.
|
|
1185
|
-
taskStatus: r.status,
|
|
1203
|
+
status: r.terminal.kind === "completed" ? "completed" : "failed",
|
|
1204
|
+
taskStatus: terminalProjection(r.terminal).status,
|
|
1186
1205
|
...(r.sessionId ? { sessionId: r.sessionId } : {}),
|
|
1187
1206
|
...(r.runId ? { taskRunId: r.runId } : {}),
|
|
1188
1207
|
queuedAt: at,
|
|
@@ -1204,7 +1223,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1204
1223
|
accumulateStats(r, false);
|
|
1205
1224
|
void persist("update");
|
|
1206
1225
|
await journalAppend(callKey, r);
|
|
1207
|
-
if (agentOpts.schema && r.
|
|
1226
|
+
if (agentOpts.schema && r.terminal.kind === "completed" && r.structuredOutput === undefined) {
|
|
1208
1227
|
throw new WorkflowAgentSchemaError(label, r);
|
|
1209
1228
|
}
|
|
1210
1229
|
return r;
|
|
@@ -1217,9 +1236,9 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1217
1236
|
: "no journal entry at this ordinal (never recorded, e.g. an oversize result under a pre-tombstone engine, or dropped)"
|
|
1218
1237
|
: cached.callKey !== callKey
|
|
1219
1238
|
? "the call key changed — the script or its args differ here"
|
|
1220
|
-
: cached.result.
|
|
1239
|
+
: cached.result.terminal?.kind === "failed" && cached.result.terminal.code === JOURNAL_OVERSIZE_ERROR_CODE
|
|
1221
1240
|
? "the prior result exceeded the journal size cap and was never cached"
|
|
1222
|
-
: `the journaled result was ${cached.result.
|
|
1241
|
+
: `the journaled result was ${cached.result.terminal?.kind ?? "(no terminal record)"}, not completed`);
|
|
1223
1242
|
diverged = true;
|
|
1224
1243
|
}
|
|
1225
1244
|
if (budgetTotal !== null && spent() >= budgetTotal) {
|
|
@@ -1379,7 +1398,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1379
1398
|
}
|
|
1380
1399
|
throw new Error("workflow aborted");
|
|
1381
1400
|
}
|
|
1382
|
-
if (stallFired && attemptResult?.
|
|
1401
|
+
if (stallFired && attemptResult?.terminal.kind !== "completed") {
|
|
1383
1402
|
if (attemptResult !== undefined && !finalized)
|
|
1384
1403
|
accumulateStats(attemptResult, true);
|
|
1385
1404
|
if (attemptResult !== undefined && !finalized)
|
|
@@ -1403,7 +1422,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1403
1422
|
throw attemptError;
|
|
1404
1423
|
result = attemptResult;
|
|
1405
1424
|
const durationMs = now() - attemptStart;
|
|
1406
|
-
const degraded = result.
|
|
1425
|
+
const degraded = result.terminal.kind === "completed" &&
|
|
1407
1426
|
result.structuredOutput === undefined &&
|
|
1408
1427
|
(result.stats.outputTokens ?? Number.POSITIVE_INFINITY) < 50 &&
|
|
1409
1428
|
lastStopReason === undefined &&
|
|
@@ -1451,14 +1470,15 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1451
1470
|
if (salvaged?.runId === undefined)
|
|
1452
1471
|
delete rec.taskRunId;
|
|
1453
1472
|
if (salvaged !== undefined) {
|
|
1454
|
-
|
|
1473
|
+
const salvagedFace = terminalProjection(salvaged.terminal);
|
|
1474
|
+
rec.taskStatus = salvagedFace.status;
|
|
1455
1475
|
if (salvaged.sessionId)
|
|
1456
1476
|
rec.sessionId = salvaged.sessionId;
|
|
1457
1477
|
setLegRunId(rec, salvaged);
|
|
1458
|
-
if (
|
|
1459
|
-
rec.errorCode =
|
|
1460
|
-
if (
|
|
1461
|
-
rec.errorMessage = boundedRedactedSummary(
|
|
1478
|
+
if (salvagedFace.errorCode !== undefined)
|
|
1479
|
+
rec.errorCode = salvagedFace.errorCode;
|
|
1480
|
+
if (salvagedFace.errorMessage !== undefined && salvagedFace.errorMessage !== "")
|
|
1481
|
+
rec.errorMessage = boundedRedactedSummary(salvagedFace.errorMessage, MAX_TRANSCRIPT_CHARS);
|
|
1462
1482
|
rec.output = boundedRedactedSummary(salvaged.structuredOutput ?? salvaged.result, MAX_TRANSCRIPT_CHARS) || (rec.errorMessage ?? "");
|
|
1463
1483
|
rec.stats = { tokens: salvaged.stats.tokens ?? 0, turns: salvaged.stats.turns ?? 0, costMicroUsd: salvaged.stats.costMicroUsd };
|
|
1464
1484
|
}
|
|
@@ -1479,10 +1499,12 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1479
1499
|
const journaled = journalAppend(callKey, salvaged ?? {
|
|
1480
1500
|
taskId: callKey,
|
|
1481
1501
|
sessionId: "",
|
|
1482
|
-
status: "failed",
|
|
1483
1502
|
result: boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500),
|
|
1484
|
-
|
|
1485
|
-
|
|
1503
|
+
terminal: {
|
|
1504
|
+
kind: "failed",
|
|
1505
|
+
...(err instanceof WorkflowAgentBlockedError ? { code: WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } : err instanceof WorkflowBudgetExceededError ? { code: err.code } : {}),
|
|
1506
|
+
message: boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500),
|
|
1507
|
+
},
|
|
1486
1508
|
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1487
1509
|
}, label).catch(() => undefined);
|
|
1488
1510
|
if (!(err instanceof WorkflowBudgetExceededError && rec.startedAt === undefined))
|
|
@@ -1496,7 +1518,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1496
1518
|
}
|
|
1497
1519
|
if (finalized)
|
|
1498
1520
|
return result;
|
|
1499
|
-
if (isDurablePause(result.
|
|
1521
|
+
if (isDurablePause(result.terminal)) {
|
|
1500
1522
|
result = mapNestedSuspend(result);
|
|
1501
1523
|
}
|
|
1502
1524
|
await settleAgentResult(rec, result, activityTail, agentOpts, "awaited");
|
|
@@ -1548,9 +1570,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1548
1570
|
void journalAppend(callKey, {
|
|
1549
1571
|
taskId: callKey,
|
|
1550
1572
|
sessionId: "",
|
|
1551
|
-
|
|
1573
|
+
terminal: { kind: "failed", code: refusal.code, message: boundedRedactedSummary(refusal.message, 500) },
|
|
1552
1574
|
result: boundedRedactedSummary(refusal.message, 500),
|
|
1553
|
-
errorCode: refusal.code,
|
|
1554
1575
|
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1555
1576
|
}).catch(() => undefined);
|
|
1556
1577
|
throw refusal;
|
|
@@ -1607,9 +1628,8 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1607
1628
|
void journalAppend(callKey, {
|
|
1608
1629
|
taskId: callKey,
|
|
1609
1630
|
sessionId: "",
|
|
1610
|
-
|
|
1631
|
+
terminal: { kind: "failed", code: WORKFLOW_SPAWN_BLOCKED_ERROR_CODE, message: boundedRedactedSummary(err.message, 500) },
|
|
1611
1632
|
result: boundedRedactedSummary(err.message, 500),
|
|
1612
|
-
errorCode: WORKFLOW_SPAWN_BLOCKED_ERROR_CODE,
|
|
1613
1633
|
stats: { turns: 0, tokens: 0, costMicroUsd: 0 },
|
|
1614
1634
|
}).catch(() => undefined);
|
|
1615
1635
|
}
|
|
@@ -1658,7 +1678,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1658
1678
|
void journalAppend(callKey, {
|
|
1659
1679
|
taskId: callKey,
|
|
1660
1680
|
sessionId: "",
|
|
1661
|
-
|
|
1681
|
+
terminal: { kind: "failed", message: boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500) },
|
|
1662
1682
|
result: boundedRedactedSummary(err instanceof Error ? err.message : String(err), 500),
|
|
1663
1683
|
stats: { turns: partialSpend?.turns ?? 0, tokens: partialSpend?.tokens ?? 0, costMicroUsd: partialSpend?.costMicroUsd ?? 0 },
|
|
1664
1684
|
}).catch(() => undefined);
|
|
@@ -1670,7 +1690,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1670
1690
|
releaseOnce();
|
|
1671
1691
|
if (finalized)
|
|
1672
1692
|
return result;
|
|
1673
|
-
if (isDurablePause(result.
|
|
1693
|
+
if (isDurablePause(result.terminal)) {
|
|
1674
1694
|
result = mapNestedSuspend(result);
|
|
1675
1695
|
}
|
|
1676
1696
|
await settleAgentResult(rec, result, activityTail, agentOpts, "best-effort");
|
|
@@ -1828,8 +1848,13 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1828
1848
|
"state (or stop it) and resume again.");
|
|
1829
1849
|
}
|
|
1830
1850
|
const entries = await journalStore.load(opts.resumeFromRunId, scope);
|
|
1831
|
-
for (const e of entries)
|
|
1851
|
+
for (const e of entries) {
|
|
1852
|
+
const t = e.result?.terminal;
|
|
1853
|
+
if (t === null || typeof t !== "object" || !isTerminalCauseKind(t.kind)) {
|
|
1854
|
+
throw new WorkflowJournalIncompatibleError(clampRunIdText(opts.resumeFromRunId), callKeyOrdinal(e.callKey));
|
|
1855
|
+
}
|
|
1832
1856
|
replayByOrdinal[callKeyOrdinal(e.callKey)] = e;
|
|
1857
|
+
}
|
|
1833
1858
|
run.resume = {
|
|
1834
1859
|
fromRunId: clampRunIdText(opts.resumeFromRunId),
|
|
1835
1860
|
journalEntries: entries.length,
|
|
@@ -49,7 +49,7 @@ export declare const SUPERVISOR_PROMPT = "You are a supervisor \u2014 the delega
|
|
|
49
49
|
* This block is strategy-blind (it is composed from the prompt context, which carries no strategy
|
|
50
50
|
* fact), so it must not promise the arm that only one strategy delivers. */
|
|
51
51
|
export declare const ORCHESTRATION_GUIDANCE_DEFERRED = "You can author and run your own WORKFLOW via the Workflow tool (multi-agent orchestration). Its schema and how-to are deferred: when a task genuinely needs orchestration, activate the tool (see the deferred-tools note) and work from what the activation returns.";
|
|
52
|
-
export declare const ORCHESTRATION_GUIDANCE = "You can author and run your own WORKFLOW via the Workflow tool \u2014 a\ndeterministic JS script that spawns and coordinates sub-agents. Use it to be more thorough (decompose and\ncover in parallel), more confident (independent perspectives + adversarial checks before committing), or to\nhandle scale one context can't hold. This is a power tool: reach for it on a SUBSTANTIAL task that genuinely\ndecomposes \u2014 for a simple or sequential task, just do the work directly. Over-orchestrating a trivial task\nwastes tokens and adds latency.\n\nHow a workflow script works (the contract):\n- It begins with `export const meta = { name, description, phases }` \u2014 a PURE LITERAL (no variables, calls,\n or template strings). Use the same phase titles in meta.phases as in your phase() calls and in each\n agent's opts `phase`.\n- \uD83D\uDD34 After the meta line, write the body as TOP-LEVEL async statements \u2014 the primitives are already in\n scope. Do NOT wrap the body in `export default`, a function, or a `body()` method; do NOT use\n `import`/`require`; do NOT put the script inside markdown code fences. End with `return <value>`.\n The script IS the function body. A complete example \u2014 copy this SHAPE exactly:\n\n export const meta = { name: 'risk-scan', description: 'list risks in parallel', phases: [{ title: 'scan' }] }\n const results = await parallel([\n () => agent({ objective: 'Name one risk of X. Reply in one short sentence.' }, { label: 'scan-risk-a', phase: 'scan' }),\n () => agent({ objective: 'Name a DIFFERENT risk of X. Reply in one short sentence.' }, { label: 'scan-risk-b', phase: 'scan' }),\n ])\n return results.filter((r) => r && r.
|
|
52
|
+
export declare const ORCHESTRATION_GUIDANCE = "You can author and run your own WORKFLOW via the Workflow tool \u2014 a\ndeterministic JS script that spawns and coordinates sub-agents. Use it to be more thorough (decompose and\ncover in parallel), more confident (independent perspectives + adversarial checks before committing), or to\nhandle scale one context can't hold. This is a power tool: reach for it on a SUBSTANTIAL task that genuinely\ndecomposes \u2014 for a simple or sequential task, just do the work directly. Over-orchestrating a trivial task\nwastes tokens and adds latency.\n\nHow a workflow script works (the contract):\n- It begins with `export const meta = { name, description, phases }` \u2014 a PURE LITERAL (no variables, calls,\n or template strings). Use the same phase titles in meta.phases as in your phase() calls and in each\n agent's opts `phase`.\n- \uD83D\uDD34 After the meta line, write the body as TOP-LEVEL async statements \u2014 the primitives are already in\n scope. Do NOT wrap the body in `export default`, a function, or a `body()` method; do NOT use\n `import`/`require`; do NOT put the script inside markdown code fences. End with `return <value>`.\n The script IS the function body. A complete example \u2014 copy this SHAPE exactly:\n\n export const meta = { name: 'risk-scan', description: 'list risks in parallel', phases: [{ title: 'scan' }] }\n const results = await parallel([\n () => agent({ objective: 'Name one risk of X. Reply in one short sentence.' }, { label: 'scan-risk-a', phase: 'scan' }),\n () => agent({ objective: 'Name a DIFFERENT risk of X. Reply in one short sentence.' }, { label: 'scan-risk-b', phase: 'scan' }),\n ])\n return results.filter((r) => r && r.terminal.kind === 'completed').map((r) => r.result)\n\n- The body is async and uses these injected primitives:\n - agent(spec, opts?) \u2014 run one sub-agent. spec is { objective: string (USE `objective`, not `goal`),\n modelName?, thinking?, systemPrompt? }; opts is { schema?, label?, phase?, isolation? } (schema goes in\n OPTS, not in spec). ALWAYS pass a short kebab-case `label` naming what THIS agent does (e.g.\n { label: 'find-dead-code' }) \u2014 label/phase go in OPTS, never inside spec (a spec-side label is ignored);\n unlabeled agents render as anonymous agent-N rows in the monitor. Set opts `phase` to one of your\n meta.phases titles so the agent groups under its stage.\n `isolation: \"worktree\"` runs the agent in its own isolated git worktree \u2014 use it ONLY\n when concurrent agents WRITE THE SAME repo/files and must not clobber each other (a separate working copy,\n not merely several agents). Returns the task result \u2014 read `r.result` (text) or `r.structuredOutput`\n (when you passed {schema}). agent() does NOT throw when the sub-agent fails \u2014 it RETURNS the result\n with `r.terminal` set (`r.terminal.kind` is 'completed' | 'failed' | 'blocked' | 'paused'); ALWAYS check\n `r.terminal.kind` and GATE later phases on it (the Workflow tool card shows the full gate pattern).\n - parallel(thunks) \u2014 run thunks concurrently; BARRIER (awaits all); a thrown thunk resolves to null\n (filter before use). Use when you need all results together.\n - pipeline(items, ...stages) \u2014 each item flows through all stages independently, NO barrier between stages\n (item A can be in stage 3 while B is in stage 1). DEFAULT for multi-stage work. Each stage gets\n (prevResult, originalItem, index). A stage that throws drops that item to null.\n - phase(title, body) \u2014 group work under a named phase (shows in /workflows).\n - budget \u2014 { total, spent(), remaining() }; once spend reaches total, agent() throws. Loop on\n budget.remaining() for budget-scaled depth \u2014 but GUARD the loop on budget.total: with no budget set,\n remaining() returns Infinity and the loop runs straight into the agent cap (add a hard iteration cap).\n spent() moves when an agent SETTLES (authoritative accounting); the live per-turn figures you may see\n in run observability are display-only and never charge the budget gate.\n - log(message) \u2014 emit a progress line.\n - args \u2014 the JSON value passed to Workflow.\n- The script returns a value; you are notified when it completes and can read the result + the run via the\n workflow observability.\n\nDiscipline (this is where orchestration earns its cost):\n- DEFAULT TO pipeline(). Only use parallel() (a barrier) when a stage genuinely needs ALL prior results at\n once (dedup/merge across the full set, early-exit on zero, cross-item comparison). Otherwise pipeline so a\n fast item isn't blocked by a slow one.\n- Give each sub-agent a CLEAR goal + output spec + boundary, so they don't duplicate or conflict. A vague\n delegation produces duplicated or off-scope work. Detailed sub-task instructions matter.\n- Be confident, not just fast: for findings that must be right, spawn INDEPENDENT verifiers prompted to\n REFUTE (default to refuted if uncertain) and keep a finding only if it survives. Diverse lenses\n (correctness / security / does-it-reproduce) catch failure modes redundancy can't. When workers fan out, a\n single bad conclusion gets amplified \u2014 verify before you commit to it.\n- Scale to the task: a quick check needs a couple of agents; \"be comprehensive / audit thoroughly\" warrants a\n larger finder pool + an adversarial verify pass. Don't fan out wider than the task needs.\n\nYou operate under hard caps (a runaway script is bounded, not trusted): a token budget, a concurrency limit,\nper-agent and total timeouts, a max agent count, and a nesting limit of ONE level (a workflow's agent cannot\nitself start another workflow). Every sub-agent you spawn runs under the deployment's permission/approval/\nsafety policy \u2014 you may inherit or TIGHTEN it for a sub-agent, never loosen it. Work within these; they are\nthe safety net that lets you be trusted with this power.";
|
|
53
53
|
/**
|
|
54
54
|
* Goal-mode completion guidance, composed when goal mode is enabled (design/96 C 节 LLM-self-report gate).
|
|
55
55
|
* Red line (G1, design/96 §定.0): declaring "done" STOPS iteration and surfaces for review (the completion
|
|
@@ -53,7 +53,7 @@ How a workflow script works (the contract):
|
|
|
53
53
|
() => agent({ objective: 'Name one risk of X. Reply in one short sentence.' }, { label: 'scan-risk-a', phase: 'scan' }),
|
|
54
54
|
() => agent({ objective: 'Name a DIFFERENT risk of X. Reply in one short sentence.' }, { label: 'scan-risk-b', phase: 'scan' }),
|
|
55
55
|
])
|
|
56
|
-
return results.filter((r) => r && r.
|
|
56
|
+
return results.filter((r) => r && r.terminal.kind === 'completed').map((r) => r.result)
|
|
57
57
|
|
|
58
58
|
- The body is async and uses these injected primitives:
|
|
59
59
|
- agent(spec, opts?) — run one sub-agent. spec is { objective: string (USE \`objective\`, not \`goal\`),
|
|
@@ -66,8 +66,8 @@ How a workflow script works (the contract):
|
|
|
66
66
|
when concurrent agents WRITE THE SAME repo/files and must not clobber each other (a separate working copy,
|
|
67
67
|
not merely several agents). Returns the task result — read \`r.result\` (text) or \`r.structuredOutput\`
|
|
68
68
|
(when you passed {schema}). agent() does NOT throw when the sub-agent fails — it RETURNS the result
|
|
69
|
-
with \`r.
|
|
70
|
-
shows the full gate pattern).
|
|
69
|
+
with \`r.terminal\` set (\`r.terminal.kind\` is 'completed' | 'failed' | 'blocked' | 'paused'); ALWAYS check
|
|
70
|
+
\`r.terminal.kind\` and GATE later phases on it (the ${RUN_WORKFLOW_TOOL_NAME} tool card shows the full gate pattern).
|
|
71
71
|
- parallel(thunks) — run thunks concurrently; BARRIER (awaits all); a thrown thunk resolves to null
|
|
72
72
|
(filter before use). Use when you need all results together.
|
|
73
73
|
- pipeline(items, ...stages) — each item flows through all stages independently, NO barrier between stages
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* yet implemented). The model pairing (who's cheap / who's strong / heterogeneous decorrelation) is
|
|
12
12
|
* deploy-side knowledge — core fills guard-number defaults + prompts + orchestrator choice, never the model.
|
|
13
13
|
*/
|
|
14
|
-
import type {
|
|
14
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
15
15
|
import type { ModelRef, ModelRole, TaskSpec } from "../core/types.js";
|
|
16
16
|
import { type TeamResult } from "../agents/team.js";
|
|
17
17
|
import { type VerificationResult } from "../agents/verify.js";
|
|
@@ -59,7 +59,7 @@ export interface ScenarioProfile {
|
|
|
59
59
|
export declare const SCENARIO_REGISTRY: Record<ScenarioId, ScenarioProfile>;
|
|
60
60
|
export interface RunScenarioOptions {
|
|
61
61
|
scenario: ScenarioId;
|
|
62
|
-
runner:
|
|
62
|
+
runner: RunnerSelfSeat;
|
|
63
63
|
/** What the scenario operates on — the team `topic` (design/code review) or the solo task objective. */
|
|
64
64
|
objective: string;
|
|
65
65
|
/**
|
|
@@ -83,7 +83,7 @@ export interface RunScenarioOptions {
|
|
|
83
83
|
/** Per-scenario result union — each entry returns its orchestrator's native result shape. */
|
|
84
84
|
export type RunScenarioResult = {
|
|
85
85
|
scenario: "solo";
|
|
86
|
-
result: Awaited<ReturnType<
|
|
86
|
+
result: Awaited<ReturnType<RunnerSelfSeat["runTask"]>>;
|
|
87
87
|
} | {
|
|
88
88
|
scenario: "design-review";
|
|
89
89
|
result: TeamResult;
|
|
@@ -125,7 +125,7 @@ async function runCodeReviewVerify(opts) {
|
|
|
125
125
|
const reviewed = {
|
|
126
126
|
taskId: "code-review",
|
|
127
127
|
sessionId: "code-review",
|
|
128
|
-
|
|
128
|
+
terminal: { kind: "completed" },
|
|
129
129
|
result: opts.objective,
|
|
130
130
|
stats: { turns: 0, tokens: 0 },
|
|
131
131
|
};
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* defaults only. The guard defaults are NOT re-stated here: we let teacher.ts own them (single source of
|
|
11
11
|
* truth, no drift).
|
|
12
12
|
*/
|
|
13
|
-
import type {
|
|
13
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
14
14
|
import type { ModelRef, TaskSpec } from "../core/types.js";
|
|
15
15
|
import { type TeacherRunResult } from "../agents/teacher.js";
|
|
16
16
|
export interface TeacherModePair {
|
|
@@ -25,7 +25,7 @@ export interface TeacherModePair {
|
|
|
25
25
|
* student task spec's `model`. All guards use teacher.ts's built-in defaults (not re-stated here, so core
|
|
26
26
|
* owns the single source of truth). The caller supplies only the two models + the task spec.
|
|
27
27
|
*/
|
|
28
|
-
export declare function teacherMode(runner:
|
|
28
|
+
export declare function teacherMode(runner: RunnerSelfSeat, spec: TaskSpec, pair: TeacherModePair): Promise<TeacherRunResult>;
|
|
29
29
|
/**
|
|
30
30
|
* Teacher-mode preset profile (G2: a profile = which two models to fill). The two model cells are role-name
|
|
31
31
|
* placeholders the deploy side maps to concrete models (core never guesses); guard defaults are NOT pinned
|
package/dist/server/http.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import type { IncomingMessage } from "node:http";
|
|
3
|
-
import type {
|
|
3
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
4
4
|
import type { ImageInput, TaskSpec } from "../core/types.js";
|
|
5
5
|
/** Inbound request body. Tool *code* can never come over the wire — the server injects tools via resolveSpec. */
|
|
6
6
|
export interface TaskRequestBody {
|
|
@@ -10,7 +10,7 @@ export interface TaskRequestBody {
|
|
|
10
10
|
[key: string]: unknown;
|
|
11
11
|
}
|
|
12
12
|
export interface TaskServerOptions {
|
|
13
|
-
runner:
|
|
13
|
+
runner: RunnerSelfSeat;
|
|
14
14
|
/**
|
|
15
15
|
* Map an inbound request body to a full TaskSpec. This is where the SERVER decides the model,
|
|
16
16
|
* tools, MCP servers, system prompt, and limits for the request. The body only supplies content
|