@cotal-ai/manager 0.45.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.
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/launch.js +2 -2
- package/dist/launch.js.map +1 -1
- package/dist/manager-service-contract.d.ts +17 -1
- package/dist/manager-service-contract.d.ts.map +1 -1
- package/dist/manager-service-contract.js +122 -3
- package/dist/manager-service-contract.js.map +1 -1
- package/dist/manager.d.ts +39 -7
- package/dist/manager.d.ts.map +1 -1
- package/dist/manager.js +231 -40
- package/dist/manager.js.map +1 -1
- package/dist/run-hosting.d.ts +114 -0
- package/dist/run-hosting.d.ts.map +1 -0
- package/dist/run-hosting.js +462 -0
- package/dist/run-hosting.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +6 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/static-lifecycle.d.ts +35 -1
- package/dist/static-lifecycle.d.ts.map +1 -1
- package/dist/static-lifecycle.js +65 -0
- package/dist/static-lifecycle.js.map +1 -1
- package/package.json +9 -9
|
@@ -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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"}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/runtime/index.js
CHANGED
|
@@ -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. */
|