@sema-agent/core 7.6.0 → 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 +26 -0
- package/dist/agents/agent-transcript-tool.d.ts +2 -2
- package/dist/agents/cascade.d.ts +2 -3
- package/dist/agents/repair-loop.d.ts +2 -2
- 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 +3 -4
- package/dist/agents/teacher.d.ts +2 -2
- package/dist/agents/team.d.ts +2 -2
- package/dist/agents/verify.d.ts +5 -6
- package/dist/core/agent-definition.d.ts +172 -0
- package/dist/core/agent-definition.js +1 -0
- 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/hands-band.d.ts +134 -0
- package/dist/core/hands-band.js +1 -0
- package/dist/core/hooks.d.ts +20 -101
- package/dist/core/hooks.js +53 -854
- package/dist/core/mcp-failure.d.ts +43 -5
- package/dist/core/mcp-failure.js +31 -14
- package/dist/core/mcp-server-spec.d.ts +217 -0
- package/dist/core/mcp-server-spec.js +1 -0
- package/dist/core/model-seat.d.ts +99 -0
- package/dist/core/model-seat.js +1 -0
- package/dist/core/reminder-mint.d.ts +10 -0
- package/dist/core/reminder-mint.js +3 -0
- package/dist/core/runner/contracts.d.ts +382 -6
- package/dist/core/runner/gate-exit.d.ts +177 -9
- package/dist/core/runner/gate-exit.js +70 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +2 -7
- package/dist/core/runner/prepare-task.d.ts +2 -2
- package/dist/core/runner/runtask.d.ts +4 -71
- package/dist/core/runner/runtask.js +14 -5
- 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/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/tool-spec.d.ts +1174 -0
- package/dist/core/tool-spec.js +1 -0
- package/dist/core/types.d.ts +26 -7691
- package/dist/core/types.js +2 -76
- package/dist/core/warm-resume.d.ts +2 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/orchestration/goal.d.ts +2 -2
- package/dist/orchestration/run-spec.d.ts +2 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -3
- package/dist/orchestration/workflow.d.ts +4 -4
- package/dist/scenarios/scenario-registry.d.ts +3 -3
- 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 +1 -1
- package/test/export-surface.snapshot.json +9 -1
package/dist/core/types.js
CHANGED
|
@@ -1,76 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export function __resetMalformedDelegationSeatAnnouncement() {
|
|
4
|
-
malformedDelegationSeatAnnounced = false;
|
|
5
|
-
}
|
|
6
|
-
export function deliverDelegationLifecycle(seat, event, notifier, site) {
|
|
7
|
-
if (typeof seat === "function") {
|
|
8
|
-
const frame = Object.freeze(Object.assign(Object.create(null), event));
|
|
9
|
-
notifier.notify(() => observeThenableRejection(seat(frame), notifier, site), site);
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
if (seat !== undefined && !malformedDelegationSeatAnnounced) {
|
|
13
|
-
malformedDelegationSeatAnnounced = true;
|
|
14
|
-
try {
|
|
15
|
-
console.warn(`The delegation-lifecycle sink (RunnerDeps.onDelegationLifecycle) holds ${seat === null ? "null" : typeof seat} — not a ` +
|
|
16
|
-
`function. Delegation spawn/terminal frames are NOT delivered until the wiring is fixed (omit the key, or wire a function).`);
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
let malformedNoticeSeatAnnounced = false;
|
|
23
|
-
export function __resetMalformedNoticeSeatAnnouncement() {
|
|
24
|
-
malformedNoticeSeatAnnounced = false;
|
|
25
|
-
}
|
|
26
|
-
export function deliverEngineNotice(onNotice, notice) {
|
|
27
|
-
if (notice.sessionId === undefined && typeof notice.detail?.["sessionId"] === "string") {
|
|
28
|
-
notice = { ...notice, sessionId: notice.detail["sessionId"] };
|
|
29
|
-
}
|
|
30
|
-
if (typeof onNotice === "function") {
|
|
31
|
-
try {
|
|
32
|
-
const r = onNotice(notice);
|
|
33
|
-
if (typeof r?.then === "function") {
|
|
34
|
-
r.then(undefined, () => {
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
catch {
|
|
39
|
-
}
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
if (onNotice !== undefined) {
|
|
43
|
-
if (!malformedNoticeSeatAnnounced) {
|
|
44
|
-
malformedNoticeSeatAnnounced = true;
|
|
45
|
-
try {
|
|
46
|
-
console.warn(`The structured notice sink (RunnerDeps.onNotice) holds ${onNotice === null ? "null" : typeof onNotice} — not a ` +
|
|
47
|
-
`function. Notices fall back to console.warn until the wiring is fixed (omit the key, or wire a function).`);
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
console.warn(notice.message);
|
|
54
|
-
}
|
|
55
|
-
export function undrainedUserInputNotices(counts, taskId, sessionId, runId) {
|
|
56
|
-
const tid = taskId !== undefined ? { taskId } : {};
|
|
57
|
-
const sid = sessionId !== undefined ? { sessionId } : {};
|
|
58
|
-
const rid = runId !== undefined ? { runId } : {};
|
|
59
|
-
const tail = `accepted as "queued" were never consumed — the run ended first. They are NOT redelivered; re-send against a live run if still wanted.`;
|
|
60
|
-
const out = [];
|
|
61
|
-
if (counts.steer > 0) {
|
|
62
|
-
out.push({
|
|
63
|
-
code: "task.user_steer_undrained",
|
|
64
|
-
message: `${counts.steer} user steer(s) ${tail}`,
|
|
65
|
-
detail: { steer: counts.steer, ...tid, ...sid, ...rid },
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
if (counts.followUp > 0) {
|
|
69
|
-
out.push({
|
|
70
|
-
code: "task.user_followup_undrained",
|
|
71
|
-
message: `${counts.followUp} user follow-up(s) ${tail}`,
|
|
72
|
-
detail: { followUp: counts.followUp, ...tid, ...sid, ...rid },
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
return out;
|
|
76
|
-
}
|
|
1
|
+
export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
|
|
2
|
+
export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, undrainedUserInputNotices } from "./engine-notice.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RunnerSelfSeat } from "./runner/contracts.js";
|
|
2
2
|
import type { TaskResult, TaskSpec } from "./types.js";
|
|
3
3
|
/**
|
|
4
4
|
* design/114 P0 — a convenience for the RECOMMENDED safe warm-resume of a (failed / timed-out) run: FORK the
|
|
@@ -17,6 +17,6 @@ import type { TaskResult, TaskSpec } from "./types.js";
|
|
|
17
17
|
* the directive for picking up the work; pass the model (and any other spec fields) via `opts` — a continuation
|
|
18
18
|
* still needs a model like any task.
|
|
19
19
|
*/
|
|
20
|
-
export declare function warmResume(runner:
|
|
20
|
+
export declare function warmResume(runner: RunnerSelfSeat, sessionId: string, objective: string, opts?: Omit<Partial<TaskSpec>, "objective" | "sessionId"> & {
|
|
21
21
|
owner?: string | null;
|
|
22
22
|
}): Promise<TaskResult | null>;
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
export { Runner, runTask } from "./core/runner/runtask.js";
|
|
9
9
|
export { resolveTaskLimits } from "./core/runner/prepare-task.js";
|
|
10
10
|
export type { RunInternals, ResolvedWorkspace } from "./core/runner/prepare-task.js";
|
|
11
|
+
export type { RunnerSelfSeat } from "./core/runner/contracts.js";
|
|
11
12
|
export type { BudgetAxis } from "./core/runner/assemble-result.js";
|
|
12
13
|
export { terminalProjection } from "./core/runner/terminal-projection.js";
|
|
13
14
|
export { SESSION_LOG_DIGEST_SCHEME, sessionEntryDigest, sessionLogDigest, sessionLogDigestsComparable, } from "./engine/session/log-digest.js";
|
|
@@ -113,7 +114,7 @@ export type { FileHistoryStore, FileHistoryResult, FileHistoryTrackResult, FileH
|
|
|
113
114
|
export type { InMemoryFileHistoryStoreOptions } from "./core/file-history-store.js";
|
|
114
115
|
export { DEFAULT_FILE_HISTORY_BOUNDARY_KEEP, resolveFileHistoryRetention, fileHistoryBoundariesToKeep } from "./core/file-history-retention.js";
|
|
115
116
|
export type { FileHistoryRetentionPolicy } from "./core/file-history-retention.js";
|
|
116
|
-
export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileStrategyStore, FileFileHistoryStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, FileStoreLockError, type FileStoreLockErrorCode, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileStrategyStoreOptions, type FileFileHistoryStoreOptions, type FileSessionRepoOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
|
|
117
|
+
export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileStrategyStore, FileFileHistoryStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, FileStoreLockError, type FileStoreLockErrorCode, processFingerprint, isProcessLive, type ProcessFingerprint, type FileStorageBackendOptions, type FileStorageCorruptReadInfo, type FileStrategyStoreOptions, type FileFileHistoryStoreOptions, type FileSessionRepoOptions, type FileCheckpointStoreOptions, } from "./stores/file/index.js";
|
|
117
118
|
export { CacheBreakDetector, type CacheBreakFinding, type ToolFingerprintInput } from "./core/cache-break-detector.js";
|
|
118
119
|
export { maybeCompact, type MaybeCompactOptions, type CompactionWindowSafetyInfo } from "./core/auto-compaction.js";
|
|
119
120
|
export { brainToRuntime } from "./core/runtime.js";
|
package/dist/index.js
CHANGED
|
@@ -90,7 +90,7 @@ export { worldStillMatchesMint } from "./core/file-history-store.js";
|
|
|
90
90
|
export { trackKeyOf as fileHistoryTrackKeyOf, resolveTrackKey as fileHistoryResolveTrackKey } from "./core/file-history-store.js";
|
|
91
91
|
export { describeTrackKey as fileHistoryDescribeTrackKey, trackKeyFamilyOf as fileHistoryKeyFamilyOf, fileHistoryExportDigest, validateFileHistoryExport } from "./core/file-history-store.js";
|
|
92
92
|
export { DEFAULT_FILE_HISTORY_BOUNDARY_KEEP, resolveFileHistoryRetention, fileHistoryBoundariesToKeep } from "./core/file-history-retention.js";
|
|
93
|
-
export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileStrategyStore, FileFileHistoryStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, FileStoreLockError, } from "./stores/file/index.js";
|
|
93
|
+
export { FileStorageBackend, FileSessionRepo, FileCheckpointStore, FileMemoryStore, FileToolResultStore, FileSessionPolicyStore, FileStrategyStore, FileFileHistoryStore, FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResult, resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock, atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog, FileStoreLockError, processFingerprint, isProcessLive, } from "./stores/file/index.js";
|
|
94
94
|
export { CacheBreakDetector } from "./core/cache-break-detector.js";
|
|
95
95
|
export { maybeCompact } from "./core/auto-compaction.js";
|
|
96
96
|
export { brainToRuntime } from "./core/runtime.js";
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* **无任何 commit/accept 副作用**(纯 loop,同 runRepairLoop SAFE-tier 永不 `fixed`)。要 accept,caller 自走
|
|
12
12
|
* design/77 Gate-1 out-of-process oracle 隔离边界,不在 goal helper 开后门。
|
|
13
13
|
*/
|
|
14
|
-
import type {
|
|
14
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
15
15
|
import type { CheckpointToken } from "../core/checkpoint-store.js";
|
|
16
16
|
import type { TaskResult, TaskSpec } from "../core/types.js";
|
|
17
17
|
/** Read-only snapshot a `doneCheck` sees after one iteration. */
|
|
@@ -103,4 +103,4 @@ export declare const DECLARE_DONE_TOOL_NAME = "DeclareDone";
|
|
|
103
103
|
* doneCheck feeds its reason back (fenced) and continues. Bounded by maxIterations / budget / wall-clock /
|
|
104
104
|
* cancel; a durable pause (suspended/needs_review) is a hard boundary that surfaces the checkpointToken.
|
|
105
105
|
*/
|
|
106
|
-
export declare function runGoal(runner:
|
|
106
|
+
export declare function runGoal(runner: RunnerSelfSeat, spec: GoalSpec): Promise<GoalResult>;
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* 生命周期(调用方保证起点是干净树 —— preflight 红才有意义)、模型/Runner 装配、chaos 包装。frozen 写入
|
|
26
26
|
* 面:policy 只挡 Write/Edit 族 = belt;bash 写入由快照恢复兜(suspenders);危险 bash deny 仍是使用方纪律。
|
|
27
27
|
*/
|
|
28
|
-
import type {
|
|
28
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
29
29
|
import type { TaskResult, TaskSpec } from "../core/types.js";
|
|
30
30
|
import type { TaskOutcome } from "../core/task-outcome.js";
|
|
31
31
|
import { type OracleBaseline, type OracleGateResult, type OracleVerdict, type SpecContract } from "../core/spec-contract.js";
|
|
@@ -59,4 +59,4 @@ export interface RunSpecResult {
|
|
|
59
59
|
* `spec.frozen_path_invalid`, `spec.frozen_missing`, `spec.spec_unreadable`, `spec.not_red`,
|
|
60
60
|
* `spec.oracle_error`.
|
|
61
61
|
*/
|
|
62
|
-
export declare function runSpec(runner: Pick<
|
|
62
|
+
export declare function runSpec(runner: Pick<RunnerSelfSeat, "runTask"> & Partial<Pick<RunnerSelfSeat, "emitTaskOutcome" | "gateBaseline">>, contract: SpecContract, opts: RunSpecOptions): Promise<RunSpecResult>;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { AgentTool } from "../internal/harness-types.js";
|
|
13
13
|
import type { Model } from "../internal/llm.js";
|
|
14
|
-
import type {
|
|
14
|
+
import type { RunnerSelfSeat } from "../core/runner/contracts.js";
|
|
15
15
|
import type { WorkflowGovernanceBaseline } from "../core/types.js";
|
|
16
16
|
import type { WorkflowRunStore } from "../core/workflow-run-store.js";
|
|
17
17
|
import type { WorkflowJournalStore } from "../core/workflow-journal-store.js";
|
|
@@ -128,7 +128,7 @@ export declare function workflowWhenToUseText(m: {
|
|
|
128
128
|
export declare function renderNamedWorkflowListing(entries: ReadonlyArray<NamedWorkflowListing>): string | undefined;
|
|
129
129
|
export interface RunWorkflowToolDeps {
|
|
130
130
|
/** The Runner that executes child tasks (the workflow's `ctx.agent` → `runner.runTask`). */
|
|
131
|
-
runner:
|
|
131
|
+
runner: RunnerSelfSeat;
|
|
132
132
|
/** The HARD sandbox (asserted `safeForUntrustedScripts:true`). */
|
|
133
133
|
scriptRunner: WorkflowScriptRunner;
|
|
134
134
|
/** Deployment-trusted governance every spawned agent inherits (design/98 §2.5). */
|
|
@@ -322,7 +322,7 @@ export interface RunWorkflowToolDeps {
|
|
|
322
322
|
* trusted internals — workflow children inherit the host's evaluated gate exactly like a
|
|
323
323
|
* `createSubagentTool` delegation. (A dep for the same reason as `forwardEvent`: the direct mount's
|
|
324
324
|
* execute ctx is minimal; `ctx.inheritedGateForChildren` still wins when a wrapping path provides it.) */
|
|
325
|
-
inheritedGateForChildren?: () => import("../core/runner/
|
|
325
|
+
inheritedGateForChildren?: () => import("../core/runner/contracts.js").InheritedGate;
|
|
326
326
|
/** RB-201 FO-3 — the HOST session's auto-mode classifier, threaded via `RunWorkflowOptions.autoModeReview`
|
|
327
327
|
* so every child this workflow spawns is reviewed before it starts, exactly like a `createSubagentTool`
|
|
328
328
|
* delegation's child. (A dep for the same reason as `forwardEvent`/`inheritedGateForChildren`: the direct
|
|
@@ -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";
|
|
@@ -452,7 +452,7 @@ export interface RunWorkflowOptions {
|
|
|
452
452
|
* (`RunInternals.inheritedGate`) on both spawn legs (`agent()` and `agentStream()`). Set by the
|
|
453
453
|
* `run_workflow` tool wiring; a directly-started workflow may pass its own. Absent ⇒ children run
|
|
454
454
|
* under only their own gates (pre-seam behavior). TRUSTED: never a script/model argument. */
|
|
455
|
-
inheritedGate?: import("../core/runner/
|
|
455
|
+
inheritedGate?: import("../core/runner/contracts.js").InheritedGate;
|
|
456
456
|
/** RB-201 FO-3 (workflow lane) — the session's auto-mode classifier, consulted BEFORE each script-spawned
|
|
457
457
|
* child starts (objective + toolset + output schema, finalized). The delegation-tool lane reviews its
|
|
458
458
|
* children at one shared point; a workflow's children reach `runner.runTask` through this module instead,
|
|
@@ -553,11 +553,11 @@ export declare const workflowResumeClaimFallback: {
|
|
|
553
553
|
* `done` rejects. `cancel(reason)` aborts the whole run. A nesting/validation violation throws SYNCHRONOUSLY
|
|
554
554
|
* from this call (before any handle exists). Thin composition over `runner.runTask` — no Runner changes.
|
|
555
555
|
*/
|
|
556
|
-
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>;
|
|
557
557
|
/**
|
|
558
558
|
* Run a workflow to completion (design/97 S1a) — the thin await over {@link startWorkflow}: returns the
|
|
559
559
|
* script's value + the assembled {@link WorkflowRun}. A synchronous nesting/validation throw from
|
|
560
560
|
* `startWorkflow` becomes a rejected promise here (this function is `async`), preserving the original
|
|
561
561
|
* `runWorkflow` contract (`await runWorkflow(...)` rejects rather than throwing synchronously).
|
|
562
562
|
*/
|
|
563
|
-
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>>;
|
|
@@ -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;
|
|
@@ -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
|
|
@@ -184,10 +184,11 @@ export declare class FileStoreLockError extends Error {
|
|
|
184
184
|
ownerPid?: number | undefined);
|
|
185
185
|
}
|
|
186
186
|
/**
|
|
187
|
-
* The coarse boot guard (§2.4): an `O_EXCL`
|
|
187
|
+
* The coarse boot guard (§2.4): an `O_EXCL` owner file (`root/LOCK` for the whole data dir; one per store
|
|
188
188
|
* ledger directory via {@link acquireStoreDirLock}) that forbids two processes sharing it. A second
|
|
189
|
-
* instance fails fast ("another instance owns this data dir"). A STALE lock (the
|
|
190
|
-
*
|
|
189
|
+
* instance fails fast ("another instance owns this data dir"). A STALE lock (the process that WROTE it is
|
|
190
|
+
* gone — see {@link isProcessLive}, which is not the same question as "is that pid free") is pruned and
|
|
191
|
+
* re-acquired — `proper-lockfile`/CC `concurrentSessions` parity.
|
|
191
192
|
*
|
|
192
193
|
* This is the family's ONE lock MECHANISM (the per-operation CAS stays in-process: one event loop + a
|
|
193
194
|
* per-token async mutex, so there is NO per-operation flock). A holder of one of these fences guarantees
|
|
@@ -201,7 +202,7 @@ export declare class BootLock {
|
|
|
201
202
|
/** The verdict of the ONE release this holding gets, replayed to any later caller (see {@link release}). */
|
|
202
203
|
private spentVerdict;
|
|
203
204
|
constructor(lockPath: string);
|
|
204
|
-
/** Acquire the lock or throw. Reclaims a lock whose recorded
|
|
205
|
+
/** Acquire the lock or throw. Reclaims a lock whose recorded OWNER is gone (see below). */
|
|
205
206
|
acquire(): void;
|
|
206
207
|
/**
|
|
207
208
|
* @param depth how many stale reclaim gates deep we already are (see the gate below). Bounded so a
|
|
@@ -240,8 +241,8 @@ export declare class BootLock {
|
|
|
240
241
|
*
|
|
241
242
|
* ONE-SHOT, and that is load-bearing. This object stops being a holder the moment it is ASKED to release
|
|
242
243
|
* — before the filesystem is touched — and a second call REPEATS the first verdict instead of acting on
|
|
243
|
-
* it again. A lock file
|
|
244
|
-
* on disk: after a FAILED release the path can legitimately be re-published (a later acquisition here
|
|
244
|
+
* it again. A lock file names its publishing PROCESS, so two BootLocks over one path in this process are
|
|
245
|
+
* byte-identical on disk: after a FAILED release the path can legitimately be re-published (a later acquisition here
|
|
245
246
|
* finishing our cleanup), and a stale object that "removed its own lock" a second time would be deleting
|
|
246
247
|
* the SUCCESSOR's fence while both sides believed they held the directory — the double-writer this whole
|
|
247
248
|
* mechanism exists to refuse, minted from bookkeeping instead of from a race. So a second release answers
|
|
@@ -320,11 +321,86 @@ export declare function acquireStoreDirLock(dir: string, opts: {
|
|
|
320
321
|
* stops two processes consolidating the SAME scope at once (the in-process model the file backend assumes —
|
|
321
322
|
* see {@link BootLock} — does not cover a second OS process with its own timer).
|
|
322
323
|
*
|
|
323
|
-
* `acquire(scope)`
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
324
|
+
* `acquire(scope)` takes a {@link BootLock} over `lockDir/<sanitizedScope>.consolidate.lock`. It returns a
|
|
325
|
+
* `release` callback on success, or `undefined` for EVERY refusal that lock knows how to make — a live
|
|
326
|
+
* owner (including this process: a second pass here is still a conflict), a takeover in flight, an
|
|
327
|
+
* unreadable file — because the caller's whole vocabulary is "busy → skip this pass", a no-op that costs
|
|
328
|
+
* one deferred consolidation. A stale lock is reclaimed by the same protocol as any other, which is the
|
|
329
|
+
* point of not hand-rolling one: this factory used to prune with a bare `unlink` and re-publish, and two
|
|
330
|
+
* passes that had both read the same dead owner would then both prune and both publish — one deleting the
|
|
331
|
+
* other's fresh lock, leaving two processes consolidating the SAME scope, which is exactly what the lock
|
|
332
|
+
* exists to prevent. The reclaim gate serialises that, the depth cap bounds it, and the identity re-read
|
|
333
|
+
* makes sure a reclaim prunes the owner it came for. One lock MECHANISM in this family, not two.
|
|
334
|
+
*
|
|
335
|
+
* The implementation lives HERE (the deployment shell's persist/exec axis), NOT core — core only DEFINES
|
|
336
|
+
* the injection point (the constitutional split: gate-presence in core, mechanism in the profile).
|
|
329
337
|
*/
|
|
330
338
|
export declare function createFileConsolidationLock(lockDir: string): (scope: string) => (() => void) | undefined;
|
|
339
|
+
/**
|
|
340
|
+
* A process identity that survives PID REUSE: a pid, WHEN that pid's process started, and the host the
|
|
341
|
+
* observation was made on.
|
|
342
|
+
*
|
|
343
|
+
* A pid alone is not an identity. The OS hands the same number out again once its holder exits, so a lock
|
|
344
|
+
* (or lease, or any other durable "who owns this" record) carrying only a pid says no more than "somebody
|
|
345
|
+
* with that number" — and after a crash, an unrelated process that inherits the number makes the dead
|
|
346
|
+
* owner's record read as a LIVE owner for as long as that process lives. Adding the START TIME makes the
|
|
347
|
+
* record falsifiable: the pid narrows the candidate to one process, the start time decides whether it is
|
|
348
|
+
* still the SAME one.
|
|
349
|
+
*
|
|
350
|
+
* The start time is carried TWICE, against two different clocks, and that is the whole robustness of the
|
|
351
|
+
* thing. Both numbers come from ONE reading of the process's elapsed time, but one is subtracted from the
|
|
352
|
+
* WALL clock and the other from the host's UPTIME — and a platform that leaves one of them unmoved when
|
|
353
|
+
* the wall clock is corrected moves the other. (Where `ps` measures elapsed time against the boot clock, a
|
|
354
|
+
* corrected wall clock shifts the derived wall-clock start and leaves the uptime-relative one alone; where
|
|
355
|
+
* it measures against a stored absolute start, it is the other way round.) A comparison that insists on
|
|
356
|
+
* BOTH before calling a record stale therefore cannot be talked into a reclaim by a clock correction —
|
|
357
|
+
* which matters because that reclaim would be of a LIVE writer's lock. See {@link isProcessLive}.
|
|
358
|
+
*
|
|
359
|
+
* Both are `null` when this host cannot produce a start time (no `ps`, a cut-down `ps` that rejects the
|
|
360
|
+
* query, a probe too slow for its own reading to be worth anything). That is a plain "unknown" — never a
|
|
361
|
+
* zero and never a guess — and every consumer treats an unobtainable fingerprint as UNFALSIFIABLE, keeping
|
|
362
|
+
* the pid-only verdict: the degrade lands on yesterday's behaviour rather than on a wrong reclaim, and
|
|
363
|
+
* says so out loud once.
|
|
364
|
+
*/
|
|
365
|
+
export interface ProcessFingerprint {
|
|
366
|
+
/** The process id the rest of the record is about. */
|
|
367
|
+
readonly pid: number;
|
|
368
|
+
/** Start of that pid's process against the WALL clock, to the second; `null` when unobtainable here. */
|
|
369
|
+
readonly startedAtMs: number | null;
|
|
370
|
+
/** The same start against this host's UPTIME (ms after boot), to the second; `null` likewise. */
|
|
371
|
+
readonly startedSinceBootMs: number | null;
|
|
372
|
+
/** The host both were read on — a fingerprint from ANOTHER host is comparable to nothing here. */
|
|
373
|
+
readonly host: string;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* The fingerprint of a process: this one when called with no pid, any other pid when named.
|
|
377
|
+
*
|
|
378
|
+
* ONE derivation for both halves of the mechanism — the record a holder WRITES and the probe a later reader
|
|
379
|
+
* verifies it with — on purpose. Deriving our own start time from `process.uptime()` instead would be
|
|
380
|
+
* cheaper, but it measures from Node's own initialisation rather than from the kernel's `exec`, so a busy
|
|
381
|
+
* machine can put the two derivations seconds apart. A reader comparing across them would then read a
|
|
382
|
+
* healthy holder as stale and RECLAIM A LIVE LOCK — a strictly worse failure than the pid reuse this fixes.
|
|
383
|
+
* One derivation makes the tolerance a rounding allowance instead of a guess about bootstrap latency.
|
|
384
|
+
*
|
|
385
|
+
* The self case is memoized: our start time cannot change, the probe is a subprocess, and a lock publish is
|
|
386
|
+
* the only place that needs it — so a process pays for it at most once, whatever it opens.
|
|
387
|
+
*/
|
|
388
|
+
export declare function processFingerprint(pid?: number): ProcessFingerprint;
|
|
389
|
+
/**
|
|
390
|
+
* Is the process a record names still the one that wrote it? ONE predicate, two terms: the pid is running,
|
|
391
|
+
* AND the fingerprint has not been falsified.
|
|
392
|
+
*
|
|
393
|
+
* "Not falsified" is the load-bearing wording, and it is what every degrade lands on. A record with no
|
|
394
|
+
* `startedAtMs` (the pre-fingerprint spelling, or a host that cannot produce one), a record written on
|
|
395
|
+
* ANOTHER host (its start time was measured against a different boot — comparing it here would be
|
|
396
|
+
* arithmetic on unrelated numbers), and a probe that cannot answer all reach the same verdict: LIVE. The
|
|
397
|
+
* asymmetry is deliberate and is the whole safety argument — a false "dead" reclaims a directory out from
|
|
398
|
+
* under a working process (two writers, and the ledger loses whichever rows the loser never loaded), while
|
|
399
|
+
* a false "live" costs a refusal an operator can act on.
|
|
400
|
+
*/
|
|
401
|
+
export declare function isProcessLive(record: {
|
|
402
|
+
readonly pid: number;
|
|
403
|
+
readonly startedAtMs?: number | null;
|
|
404
|
+
readonly startedSinceBootMs?: number | null;
|
|
405
|
+
readonly host?: string | null;
|
|
406
|
+
}): boolean;
|