@cotal-ai/manager 0.44.0 → 0.46.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.
@@ -0,0 +1,114 @@
1
+ import { type RunListRow, type RunStatusView, type SpaceAuth } from "@cotal-ai/core";
2
+ /** What the host needs from the manager: its coordinates and its trust material. */
3
+ export interface RunHostingContext {
4
+ readonly space: string;
5
+ readonly servers: string | undefined;
6
+ /** The endpoint hosting the runs: the manager's own service name. */
7
+ readonly endpoint: string;
8
+ /** The registration instance id, the coordinate a checkpoint's timer schedule is addressed by. */
9
+ readonly instanceId: string;
10
+ /** This manager process, as a checkpoint's holder-bound resume names it. Each attempt's holder
11
+ * id is derived from `id` and the takeover id (see the header). */
12
+ readonly holder: {
13
+ readonly id: string;
14
+ readonly lifecycleUid: string;
15
+ };
16
+ /** The space signer on an auth mesh; undefined on an open mesh (bare connections). */
17
+ readonly auth: SpaceAuth | undefined;
18
+ readonly log: (line: string) => void;
19
+ }
20
+ export declare class RunHosting {
21
+ private readonly ctx;
22
+ private readonly runs;
23
+ private launching;
24
+ private reconciled;
25
+ private stopping;
26
+ constructor(ctx: RunHostingContext);
27
+ /** The one registered run host. Absent means the composition root never imported the runtime,
28
+ * which is a configuration error named here rather than a silent no-op surface. */
29
+ private host;
30
+ /** The boot gate: no launch is served until the reconcile has taken back what a predecessor
31
+ * was driving (see the header). */
32
+ private assertReconciled;
33
+ /** `run-start`: validate, mint the id, launch the drive, answer. The drive continues off-handler. */
34
+ start(args: {
35
+ source: string;
36
+ file?: string;
37
+ timeout?: string;
38
+ }): Promise<{
39
+ runId: string;
40
+ }>;
41
+ /** `run-resume`: take a recorded run over under a fresh takeover and continue it from its journal.
42
+ * The source is the recorded program; a run started before programs were recorded has no
43
+ * hosted resume, and says so. The slot is claimed before the record read, so a second resume
44
+ * arriving during it is a conflict rather than a second attempt. */
45
+ resume(args: {
46
+ runId: string;
47
+ timeout?: string;
48
+ }): Promise<{
49
+ runId: string;
50
+ }>;
51
+ /** `run-answer`: resolve an open checkpoint, or an open `ask` attempt, through the driver's door.
52
+ * Two credentials: a READ that replays the run's journal to the open pause, then an ANSWERING
53
+ * one minted for that pause's token alone, so the writes reach no other pause on the endpoint.
54
+ * `by` is the caller as the manager knows them, decided by the serve layer from the
55
+ * authenticated principal (SPEC 14.5), never read from the request. */
56
+ answer(args: {
57
+ runId: string;
58
+ endpoint?: string;
59
+ stepKey: string;
60
+ value?: unknown;
61
+ artifact?: string;
62
+ }, by: string): Promise<unknown>;
63
+ /** `run-status`: the record plus the journal view. */
64
+ status(args: {
65
+ runId: string;
66
+ endpoint?: string;
67
+ }): Promise<RunStatusView>;
68
+ /** `run-ps`: every run recorded on the endpoint (or every endpoint). */
69
+ list(args: {
70
+ endpoint?: string;
71
+ }): Promise<RunListRow[]>;
72
+ /** Boot: take back every run this endpoint recorded `running`. A dead predecessor's drive left
73
+ * its status at `running`; a successor resumes each one under a fresh takeover. A run with no
74
+ * recorded program is left alone and named: nothing can be resumed without its source. Never
75
+ * fatal to the manager; a run that cannot be taken back is logged, not lost (its journal
76
+ * stands). Opens the boot gate on return, whichever way it went: a reconcile that could not
77
+ * read the store leaves the family serving, since a later resume by hand is the remedy. */
78
+ reconcile(): Promise<void>;
79
+ private takeBack;
80
+ /** Renewal: re-mint every live drive's `run-driver` credential for the SAME nkey and attempt
81
+ * coordinates when it is past its renewal point; the connection presents the fresh one on its
82
+ * next (re)connect. Open mesh: nothing to renew. */
83
+ renew(): Promise<void>;
84
+ /** Shutdown: ask every drive to stop at its next boundary and drain the connections of those
85
+ * that reach one. A drive parked in a pause reaches no boundary; its connection is closed under
86
+ * it, so nothing it writes on the way out can land and its record stays `running`, which is what
87
+ * the next incarnation's reconcile takes back. A slot still launching holds no drive yet; its
88
+ * launch sees `stopping` and closes its own connection. */
89
+ stop(): Promise<void>;
90
+ /** How many drives this incarnation holds; the status surface reads it. */
91
+ get liveCount(): number;
92
+ /** Claim a run's slot SYNCHRONOUSLY: the one place the occupancy rule is decided, with no await
93
+ * between the check and the set. A held slot is a conflict for every later claimant until the
94
+ * attempt that holds it ends. */
95
+ private claim;
96
+ /** Release a slot, only if it is still this attempt's: a later attempt of the same run is a new
97
+ * entry and is never removed by an earlier one's end. */
98
+ private free;
99
+ /** Launch one attempt on a slot. The slot is claimed here when the caller has not already
100
+ * (`start`), and is this launch's to give back from the first line: every refusal below,
101
+ * including the two before a drive is attempted, frees a slot whose drive never started. */
102
+ private launch;
103
+ private drive;
104
+ /** Answer only once this attempt's status is recorded, or the drive has said why it never was:
105
+ * a caller handed an id for a run whose activation then failed would find nothing under it. A
106
+ * run that completes inside the wait has its record and is answered like any other. */
107
+ private activated;
108
+ /** One served read or answer over a one-shot `run-operator` connection (open mesh: bare). The
109
+ * takeover id the rows are minted for is handed to `fn`, so a journal replay inside names the
110
+ * durable the credential admits. Only an answering call holds the answer and settle writes,
111
+ * and those are pinned to the one pause it names. */
112
+ private withOperator;
113
+ }
114
+ //# sourceMappingURL=run-hosting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-hosting.d.ts","sourceRoot":"","sources":["../src/run-hosting.ts"],"names":[],"mappings":"AA+CA,OAAO,EAuBL,KAAK,UAAU,EAGf,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAExB,oFAAoF;AACpF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,kGAAkG;IAClG,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;wEACoE;IACpE,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACxE,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAqBD,qBAAa,UAAU;IAMT,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgC;IACrD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,QAAQ,CAAS;gBAEI,GAAG,EAAE,iBAAiB;IAEnD;wFACoF;IACpF,OAAO,CAAC,IAAI;IAIZ;wCACoC;IACpC,OAAO,CAAC,gBAAgB;IAKxB,qGAAqG;IAC/F,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IA8BlG;;;yEAGqE;IAC/D,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAkCnF;;;;4EAIwE;IAClE,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAyB3I,sDAAsD;IAChD,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC;IAShF,wEAAwE;IAClE,IAAI,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAM9D;;;;;gGAK4F;IACtF,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;YAQlB,QAAQ;IAoCtB;;yDAEqD;IAC/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAe5B;;;;gEAI4D;IACtD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,2EAA2E;IAC3E,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;sCAEkC;IAClC,OAAO,CAAC,KAAK;IAQb;8DAC0D;IAC1D,OAAO,CAAC,IAAI;IAIZ;;iGAE6F;YAC/E,MAAM;YAwBN,KAAK;IA6EnB;;4FAEwF;YAC1E,SAAS;IAoBvB;;;0DAGsD;YACxC,YAAY;CA0B3B"}
@@ -0,0 +1,462 @@
1
+ /**
2
+ * The manager as a WORKFLOW-RUN HOST (SPEC 14.3): where a run's driver lives when nobody's
3
+ * terminal is holding it.
4
+ *
5
+ * The manager serves five commands: `run-start` and `run-resume` hand a program to a driver hosted
6
+ * IN THIS PROCESS and answer with the run id once the attempt's status record is a fact in the
7
+ * store (or with why it never became one); `run-answer` resolves an open checkpoint;
8
+ * `run-status` and `run-ps` read. The manager knows nothing about the language: it resolves the
9
+ * registered {@link RunHost} by name and drives through that contract, so `@cotal-ai/runtime` stays
10
+ * an implementation the manager never imports.
11
+ *
12
+ * Every drive rides its OWN connection under its OWN credential, never the serve connection and
13
+ * never the manager's supervisor identity. On an auth mesh that credential is the per-run,
14
+ * per-takeover `run-driver` profile (SPEC 14.6), minted from the space signer with the attempt's
15
+ * exact coordinates, and re-minted for the same nkey on the renewal loop so a run parked for days
16
+ * outlives the credential's TTL. A served read or answer rides a one-shot `run-operator` credential
17
+ * minted for that one call, so the serve handler's reach over the records store is exactly the
18
+ * call's and expires with it; an answer is two such calls, the read that finds the pause and then
19
+ * a write pinned to that pause's token. An open mesh has no credential system and connects bare.
20
+ *
21
+ * A USER-AUTH mesh hosts no runs, and the manager says so instead of standing this host up: a
22
+ * hosted run's spawns, turns and despawns ride a caller derived from the run id under the static
23
+ * owner, which is no user's, so on a user mesh they would be refused at the manager's own owner
24
+ * check and the program would fail at its first seat. Until a run carries its starting user's
25
+ * owner into that caller, the family is `unimplemented` there, named as such.
26
+ *
27
+ * A manager restart takes its runs back: at boot, every run recorded `running` under this
28
+ * endpoint is resumed under a fresh takeover, epoch + 1, from its recorded program. A run whose
29
+ * predecessor died mid-pause is picked up where its journal says it is; nothing about the crash is
30
+ * recorded as the program's outcome. Until that reconcile has returned, `run-start` and
31
+ * `run-resume` are refused `unavailable`: a resume served while the reconcile is still collecting
32
+ * would launch a second attempt of a run the reconcile is about to take back.
33
+ *
34
+ * ONE ATTEMPT PER RUN, HELD SYNCHRONOUSLY. A run's slot in the live map is claimed before the
35
+ * first await of a launch and released only by that attempt's own end: its drive's completion, or
36
+ * any refusal on the way to one, the admission cap included. So two concurrent resumes, or a
37
+ * resume racing the boot reconcile, cannot both reach the activation barrier, and a refused
38
+ * attempt leaves nothing behind that a later one would read as held. Each attempt
39
+ * also presents its OWN holder id (the manager's endpoint id plus the takeover id): the journal's
40
+ * activation barrier admits an identical (token, holder, epoch) tuple as the same process picking
41
+ * its run back up, so a constant holder id would let two attempts co-activate through that
42
+ * relaxation instead of one being refused.
43
+ */
44
+ import { randomBytes } from "node:crypto";
45
+ import { connect, credsAuthenticator } from "@nats-io/transport-node";
46
+ import { jetstream, jetstreamManager } from "@nats-io/jetstream";
47
+ import { COTAL_LANG_RUN_HOST, DEFAULT_SERVER, EpEnvelopeError, LANG_PROBLEM_DETAIL_KIND, RUN_ACTIVATION_WAIT_MS, RUN_HOST_KIND, inspectCredHealth, mintCreds, newIdentity, newTakeoverId, openRecordsBucket, readRunProgram, readRunRecord, registry, standaloneConnectOpts, walkKvEntries, } from "@cotal-ai/core";
48
+ const DEFAULT_CHECKPOINT_TIMEOUT = "1h";
49
+ /** How many launches (start or resume) may be in their activation wait at once. Each holds a
50
+ * standing connection and a minted credential; past this a caller is refused `resource-exhausted`
51
+ * rather than letting a burst of starts pin unbounded connections for the wait's length. */
52
+ const MAX_LAUNCHING = 8;
53
+ export class RunHosting {
54
+ ctx;
55
+ runs = new Map();
56
+ launching = 0;
57
+ reconciled = false;
58
+ stopping = false;
59
+ constructor(ctx) {
60
+ this.ctx = ctx;
61
+ }
62
+ /** The one registered run host. Absent means the composition root never imported the runtime,
63
+ * which is a configuration error named here rather than a silent no-op surface. */
64
+ host() {
65
+ return registry.resolve(RUN_HOST_KIND, COTAL_LANG_RUN_HOST);
66
+ }
67
+ /** The boot gate: no launch is served until the reconcile has taken back what a predecessor
68
+ * was driving (see the header). */
69
+ assertReconciled() {
70
+ if (!this.reconciled)
71
+ throw new EpEnvelopeError("unavailable", "the manager is still taking back the workflow runs a predecessor was driving; retry shortly (SPEC 14.3)");
72
+ }
73
+ /** `run-start`: validate, mint the id, launch the drive, answer. The drive continues off-handler. */
74
+ async start(args) {
75
+ this.assertReconciled();
76
+ const host = this.host();
77
+ const verdict = host.validate(args.source, args.file);
78
+ if (!verdict.ok) {
79
+ // The refusal carries every problem, as the runtime's own records, so a caller (a person at
80
+ // the CLI, an agent at the tool) can fix the program without a second round-trip. The
81
+ // rendered source frame stays out of it: the caller holds the source, and a refusal is not
82
+ // the place to echo it back.
83
+ throw new EpEnvelopeError("bad-request", `the program does not validate (${verdict.errors.length} problem${verdict.errors.length === 1 ? "" : "s"})`, verdict.errors.map((e) => ({ kind: LANG_PROBLEM_DETAIL_KIND, ...withoutFrame(e) })));
84
+ }
85
+ // Minted here, never caller-supplied: the records table binds run-id minting to the driver.
86
+ // 128 bits, the width the spec's other minted identifiers carry.
87
+ const runId = `run-${randomBytes(16).toString("hex")}`;
88
+ await this.launch(host, {
89
+ mode: "new",
90
+ runId,
91
+ source: args.source,
92
+ ...(args.file !== undefined ? { file: args.file } : {}),
93
+ epoch: 1,
94
+ fencingToken: 1,
95
+ timeout: args.timeout ?? DEFAULT_CHECKPOINT_TIMEOUT,
96
+ });
97
+ return { runId };
98
+ }
99
+ /** `run-resume`: take a recorded run over under a fresh takeover and continue it from its journal.
100
+ * The source is the recorded program; a run started before programs were recorded has no
101
+ * hosted resume, and says so. The slot is claimed before the record read, so a second resume
102
+ * arriving during it is a conflict rather than a second attempt. */
103
+ async resume(args) {
104
+ this.assertReconciled();
105
+ const host = this.host();
106
+ const slot = this.claim(args.runId);
107
+ let found;
108
+ try {
109
+ found = await this.withOperator({ runId: args.runId }, async (_planes, kv) => {
110
+ const record = await readRunRecord(kv, this.ctx.endpoint, args.runId);
111
+ if (record === undefined)
112
+ return undefined;
113
+ const program = await readRunProgram(kv, this.ctx.endpoint, args.runId);
114
+ return { status: record.status?.value, program };
115
+ });
116
+ if (found === undefined)
117
+ throw new EpEnvelopeError("not-found", `run ${args.runId}: no record on endpoint ${this.ctx.endpoint}; a run that was never started cannot be resumed`);
118
+ if (found.program === undefined)
119
+ throw new EpEnvelopeError("failed-precondition", `run ${args.runId}: no program is recorded for it, so a hosted resume has no source to run; drive it from a terminal with \`cotal run resume ${args.runId} --local --file <program>\``);
120
+ }
121
+ catch (e) {
122
+ // Nothing was launched: the slot is this call's to give back.
123
+ this.free(slot);
124
+ throw e;
125
+ }
126
+ // From here the slot is the launch's: every refusal there frees it, or the drive's own end does.
127
+ await this.launch(host, {
128
+ mode: "existing",
129
+ runId: args.runId,
130
+ source: found.program.source,
131
+ ...(found.program.file !== undefined ? { file: found.program.file } : {}),
132
+ epoch: (found.status?.epoch ?? 0) + 1,
133
+ fencingToken: (found.status?.fencingToken ?? 0) + 1,
134
+ timeout: args.timeout ?? DEFAULT_CHECKPOINT_TIMEOUT,
135
+ }, slot);
136
+ return { runId: args.runId };
137
+ }
138
+ /** `run-answer`: resolve an open checkpoint, or an open `ask` attempt, through the driver's door.
139
+ * Two credentials: a READ that replays the run's journal to the open pause, then an ANSWERING
140
+ * one minted for that pause's token alone, so the writes reach no other pause on the endpoint.
141
+ * `by` is the caller as the manager knows them, decided by the serve layer from the
142
+ * authenticated principal (SPEC 14.5), never read from the request. */
143
+ async answer(args, by) {
144
+ const host = this.host();
145
+ const endpoint = args.endpoint ?? this.ctx.endpoint;
146
+ let open;
147
+ try {
148
+ open = await this.withOperator({ endpoint, runId: args.runId }, (planes, _kv, takeoverId) => host.locate(planes, { endpoint, runId: args.runId, takeoverId, stepKey: args.stepKey }));
149
+ }
150
+ catch (e) {
151
+ // The resolver's own refusal is a fact about the run, worded for the caller: no open
152
+ // checkpoint at that key is `not-found`; the plane's own envelope errors pass through.
153
+ if (e instanceof EpEnvelopeError)
154
+ throw e;
155
+ if (e.name === "CheckpointNotOpen")
156
+ throw new EpEnvelopeError("not-found", e.message);
157
+ throw e;
158
+ }
159
+ return await this.withOperator({ endpoint, answers: { token: open.token } }, (planes) => host.answer(planes, {
160
+ endpoint,
161
+ open,
162
+ by,
163
+ ...(args.value !== undefined ? { value: args.value } : {}),
164
+ ...(args.artifact !== undefined ? { artifact: args.artifact } : {}),
165
+ now: Date.now(),
166
+ }));
167
+ }
168
+ /** `run-status`: the record plus the journal view. */
169
+ async status(args) {
170
+ const host = this.host();
171
+ const endpoint = args.endpoint ?? this.ctx.endpoint;
172
+ const view = await this.withOperator({ endpoint, runId: args.runId }, (planes, _kv, takeoverId) => host.status(planes, { endpoint, runId: args.runId, takeoverId }));
173
+ if (view === undefined)
174
+ throw new EpEnvelopeError("not-found", `run ${args.runId}: no record on endpoint ${endpoint}`);
175
+ return view;
176
+ }
177
+ /** `run-ps`: every run recorded on the endpoint (or every endpoint). */
178
+ async list(args) {
179
+ const host = this.host();
180
+ return await this.withOperator({ ...(args.endpoint !== undefined ? { endpoint: args.endpoint } : {}) }, (planes) => host.list(planes, args.endpoint !== undefined ? { endpoint: args.endpoint } : {}));
181
+ }
182
+ /** Boot: take back every run this endpoint recorded `running`. A dead predecessor's drive left
183
+ * its status at `running`; a successor resumes each one under a fresh takeover. A run with no
184
+ * recorded program is left alone and named: nothing can be resumed without its source. Never
185
+ * fatal to the manager; a run that cannot be taken back is logged, not lost (its journal
186
+ * stands). Opens the boot gate on return, whichever way it went: a reconcile that could not
187
+ * read the store leaves the family serving, since a later resume by hand is the remedy. */
188
+ async reconcile() {
189
+ try {
190
+ await this.takeBack();
191
+ }
192
+ finally {
193
+ this.reconciled = true;
194
+ }
195
+ }
196
+ async takeBack() {
197
+ let inherited = [];
198
+ try {
199
+ inherited = await this.withOperator({}, async (_planes, kv) => {
200
+ const out = [];
201
+ for (const e of await walkKvEntries(kv, `run.${this.ctx.endpoint}.*.spec`)) {
202
+ const runId = e.key.split(".")[2];
203
+ if (runId === undefined)
204
+ continue;
205
+ const record = await readRunRecord(kv, this.ctx.endpoint, runId);
206
+ const status = record?.status?.value;
207
+ if (status === undefined || status.state !== "running")
208
+ continue;
209
+ const program = await readRunProgram(kv, this.ctx.endpoint, runId);
210
+ if (program === undefined) {
211
+ this.ctx.log(`! run ${runId} is recorded running with no recorded program; it cannot be taken back here - resume it from a terminal with \`cotal run resume ${runId} --local --file <program>\``);
212
+ continue;
213
+ }
214
+ out.push({ runId, epoch: status.epoch + 1, fencingToken: status.fencingToken + 1, source: program.source, ...(program.file !== undefined ? { file: program.file } : {}) });
215
+ }
216
+ return out;
217
+ });
218
+ }
219
+ catch (e) {
220
+ this.ctx.log(`! workflow-run boot reconcile failed: ${e.message} - runs a predecessor was driving stay parked until the next restart or a \`cotal run resume <runId>\``);
221
+ return;
222
+ }
223
+ if (inherited.length === 0)
224
+ return;
225
+ const host = this.host();
226
+ for (const r of inherited) {
227
+ try {
228
+ await this.launch(host, { mode: "existing", runId: r.runId, source: r.source, ...(r.file !== undefined ? { file: r.file } : {}), epoch: r.epoch, fencingToken: r.fencingToken, timeout: DEFAULT_CHECKPOINT_TIMEOUT });
229
+ }
230
+ catch (e) {
231
+ this.ctx.log(`! run ${r.runId} could not be taken back: ${e.message}`);
232
+ }
233
+ }
234
+ this.ctx.log(`workflow-run boot reconcile: took back ${inherited.length} run(s) recorded running`);
235
+ }
236
+ /** Renewal: re-mint every live drive's `run-driver` credential for the SAME nkey and attempt
237
+ * coordinates when it is past its renewal point; the connection presents the fresh one on its
238
+ * next (re)connect. Open mesh: nothing to renew. */
239
+ async renew() {
240
+ const auth = this.ctx.auth;
241
+ if (!auth)
242
+ return;
243
+ for (const run of this.runs.values()) {
244
+ if (run.creds === undefined || inspectCredHealth(run.creds).state === "healthy")
245
+ continue;
246
+ try {
247
+ run.creds = await mintCreds(auth, run.identity, "run-driver", {
248
+ runDriver: { endpoint: this.ctx.endpoint, runId: run.runId, takeoverId: run.takeoverId, instanceId: this.ctx.instanceId, epoch: run.epoch },
249
+ });
250
+ }
251
+ catch (e) {
252
+ this.ctx.log(`! run-driver renewal for ${run.runId}: ${e.message} - the drive dies at this cred's expiry unless the manager restarts`);
253
+ }
254
+ }
255
+ }
256
+ /** Shutdown: ask every drive to stop at its next boundary and drain the connections of those
257
+ * that reach one. A drive parked in a pause reaches no boundary; its connection is closed under
258
+ * it, so nothing it writes on the way out can land and its record stays `running`, which is what
259
+ * the next incarnation's reconcile takes back. A slot still launching holds no drive yet; its
260
+ * launch sees `stopping` and closes its own connection. */
261
+ async stop() {
262
+ this.stopping = true;
263
+ const live = [...this.runs.values()].filter((r) => r.nc !== undefined && r.drive !== undefined);
264
+ this.runs.clear();
265
+ for (const run of live)
266
+ run.drive.release("the hosting manager is stopping");
267
+ await Promise.all(live.map(async (run) => {
268
+ const reached = await Promise.race([run.drive.done.then(() => true), new Promise((r) => setTimeout(() => r(false), 2_000))]);
269
+ if (reached)
270
+ await run.nc.drain().catch(() => run.nc.close());
271
+ else
272
+ await run.nc.close();
273
+ }));
274
+ }
275
+ /** How many drives this incarnation holds; the status surface reads it. */
276
+ get liveCount() {
277
+ return this.runs.size;
278
+ }
279
+ /** Claim a run's slot SYNCHRONOUSLY: the one place the occupancy rule is decided, with no await
280
+ * between the check and the set. A held slot is a conflict for every later claimant until the
281
+ * attempt that holds it ends. */
282
+ claim(runId) {
283
+ if (this.runs.has(runId))
284
+ throw new EpEnvelopeError("conflict", `run ${runId} is being driven by this manager already`);
285
+ const takeoverId = newTakeoverId();
286
+ const slot = { runId, takeoverId, epoch: 0, identity: newIdentity() };
287
+ this.runs.set(runId, slot);
288
+ return slot;
289
+ }
290
+ /** Release a slot, only if it is still this attempt's: a later attempt of the same run is a new
291
+ * entry and is never removed by an earlier one's end. */
292
+ free(slot) {
293
+ if (this.runs.get(slot.runId) === slot)
294
+ this.runs.delete(slot.runId);
295
+ }
296
+ /** Launch one attempt on a slot. The slot is claimed here when the caller has not already
297
+ * (`start`), and is this launch's to give back from the first line: every refusal below,
298
+ * including the two before a drive is attempted, frees a slot whose drive never started. */
299
+ async launch(host, req, claimed) {
300
+ const slot = claimed ?? this.claim(req.runId);
301
+ try {
302
+ if (this.stopping)
303
+ throw new EpEnvelopeError("unavailable", "the manager is stopping and hosts no new drives");
304
+ if (this.launching >= MAX_LAUNCHING)
305
+ throw new EpEnvelopeError("resource-exhausted", `${MAX_LAUNCHING} workflow runs are launching on this manager already; retry once one has activated`);
306
+ this.launching += 1;
307
+ try {
308
+ await this.drive(host, req, slot);
309
+ }
310
+ finally {
311
+ this.launching -= 1;
312
+ }
313
+ }
314
+ catch (e) {
315
+ // A slot whose drive never started is freed here; one whose drive exists is freed by that
316
+ // drive's own end, so the run reads as held until its attempt has stopped.
317
+ if (slot.drive === undefined)
318
+ this.free(slot);
319
+ throw e;
320
+ }
321
+ }
322
+ async drive(host, req, slot) {
323
+ const { takeoverId, identity } = slot;
324
+ const auth = this.ctx.auth;
325
+ const creds = auth
326
+ ? await mintCreds(auth, identity, "run-driver", {
327
+ runDriver: { endpoint: this.ctx.endpoint, runId: req.runId, takeoverId, instanceId: this.ctx.instanceId, epoch: req.epoch },
328
+ })
329
+ : undefined;
330
+ // The attempt's coordinates on the slot before the connection: the renewal loop re-mints from
331
+ // these, and the epoch is a per-attempt fact.
332
+ const holder = Object.assign(slot, { epoch: req.epoch, ...(creds !== undefined ? { creds } : {}) });
333
+ const enc = new TextEncoder();
334
+ // A STANDING connection: the drive may park for hours inside a pause, so it reconnects without
335
+ // bound and presents whatever credential the renewal loop last minted.
336
+ const nc = await connect({
337
+ servers: this.ctx.servers ?? DEFAULT_SERVER,
338
+ ...(creds !== undefined
339
+ ? { authenticator: (nonce) => credsAuthenticator(enc.encode(holder.creds))(nonce), inboxPrefix: `_INBOX_${identity.id}` }
340
+ : {}),
341
+ maxReconnectAttempts: -1,
342
+ });
343
+ let planes;
344
+ try {
345
+ planes = { nc, js: jetstream(nc), jsm: await jetstreamManager(nc), kv: await openRecordsBucket(nc, this.ctx.space), space: this.ctx.space };
346
+ // Checked AFTER the last await before the drive starts: a stop that landed during the
347
+ // connect has already cleared the live map, and a drive started now would be nobody's.
348
+ if (this.stopping)
349
+ throw new EpEnvelopeError("unavailable", "the manager is stopping and hosts no new drives");
350
+ }
351
+ catch (e) {
352
+ await nc.drain().catch(() => nc.close());
353
+ throw e;
354
+ }
355
+ const max = nc.info?.max_payload;
356
+ // The holder this attempt activates as: this process AND this attempt (see the header).
357
+ const attemptHolder = { id: `${this.ctx.holder.id}.${takeoverId}`, lifecycleUid: this.ctx.holder.lifecycleUid };
358
+ const drive = host.drive(planes, {
359
+ mode: req.mode,
360
+ endpoint: this.ctx.endpoint,
361
+ runId: req.runId,
362
+ source: req.source,
363
+ ...(req.file !== undefined ? { file: req.file } : {}),
364
+ lease: { holder: attemptHolder.id, epoch: req.epoch, fencingToken: req.fencingToken, takeoverId },
365
+ holder: attemptHolder,
366
+ instanceId: this.ctx.instanceId,
367
+ epoch: req.epoch,
368
+ defaultCheckpointTimeout: req.timeout,
369
+ // The broker's own max_payload, minus headroom for the record envelope around the entry.
370
+ ...(typeof max === "number" && max > 4096 ? { resultBytes: max - 4096 } : {}),
371
+ });
372
+ holder.nc = nc;
373
+ holder.drive = drive;
374
+ const activation = this.activated(planes.kv, req, drive);
375
+ void drive.done.then(async (out) => {
376
+ this.ctx.log(`run ${req.runId}: ${describeOutcome(out)}`);
377
+ this.free(holder);
378
+ // The activation wait reads the record over this connection; it finishes before the drain.
379
+ await activation.catch(() => undefined);
380
+ await nc.drain().catch(() => nc.close());
381
+ });
382
+ try {
383
+ await activation;
384
+ }
385
+ catch (e) {
386
+ // An attempt that never activated in time is not left holding a slot and a connection with
387
+ // nobody's word on it: it is released, and a drive that reaches no boundary within a
388
+ // moment has its connection closed under it, the same way a stop treats a parked drive.
389
+ // Its own end then frees the slot.
390
+ drive.release(`the hosting manager gave up waiting for its activation: ${e.message}`);
391
+ const reached = await Promise.race([drive.done.then(() => true), new Promise((r) => setTimeout(() => r(false), 2_000))]);
392
+ if (!reached)
393
+ await nc.close();
394
+ throw e;
395
+ }
396
+ this.ctx.log(`run ${req.runId}: ${req.mode === "new" ? "started" : "resumed"} on endpoint ${this.ctx.endpoint} (epoch ${req.epoch}, takeover ${takeoverId})`);
397
+ }
398
+ /** Answer only once this attempt's status is recorded, or the drive has said why it never was:
399
+ * a caller handed an id for a run whose activation then failed would find nothing under it. A
400
+ * run that completes inside the wait has its record and is answered like any other. */
401
+ async activated(kv, req, drive) {
402
+ const recorded = async () => (await readRunRecord(kv, this.ctx.endpoint, req.runId))?.status?.value.epoch === req.epoch;
403
+ const settled = drive.done.then((out) => ({ out }));
404
+ const deadline = Date.now() + RUN_ACTIVATION_WAIT_MS;
405
+ for (;;) {
406
+ if (await recorded())
407
+ return;
408
+ const early = await Promise.race([settled, new Promise((r) => setTimeout(r, 50))]);
409
+ if (early !== undefined) {
410
+ if (await recorded())
411
+ return;
412
+ throw new EpEnvelopeError(early.out.status === "failed" ? "internal" : "failed-precondition", `run ${req.runId} did not start: ${describeOutcome(early.out)}`);
413
+ }
414
+ if (Date.now() > deadline)
415
+ throw new EpEnvelopeError("unavailable", `run ${req.runId}: its drive has not activated after ${RUN_ACTIVATION_WAIT_MS / 1000}s and was released; \`cotal run ps\` shows what it recorded, and a \`cotal run resume ${req.runId}\` tries again`);
416
+ }
417
+ }
418
+ /** One served read or answer over a one-shot `run-operator` connection (open mesh: bare). The
419
+ * takeover id the rows are minted for is handed to `fn`, so a journal replay inside names the
420
+ * durable the credential admits. Only an answering call holds the answer and settle writes,
421
+ * and those are pinned to the one pause it names. */
422
+ async withOperator(scope, fn) {
423
+ const takeoverId = newTakeoverId();
424
+ const endpoint = scope.endpoint ?? this.ctx.endpoint;
425
+ const auth = this.ctx.auth;
426
+ const nc = await connect({
427
+ servers: this.ctx.servers ?? DEFAULT_SERVER,
428
+ ...(auth
429
+ ? standaloneConnectOpts({
430
+ creds: await mintCreds(auth, newIdentity(), "run-operator", {
431
+ runOperator: { endpoint, takeoverId, ...(scope.runId !== undefined ? { runId: scope.runId } : {}), ...(scope.answers !== undefined ? { answers: scope.answers } : {}) },
432
+ }),
433
+ /* not yet wired to a recorded transport */ tls: false,
434
+ })
435
+ : {}),
436
+ maxReconnectAttempts: 0,
437
+ });
438
+ try {
439
+ const kv = await openRecordsBucket(nc, this.ctx.space);
440
+ return await fn({ nc, js: jetstream(nc), jsm: await jetstreamManager(nc), kv, space: this.ctx.space }, kv, takeoverId);
441
+ }
442
+ finally {
443
+ await nc.drain().catch(() => nc.close());
444
+ }
445
+ }
446
+ }
447
+ /** A validation problem without its rendered source frame (the caller holds the source). */
448
+ function withoutFrame(e) {
449
+ const where = e.where;
450
+ if (where === null || typeof where !== "object")
451
+ return e;
452
+ const { frame: _frame, ...rest } = where;
453
+ return { ...e, where: rest };
454
+ }
455
+ function describeOutcome(out) {
456
+ if (out.status === "completed")
457
+ return `completed in ${out.steps} step(s)`;
458
+ if (out.status === "released")
459
+ return `released - ${out.reason.name}: ${out.reason.message.split("\n")[0]}`;
460
+ return `failed - ${out.error.code ? `${out.error.code} ` : ""}${out.error.name}: ${out.error.message.split("\n")[0]}`;
461
+ }
462
+ //# sourceMappingURL=run-hosting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-hosting.js","sourceRoot":"","sources":["../src/run-hosting.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
- import { type Runtime, type RuntimeKind } from "@cotal-ai/core";
1
+ import { type AgentHandle, type Runtime, type RuntimeKind, type RuntimeReference } from "@cotal-ai/core";
2
2
  export type { Runtime, RuntimeKind, AgentHandle, AttachSession } from "@cotal-ai/core";
3
+ /** Adopt a durable handle, or refuse by name when this runtime has no adopt method. */
4
+ export declare function requireRuntimeAdopt(runtime: Runtime, reference: RuntimeReference): AgentHandle;
3
5
  /** How a manager picks its backend. `auto` is the deterministic default — always `pty`. External
4
6
  * runtimes are never auto-selected; choose one explicitly, which resolves
5
7
  * the integration from the registry and fails loud if it isn't imported. No fallbacks. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,WAAW,EAAwB,MAAM,gBAAgB,CAAC;AAGhG,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEvF;;2FAE2F;AAC3F,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;AAE/C;;qFAEqF;AACrF,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAyBzE;AAED,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAQ1E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,WAAW,EAAE,KAAK,OAAO,EAAE,KAAK,WAAW,EAAwB,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGzI,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEvF,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,GAAG,WAAW,CAI9F;AAED;;2FAE2F;AAC3F,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;AAE/C;;qFAEqF;AACrF,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAyBzE;AAED,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,MAAsB,GAAG,MAAM,CAQ1E"}
@@ -2,6 +2,12 @@ import { existsSync } from "node:fs";
2
2
  import { dirname, join, resolve } from "node:path";
3
3
  import { registry } from "@cotal-ai/core";
4
4
  import { PtyRuntime } from "./pty.js";
5
+ /** Adopt a durable handle, or refuse by name when this runtime has no adopt method. */
6
+ export function requireRuntimeAdopt(runtime, reference) {
7
+ if (typeof runtime.adopt !== "function")
8
+ throw new Error(`runtime "${runtime.kind}" does not support adopt`);
9
+ return runtime.adopt(reference);
10
+ }
5
11
  /** Build the runtime a manager will spawn through. `pty` ships with the manager and is what `auto`
6
12
  * resolves to. Every other name resolves a self-registered {@link RuntimeProvider}; an explicit
7
13
  * provider that is absent or unreachable throws, never a silent fallback to pty. */