@relayflows/sdk 2.0.51 → 2.0.52
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/authored-budget.d.ts +1 -1
- package/dist/authored-budget.d.ts.map +1 -1
- package/dist/authored-budget.js +3 -3
- package/dist/authored-budget.js.map +1 -1
- package/dist/authored-flow-error.d.ts +3 -1
- package/dist/authored-flow-error.d.ts.map +1 -1
- package/dist/authored-flow-error.js.map +1 -1
- package/dist/authored-flow-executor.d.ts +2 -0
- package/dist/authored-flow-executor.d.ts.map +1 -1
- package/dist/authored-flow-executor.js +93 -12
- package/dist/authored-flow-executor.js.map +1 -1
- package/dist/authored-flow-lifecycle.d.ts +28 -3
- package/dist/authored-flow-lifecycle.d.ts.map +1 -1
- package/dist/authored-flow-lifecycle.js +206 -10
- package/dist/authored-flow-lifecycle.js.map +1 -1
- package/dist/authored-node-entry.js +2 -0
- package/dist/authored-node-entry.js.map +1 -1
- package/dist/authored-parallel-body.d.ts +10 -0
- package/dist/authored-parallel-body.d.ts.map +1 -0
- package/dist/authored-parallel-body.js +68 -0
- package/dist/authored-parallel-body.js.map +1 -0
- package/dist/authored-parallel-eligibility.d.ts +8 -0
- package/dist/authored-parallel-eligibility.d.ts.map +1 -0
- package/dist/authored-parallel-eligibility.js +287 -0
- package/dist/authored-parallel-eligibility.js.map +1 -0
- package/dist/authored-promise-graph.d.ts +16 -0
- package/dist/authored-promise-graph.d.ts.map +1 -1
- package/dist/authored-promise-graph.js +36 -0
- package/dist/authored-promise-graph.js.map +1 -1
- package/dist/authored-root-readback.d.ts +1 -2
- package/dist/authored-root-readback.d.ts.map +1 -1
- package/dist/authored-root-readback.js +1 -1
- package/dist/authored-root-readback.js.map +1 -1
- package/dist/authored-root.d.ts +6 -1
- package/dist/authored-root.d.ts.map +1 -1
- package/dist/authored-root.js +55 -8
- package/dist/authored-root.js.map +1 -1
- package/dist/authored-step-graph.d.ts +19 -4
- package/dist/authored-step-graph.d.ts.map +1 -1
- package/dist/authored-step-graph.js +49 -6
- package/dist/authored-step-graph.js.map +1 -1
- package/dist/authored-step-index.d.ts +2 -1
- package/dist/authored-step-index.d.ts.map +1 -1
- package/dist/authored-step-index.js +2 -1
- package/dist/authored-step-index.js.map +1 -1
- package/dist/authored-verdict.d.ts +2 -0
- package/dist/authored-verdict.d.ts.map +1 -1
- package/dist/authored-verdict.js +4 -1
- package/dist/authored-verdict.js.map +1 -1
- package/dist/authored-worker-step.d.ts +2 -1
- package/dist/authored-worker-step.d.ts.map +1 -1
- package/dist/authored-worker-step.js +12 -5
- package/dist/authored-worker-step.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +4 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/failure-kinds.d.ts +1 -1
- package/dist/failure-kinds.d.ts.map +1 -1
- package/dist/failure-kinds.js +2 -0
- package/dist/failure-kinds.js.map +1 -1
- package/dist/journal-client.d.ts +3 -1
- package/dist/journal-client.d.ts.map +1 -1
- package/dist/journal-client.js +18 -1
- package/dist/journal-client.js.map +1 -1
- package/package.json +3 -2
- package/src/authored-budget.ts +4 -3
- package/src/authored-flow-error.ts +2 -0
- package/src/authored-flow-executor.ts +85 -11
- package/src/authored-flow-lifecycle.ts +215 -9
- package/src/authored-node-entry.ts +2 -0
- package/src/authored-parallel-body.ts +67 -0
- package/src/authored-parallel-eligibility.ts +245 -0
- package/src/authored-promise-graph.ts +35 -0
- package/src/authored-root-readback.ts +1 -2
- package/src/authored-root.ts +62 -9
- package/src/authored-step-graph.ts +50 -5
- package/src/authored-step-index.ts +2 -1
- package/src/authored-verdict.ts +4 -1
- package/src/authored-worker-step.ts +12 -3
- package/src/cli/run.ts +4 -2
- package/src/failure-kinds.ts +2 -0
- package/src/journal-client.ts +19 -0
package/src/authored-verdict.ts
CHANGED
|
@@ -21,6 +21,8 @@ import type { JournalEvent } from './journal-reader.js';
|
|
|
21
21
|
|
|
22
22
|
/** The `instruction` discriminator `authored-root.ts` writes into the root step. */
|
|
23
23
|
export const AUTHORED_ROOT_KIND = 'relayflows.authored-root.v1';
|
|
24
|
+
/** Older CLIs do not recognize this root and must refuse a parallel rollback. */
|
|
25
|
+
export const AUTHORED_PARALLEL_ROOT_KIND = 'relayflows.authored-root.parallel.v2';
|
|
24
26
|
|
|
25
27
|
export interface AuthoredVerdict {
|
|
26
28
|
readonly reason: LoweredCompletionReason;
|
|
@@ -76,7 +78,8 @@ export function declaresAuthoredRoot(spawned: JournalEvent): boolean {
|
|
|
76
78
|
if (step === null || step['id'] !== 'authored-root') return false;
|
|
77
79
|
if (typeof step['instruction'] !== 'string') return false;
|
|
78
80
|
try {
|
|
79
|
-
|
|
81
|
+
const kind = record(JSON.parse(step['instruction']))?.['kind'];
|
|
82
|
+
return kind === AUTHORED_ROOT_KIND || kind === AUTHORED_PARALLEL_ROOT_KIND;
|
|
80
83
|
} catch {
|
|
81
84
|
return false;
|
|
82
85
|
}
|
|
@@ -19,7 +19,7 @@ import { authoredChildAdmissionKey } from './authored-admission.js';
|
|
|
19
19
|
import { alsoRecord, recordAuthoredChild } from './authored-step-index.js';
|
|
20
20
|
import type { StepFailedDetails } from './failure-kinds.js';
|
|
21
21
|
import { LOCAL_AGENT_WORKSPACE } from './local-agent-pins.js';
|
|
22
|
-
import { authoredWorkerSlots, type AuthoredWorkerSlots } from './worker-slots.js';
|
|
22
|
+
import { authoredWorkerSlots, WorkerSlots, type AuthoredWorkerSlots } from './worker-slots.js';
|
|
23
23
|
import { validateStepSecrets } from './step-secrets.js';
|
|
24
24
|
|
|
25
25
|
const AGENT_TIMEOUT = Symbol('declared agent timeout');
|
|
@@ -356,8 +356,14 @@ export function authoredWorkerRunner(
|
|
|
356
356
|
export function authoredDeterministicRunner(
|
|
357
357
|
name: string, journal: JournalClient, journalSteps: AuthoredFlowJournalStep[], budget: AuthoredBudget,
|
|
358
358
|
context: AuthoredStepContext = {},
|
|
359
|
+
parallel = false,
|
|
359
360
|
) {
|
|
360
361
|
const rootRunId = context.rootRunId;
|
|
362
|
+
// run.start drives a deterministic child to completion before replying. The
|
|
363
|
+
// daemon reads one connection in order, so sharing the body's connection
|
|
364
|
+
// would serialize Promise.all. Each admitted child gets its own connection;
|
|
365
|
+
// this limit bounds both daemon threads and shell commands per authored body.
|
|
366
|
+
const slots = new WorkerSlots(8);
|
|
361
367
|
// One lowering, two readers. `record` changes what the child run's verdict
|
|
362
368
|
// MEANS, so the reader changes with it; everything before the read — spec,
|
|
363
369
|
// admission key, budget, child index — is deliberately shared, because a
|
|
@@ -386,8 +392,10 @@ export function authoredDeterministicRunner(
|
|
|
386
392
|
});
|
|
387
393
|
return read(outcome);
|
|
388
394
|
};
|
|
389
|
-
|
|
390
|
-
|
|
395
|
+
const admit = async () => terminal
|
|
396
|
+
? consume(await journal.runStart(spec, undefined, admissionKey, false, parallel))
|
|
397
|
+
: budget.execute(journal, spec, consume, admissionKey, parallel);
|
|
398
|
+
return parallel ? slots.run(admit) : admit();
|
|
391
399
|
}
|
|
392
400
|
const lowerRun = (id: string, command: string, terminal = false, leaseMs?: number, verification?: NamedGate,
|
|
393
401
|
secrets?: string[]): Promise<string> =>
|
|
@@ -398,6 +406,7 @@ export function authoredDeterministicRunner(
|
|
|
398
406
|
secrets?: string[]): Promise<RecordedRunOutcome> =>
|
|
399
407
|
lower(id, command, false, leaseMs, verification, 'record', secrets,
|
|
400
408
|
outcome => readRecordedOutcome(journal, outcome, id, journalSteps, context));
|
|
409
|
+
lowerRun.stop = (reason: unknown): void => slots.close(reason);
|
|
401
410
|
return lowerRun;
|
|
402
411
|
}
|
|
403
412
|
|
package/src/cli/run.ts
CHANGED
|
@@ -415,9 +415,11 @@ export async function resumeFlow(
|
|
|
415
415
|
return { exitCode: 2, report: { ...base, runId, socketPath,
|
|
416
416
|
diagnostics: [{ severity: 'refusal', kind: 'human_influenced_run', message: error.message.replace(/^human_influenced_run: /, '') }] } };
|
|
417
417
|
}
|
|
418
|
-
if (error instanceof AuthoredFlowExecutionError
|
|
418
|
+
if (error instanceof AuthoredFlowExecutionError
|
|
419
|
+
&& (error.code === 'unsafe_parallel_runtime' || error.code === 'unsupported_promise_lifecycle')) {
|
|
419
420
|
return { exitCode: 2, report: { ...base, runId, socketPath,
|
|
420
|
-
diagnostics: [{ severity: 'refusal',
|
|
421
|
+
diagnostics: [{ severity: 'refusal',
|
|
422
|
+
kind: error.code === 'unsafe_parallel_runtime' ? error.code : 'invalid_spec', message: error.message }] } };
|
|
421
423
|
}
|
|
422
424
|
if (error instanceof AuthoredFlowExecutionError
|
|
423
425
|
&& (error.code === 'helper_slack.credential_missing' || error.code === 'helper_slack.mount_required'
|
package/src/failure-kinds.ts
CHANGED
|
@@ -134,6 +134,8 @@ export const RUN_FAILURE_KINDS = [
|
|
|
134
134
|
'run_parked',
|
|
135
135
|
'run_declined',
|
|
136
136
|
'run_unavailable',
|
|
137
|
+
/** A pinned parallel root is still active, but this process cannot safely dispatch it. */
|
|
138
|
+
'unsafe_parallel_runtime',
|
|
137
139
|
/** A predicate `.gate(fn)` judged false; the verdict is journaled as `<step>.gate`. */
|
|
138
140
|
'gate_failed',
|
|
139
141
|
/** `flows answer` named a wait the run is not asking: unknown, or already answered. */
|
package/src/journal-client.ts
CHANGED
|
@@ -135,7 +135,12 @@ export class JournalClient extends JournalConnection {
|
|
|
135
135
|
reuseFromRunId?: string,
|
|
136
136
|
admissionKey?: string,
|
|
137
137
|
watch = false,
|
|
138
|
+
isolated = false,
|
|
138
139
|
): Promise<VerbContract['run.start']['result']> {
|
|
140
|
+
if (isolated) {
|
|
141
|
+
if (watch) throw new Error('an isolated run.start cannot keep a watch on its temporary session');
|
|
142
|
+
return this.runStartIsolated(spec, reuseFromRunId, admissionKey);
|
|
143
|
+
}
|
|
139
144
|
for (const step of spec.steps) {
|
|
140
145
|
for (const name of validateStepSecrets(step.secrets, process.env)) {
|
|
141
146
|
if (this.withheld.has(name)) {
|
|
@@ -155,6 +160,20 @@ export class JournalClient extends JournalConnection {
|
|
|
155
160
|
}, null);
|
|
156
161
|
}
|
|
157
162
|
|
|
163
|
+
/** Drive a blocking deterministic child on its own socket, then close it. */
|
|
164
|
+
private async runStartIsolated(
|
|
165
|
+
spec: KernelRunSpec, reuseFromRunId?: string, admissionKey?: string,
|
|
166
|
+
): Promise<VerbContract['run.start']['result']> {
|
|
167
|
+
const peer = this.createPeer();
|
|
168
|
+
try {
|
|
169
|
+
await peer.connect();
|
|
170
|
+
await peer.hello('flows-authored-deterministic');
|
|
171
|
+
return await peer.runStart(spec, reuseFromRunId, admissionKey);
|
|
172
|
+
} finally {
|
|
173
|
+
peer.close();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
158
177
|
/** §3 memoized resume. */
|
|
159
178
|
runResume(runId: string, allowHumanInfluenced = false): Promise<VerbContract['run.resume']['result']> {
|
|
160
179
|
return this.request('run.resume', {
|