@agen-ai/agent-orchestration 0.0.0-stage → 0.4.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/LICENSE +21 -0
- package/README.md +413 -2
- package/dist/catalog/parse.d.ts +3 -0
- package/dist/catalog/parse.js +13 -0
- package/dist/catalog/schemas.d.ts +8 -0
- package/dist/catalog/schemas.js +78 -0
- package/dist/catalog/types.d.ts +53 -0
- package/dist/catalog/types.js +0 -0
- package/dist/coordinator/admission.d.ts +7 -0
- package/dist/coordinator/admission.js +189 -0
- package/dist/coordinator/cancel.d.ts +7 -0
- package/dist/coordinator/cancel.js +111 -0
- package/dist/coordinator/create.d.ts +3 -0
- package/dist/coordinator/create.js +87 -0
- package/dist/coordinator/parse.d.ts +10 -0
- package/dist/coordinator/parse.js +60 -0
- package/dist/coordinator/read.d.ts +4 -0
- package/dist/coordinator/read.js +267 -0
- package/dist/coordinator/recovery.d.ts +4 -0
- package/dist/coordinator/recovery.js +24 -0
- package/dist/coordinator/shutdown.d.ts +7 -0
- package/dist/coordinator/shutdown.js +66 -0
- package/dist/coordinator/types.d.ts +154 -0
- package/dist/coordinator/types.js +0 -0
- package/dist/delivery/calls.d.ts +4 -0
- package/dist/delivery/calls.js +34 -0
- package/dist/delivery/journal.d.ts +7 -0
- package/dist/delivery/journal.js +57 -0
- package/dist/delivery/parse.d.ts +4 -0
- package/dist/delivery/parse.js +31 -0
- package/dist/delivery/recovery.d.ts +3 -0
- package/dist/delivery/recovery.js +18 -0
- package/dist/delivery/scheduler.d.ts +3 -0
- package/dist/delivery/scheduler.js +123 -0
- package/dist/delivery/setup.d.ts +7 -0
- package/dist/delivery/setup.js +37 -0
- package/dist/delivery/types.d.ts +36 -0
- package/dist/delivery/types.js +0 -0
- package/dist/execution/authority.d.ts +16 -0
- package/dist/execution/authority.js +86 -0
- package/dist/execution/cleanup.d.ts +3 -0
- package/dist/execution/cleanup.js +75 -0
- package/dist/execution/control.d.ts +6 -0
- package/dist/execution/control.js +231 -0
- package/dist/execution/finish.d.ts +6 -0
- package/dist/execution/finish.js +49 -0
- package/dist/execution/journal.d.ts +19 -0
- package/dist/execution/journal.js +28 -0
- package/dist/execution/prepare.d.ts +3 -0
- package/dist/execution/prepare.js +153 -0
- package/dist/execution/scheduler.d.ts +4 -0
- package/dist/execution/scheduler.js +136 -0
- package/dist/execution/state.d.ts +107 -0
- package/dist/execution/state.js +120 -0
- package/dist/execution/stream.d.ts +9 -0
- package/dist/execution/stream.js +108 -0
- package/dist/host/types.d.ts +95 -0
- package/dist/host/types.js +0 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +58 -0
- package/dist/mcp/bridge.d.ts +4 -0
- package/dist/mcp/bridge.js +222 -0
- package/dist/mcp/http.d.ts +11 -0
- package/dist/mcp/http.js +74 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/limits.d.ts +10 -0
- package/dist/mcp/limits.js +30 -0
- package/dist/mcp/protocol.d.ts +50 -0
- package/dist/mcp/protocol.js +81 -0
- package/dist/mcp/types.d.ts +22 -0
- package/dist/mcp/types.js +0 -0
- package/dist/policy/matching.d.ts +4 -0
- package/dist/policy/matching.js +18 -0
- package/dist/policy/parse.d.ts +3 -0
- package/dist/policy/parse.js +13 -0
- package/dist/policy/resolve.d.ts +7 -0
- package/dist/policy/resolve.js +67 -0
- package/dist/policy/schemas.d.ts +5 -0
- package/dist/policy/schemas.js +59 -0
- package/dist/policy/types.d.ts +60 -0
- package/dist/policy/types.js +0 -0
- package/dist/shared/bounds.d.ts +6 -0
- package/dist/shared/bounds.js +88 -0
- package/dist/shared/errors.d.ts +9 -0
- package/dist/shared/errors.js +27 -0
- package/dist/shared/identity.d.ts +6 -0
- package/dist/shared/identity.js +32 -0
- package/dist/shared/immutable.d.ts +2 -0
- package/dist/shared/immutable.js +10 -0
- package/dist/shared/limits.d.ts +32 -0
- package/dist/shared/limits.js +69 -0
- package/dist/shared/operational-errors.d.ts +7 -0
- package/dist/shared/operational-errors.js +15 -0
- package/dist/shared/schemas.d.ts +11 -0
- package/dist/shared/schemas.js +23 -0
- package/dist/shared/text.d.ts +2 -0
- package/dist/shared/text.js +15 -0
- package/dist/store/memory.d.ts +7 -0
- package/dist/store/memory.js +215 -0
- package/dist/store/pages.d.ts +16 -0
- package/dist/store/pages.js +46 -0
- package/dist/store/parse.d.ts +5 -0
- package/dist/store/parse.js +137 -0
- package/dist/store/types.d.ts +219 -0
- package/dist/store/types.js +0 -0
- package/dist/store-adapter/admission.d.ts +6 -0
- package/dist/store-adapter/admission.js +90 -0
- package/dist/store-adapter/context.d.ts +20 -0
- package/dist/store-adapter/context.js +107 -0
- package/dist/store-adapter/delivery.d.ts +15 -0
- package/dist/store-adapter/delivery.js +81 -0
- package/dist/store-adapter/execution.d.ts +12 -0
- package/dist/store-adapter/execution.js +151 -0
- package/dist/store-adapter/index.d.ts +7 -0
- package/dist/store-adapter/index.js +27 -0
- package/dist/store-adapter/lifecycle.d.ts +15 -0
- package/dist/store-adapter/lifecycle.js +80 -0
- package/dist/store-adapter/plan.d.ts +7 -0
- package/dist/store-adapter/plan.js +168 -0
- package/dist/store-adapter/types.d.ts +45 -0
- package/dist/store-adapter/types.js +0 -0
- package/dist/tasks/failure.d.ts +4 -0
- package/dist/tasks/failure.js +24 -0
- package/dist/tasks/parse.d.ts +18 -0
- package/dist/tasks/parse.js +66 -0
- package/dist/tasks/schemas.d.ts +47 -0
- package/dist/tasks/schemas.js +215 -0
- package/dist/tasks/types.d.ts +192 -0
- package/dist/tasks/types.js +0 -0
- package/dist/tools/create.d.ts +4 -0
- package/dist/tools/create.js +69 -0
- package/dist/tools/errors.d.ts +4 -0
- package/dist/tools/errors.js +35 -0
- package/dist/tools/guidance.d.ts +4 -0
- package/dist/tools/guidance.js +28 -0
- package/dist/tools/handlers.d.ts +4 -0
- package/dist/tools/handlers.js +84 -0
- package/dist/tools/projection.d.ts +13 -0
- package/dist/tools/projection.js +72 -0
- package/dist/tools/schemas.d.ts +6 -0
- package/dist/tools/schemas.js +93 -0
- package/dist/tools/types.d.ts +28 -0
- package/dist/tools/types.js +0 -0
- package/package.json +64 -3
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { failDelegation } from "../shared/operational-errors.js";
|
|
2
|
+
import { delegationDataBytes } from "../shared/identity.js";
|
|
3
|
+
import { DELEGATION_CRITICAL_SLOTS, DELEGATION_RUN_RESERVATION_BYTES } from "../shared/limits.js";
|
|
4
|
+
import { addOperation, same } from "./context.js";
|
|
5
|
+
function admitRun(context, command) {
|
|
6
|
+
const { admission } = command;
|
|
7
|
+
const { current } = context;
|
|
8
|
+
const { limits } = current;
|
|
9
|
+
if (current.runIdExists || current.runs.some((run) => run.runId === admission.runId)) {
|
|
10
|
+
failDelegation("operation_conflict", "The run identity is already retained.");
|
|
11
|
+
}
|
|
12
|
+
if (admission.depth > limits.maxDepth || delegationDataBytes(admission.input) > limits.maxInputBytes || admission.input.parts.reduce((count, part) => count + (part.type === "text" ? part.text.length : 0), 0) > limits.maxInputTextCharacters) {
|
|
13
|
+
failDelegation("capacity_exceeded", "The admitted depth or input exceeds its configured limit.");
|
|
14
|
+
}
|
|
15
|
+
if (!admission.policyCeiling.targets.some((target) => same(target, admission.target))) {
|
|
16
|
+
failDelegation("policy_denied", "The exact admitted target is outside the retained policy ceiling.");
|
|
17
|
+
}
|
|
18
|
+
if (Date.parse(admission.deadlineAt) <= Date.parse(admission.createdAt) || Date.parse(admission.queuedStartDeadlineAt) <= Date.parse(admission.createdAt) || Date.parse(admission.deadlineAt) - Date.parse(admission.createdAt) > limits.runTimeoutMs || Date.parse(admission.queuedStartDeadlineAt) - Date.parse(admission.createdAt) > limits.queuedStartTimeoutMs) {
|
|
19
|
+
failDelegation("capacity_exceeded", "Admission deadlines exceed their configured bounds.");
|
|
20
|
+
}
|
|
21
|
+
if (current.task) {
|
|
22
|
+
const previous = current.runs.find((run) => run.runId === admission.previousRunId);
|
|
23
|
+
if (!previous || command.runId !== previous.runId || command.expectedRunRevision !== previous.revision) {
|
|
24
|
+
failDelegation("stale_revision", "A continuation requires its exact previous run revision.");
|
|
25
|
+
}
|
|
26
|
+
if (admission.continuationMode === "next_turn" && (previous.phase !== "running" || previous.cancelRequested) || admission.continuationMode === "follow_up" && (previous.phase !== "settled" || previous.outcome?.kind === "recovery_required")) {
|
|
27
|
+
failDelegation("stale_revision", "The continuation mode does not match its previous run boundary.");
|
|
28
|
+
}
|
|
29
|
+
if (current.task.state === "retired" || current.task.state === "recovery_required" || !same(current.task.parent, admission.parent) || current.task.depth !== admission.depth || current.task.policyCeilingRef !== admission.policyCeiling.ceilingId || current.task.completionPolicy !== admission.completionPolicy || current.task.ancestorTaskId !== admission.ancestorTaskId || admission.previousRunId !== current.task.latestRunId || current.runs.some((run) => run.phase === "queued")) {
|
|
30
|
+
failDelegation("stale_revision", "A continuation must preserve its task and follow the latest safe run.");
|
|
31
|
+
}
|
|
32
|
+
if (current.runs.some((run) => run.phase === "waiting") || current.task.runCount >= limits.maxRunsPerTask) {
|
|
33
|
+
failDelegation("capacity_exceeded", "This task cannot admit another queued continuation.");
|
|
34
|
+
}
|
|
35
|
+
} else if (admission.previousRunId || command.expectedTaskRevision !== 0) {
|
|
36
|
+
failDelegation("stale_revision", "A new task cannot refer to an earlier run.");
|
|
37
|
+
}
|
|
38
|
+
const ceilingBytes = current.ceiling ? 0 : delegationDataBytes(admission.policyCeiling);
|
|
39
|
+
if (current.ceiling && !same(current.ceiling, admission.policyCeiling)) {
|
|
40
|
+
failDelegation("operation_conflict", "A retained ceiling digest has conflicting facts.");
|
|
41
|
+
}
|
|
42
|
+
const inputBytes = delegationDataBytes(admission.input) + ceilingBytes;
|
|
43
|
+
if (!current.task && context.capacity.tasks >= limits.maxTasks || context.capacity.runs >= limits.maxRuns || context.capacity.queuedRuns >= limits.maxQueuedRuns || context.capacity.retainedInputBytes + inputBytes > limits.maxRetainedInputBytes) {
|
|
44
|
+
failDelegation("capacity_exceeded", "The retained admission or queue capacity is full.");
|
|
45
|
+
}
|
|
46
|
+
context.capacity = {
|
|
47
|
+
...context.capacity,
|
|
48
|
+
tasks: context.capacity.tasks + (current.task ? 0 : 1),
|
|
49
|
+
runs: context.capacity.runs + 1,
|
|
50
|
+
queuedRuns: context.capacity.queuedRuns + 1,
|
|
51
|
+
retainedInputBytes: context.capacity.retainedInputBytes + inputBytes,
|
|
52
|
+
reservedBytes: context.capacity.reservedBytes + DELEGATION_RUN_RESERVATION_BYTES,
|
|
53
|
+
criticalSlots: context.capacity.criticalSlots + DELEGATION_CRITICAL_SLOTS
|
|
54
|
+
};
|
|
55
|
+
context.task = { ...context.task, latestRunId: admission.runId, runCount: (current.task?.runCount ?? 0) + 1 };
|
|
56
|
+
context.run = {
|
|
57
|
+
taskId: command.taskId,
|
|
58
|
+
runId: admission.runId,
|
|
59
|
+
ordinal: context.task.runCount,
|
|
60
|
+
...admission.previousRunId && admission.continuationMode ? {
|
|
61
|
+
previousRunId: admission.previousRunId,
|
|
62
|
+
continuationMode: admission.continuationMode
|
|
63
|
+
} : {},
|
|
64
|
+
admissionOperationId: command.operationId,
|
|
65
|
+
admittedTarget: admission.target,
|
|
66
|
+
admittedPolicyRevision: admission.policyRevision,
|
|
67
|
+
admittedOriginPolicyRevision: admission.originPolicyRevision,
|
|
68
|
+
input: admission.input,
|
|
69
|
+
ownerEpoch: command.owner.epoch,
|
|
70
|
+
phase: "queued",
|
|
71
|
+
revision: 1,
|
|
72
|
+
createdAt: admission.createdAt,
|
|
73
|
+
deadlineAt: admission.deadlineAt,
|
|
74
|
+
queuedStartDeadlineAt: admission.queuedStartDeadlineAt,
|
|
75
|
+
dispatch: "none",
|
|
76
|
+
preparation: "none",
|
|
77
|
+
cancelRequested: false,
|
|
78
|
+
observationIndex: 0,
|
|
79
|
+
observationCount: 0,
|
|
80
|
+
observationBytes: 0,
|
|
81
|
+
omittedObservations: 0,
|
|
82
|
+
ordinaryOperationCount: 0
|
|
83
|
+
};
|
|
84
|
+
context.receipt = { ...context.receipt, status: "queued", runId: admission.runId, runRevision: 1, operationId: command.operationId };
|
|
85
|
+
addOperation(context, "admit", admission.createdAt);
|
|
86
|
+
if (!current.ceiling) context.mutations.push({ kind: "ceiling", value: admission.policyCeiling });
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
admitRun
|
|
90
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DelegationNotificationRecord, DelegationRunOutcome, DelegationRunRecord, DelegationTaskRecord } from "../tasks/types.js";
|
|
2
|
+
import type { DelegationCommitReceipt, DelegationOperationKind, DelegationOperationRecord, DelegationStoreCapacity, DelegationStoreCommand } from "../store/types.js";
|
|
3
|
+
import type { DelegationStoreCommitCurrent, DelegationStoreRowMutation } from "./types.js";
|
|
4
|
+
export declare const criticalKinds: ReadonlySet<DelegationOperationKind>;
|
|
5
|
+
export interface CommitContext {
|
|
6
|
+
command: DelegationStoreCommand;
|
|
7
|
+
current: DelegationStoreCommitCurrent;
|
|
8
|
+
task: DelegationTaskRecord;
|
|
9
|
+
run?: DelegationRunRecord;
|
|
10
|
+
capacity: DelegationStoreCapacity;
|
|
11
|
+
mutations: DelegationStoreRowMutation[];
|
|
12
|
+
receipt: DelegationCommitReceipt;
|
|
13
|
+
}
|
|
14
|
+
export declare function same(left: unknown, right: unknown): boolean;
|
|
15
|
+
export declare function requireRun(context: CommitContext): DelegationRunRecord;
|
|
16
|
+
export declare function setRun(context: CommitContext, change: Partial<DelegationRunRecord>): void;
|
|
17
|
+
export declare function addOperation(context: CommitContext, kind: DelegationOperationKind, at: string, attempt?: number, request?: DelegationOperationRecord["request"]): void;
|
|
18
|
+
export declare function settleRun(context: CommitContext, requested: DelegationRunOutcome, at: string): DelegationNotificationRecord;
|
|
19
|
+
export declare function deriveTask(context: CommitContext): void;
|
|
20
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { failDelegation } from "../shared/operational-errors.js";
|
|
2
|
+
import { delegationCanonicalJson, delegationDataBytes, delegationSubordinateId } from "../shared/identity.js";
|
|
3
|
+
import { DELEGATION_CRITICAL_SLOT_BYTES, DELEGATION_FINAL_RESERVATION_BYTES } from "../shared/limits.js";
|
|
4
|
+
import { parseDelegationCompletionEnvelope } from "../tasks/parse.js";
|
|
5
|
+
const criticalKinds = /* @__PURE__ */ new Set(["cancel", "interrupt", "session_close", "binding_cleanup"]);
|
|
6
|
+
function same(left, right) {
|
|
7
|
+
return delegationCanonicalJson(left) === delegationCanonicalJson(right);
|
|
8
|
+
}
|
|
9
|
+
function requireRun(context) {
|
|
10
|
+
if (!context.run) return failDelegation("stale_revision", "The exact task run is unavailable.");
|
|
11
|
+
return context.run;
|
|
12
|
+
}
|
|
13
|
+
function setRun(context, change) {
|
|
14
|
+
const prior = requireRun(context);
|
|
15
|
+
const run = { ...prior, ...change };
|
|
16
|
+
if (prior.phase === "queued" && run.phase !== "queued") context.capacity = {
|
|
17
|
+
...context.capacity,
|
|
18
|
+
queuedRuns: context.capacity.queuedRuns - 1,
|
|
19
|
+
activeRuns: context.capacity.activeRuns + (run.phase === "settled" ? 0 : 1)
|
|
20
|
+
};
|
|
21
|
+
if (prior.phase !== "queued" && prior.phase !== "settled" && run.phase === "settled") {
|
|
22
|
+
context.capacity = { ...context.capacity, activeRuns: context.capacity.activeRuns - 1 };
|
|
23
|
+
}
|
|
24
|
+
context.run = run;
|
|
25
|
+
}
|
|
26
|
+
function addOperation(context, kind, at, attempt = 1, request) {
|
|
27
|
+
const run = requireRun(context);
|
|
28
|
+
if (!criticalKinds.has(kind)) {
|
|
29
|
+
if (run.ordinaryOperationCount >= context.current.limits.maxOrdinaryOperationsPerRun || context.capacity.ordinaryOperations >= context.current.limits.maxOrdinaryOperations) {
|
|
30
|
+
failDelegation("capacity_exceeded", "The ordinary operation ledger is full.");
|
|
31
|
+
}
|
|
32
|
+
setRun(context, { ordinaryOperationCount: run.ordinaryOperationCount + 1 });
|
|
33
|
+
context.capacity = { ...context.capacity, ordinaryOperations: context.capacity.ordinaryOperations + 1 };
|
|
34
|
+
}
|
|
35
|
+
const operation = {
|
|
36
|
+
operationId: context.command.operationId,
|
|
37
|
+
parent: context.task.parent,
|
|
38
|
+
taskId: context.task.taskId,
|
|
39
|
+
runId: run.runId,
|
|
40
|
+
kind,
|
|
41
|
+
inputDigest: context.command.inputDigest,
|
|
42
|
+
ownerEpoch: context.command.owner.epoch,
|
|
43
|
+
disposition: kind === "admit" || kind === "cancel" ? "completed" : "intent",
|
|
44
|
+
attempts: attempt,
|
|
45
|
+
at,
|
|
46
|
+
...request ? { request } : {},
|
|
47
|
+
receipt: { ...context.receipt, operationId: context.command.operationId }
|
|
48
|
+
};
|
|
49
|
+
if (delegationDataBytes(operation) > DELEGATION_CRITICAL_SLOT_BYTES) failDelegation("capacity_exceeded", "Operation exceeds its fixed ledger slot.");
|
|
50
|
+
context.mutations.push({ kind: "operation", value: operation });
|
|
51
|
+
}
|
|
52
|
+
function settleRun(context, requested, at) {
|
|
53
|
+
const run = requireRun(context);
|
|
54
|
+
if (run.outcome) failDelegation("operation_conflict", "A settled run outcome is immutable.");
|
|
55
|
+
const outcome = run.recoveryReason ? { kind: "recovery_required", reason: run.recoveryReason } : requested;
|
|
56
|
+
const notificationId = delegationSubordinateId(run.runId, "notification");
|
|
57
|
+
const envelope = parseDelegationCompletionEnvelope({
|
|
58
|
+
storeId: context.current.storeId,
|
|
59
|
+
notificationId,
|
|
60
|
+
taskId: run.taskId,
|
|
61
|
+
runId: run.runId,
|
|
62
|
+
parent: context.task.parent,
|
|
63
|
+
policy: context.task.completionPolicy,
|
|
64
|
+
settledAt: at,
|
|
65
|
+
expiresAt: new Date(Date.parse(at) + context.current.limits.notificationTtlMs).toISOString(),
|
|
66
|
+
outcome
|
|
67
|
+
});
|
|
68
|
+
const notification = {
|
|
69
|
+
envelope,
|
|
70
|
+
revision: 1,
|
|
71
|
+
state: context.task.completionPolicy === "collect" ? "collectible" : "pending",
|
|
72
|
+
attempts: 0
|
|
73
|
+
};
|
|
74
|
+
if (delegationDataBytes({ outcome, notification }) > DELEGATION_FINAL_RESERVATION_BYTES) {
|
|
75
|
+
failDelegation("capacity_exceeded", "Settlement exceeds its reserved final slot.");
|
|
76
|
+
}
|
|
77
|
+
setRun(context, {
|
|
78
|
+
phase: "settled",
|
|
79
|
+
outcome,
|
|
80
|
+
settledAt: at,
|
|
81
|
+
...run.pendingRequest ? { pendingRequest: { ...run.pendingRequest, state: "unavailable" } } : {},
|
|
82
|
+
finalization: {
|
|
83
|
+
operationId: context.command.operationId,
|
|
84
|
+
inputDigest: context.command.inputDigest,
|
|
85
|
+
taskRevision: context.task.revision,
|
|
86
|
+
runRevision: run.revision
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
context.receipt = { ...context.receipt, status: "settled", notificationId };
|
|
90
|
+
context.mutations.push({ kind: "notification", value: notification });
|
|
91
|
+
return notification;
|
|
92
|
+
}
|
|
93
|
+
function deriveTask(context) {
|
|
94
|
+
const runs = context.current.runs.map((run) => run.runId === context.run?.runId ? context.run : run);
|
|
95
|
+
if (context.run && !runs.some((run) => run.runId === context.run?.runId)) runs.push(context.run);
|
|
96
|
+
const state = context.task.state === "retired" ? "retired" : runs.some((run) => run.outcome?.kind === "recovery_required" || run.recoveryReason) ? "recovery_required" : runs.some((run) => run.phase !== "settled") ? "active" : "settled";
|
|
97
|
+
context.task = { ...context.task, state };
|
|
98
|
+
}
|
|
99
|
+
export {
|
|
100
|
+
addOperation,
|
|
101
|
+
criticalKinds,
|
|
102
|
+
deriveTask,
|
|
103
|
+
requireRun,
|
|
104
|
+
same,
|
|
105
|
+
setRun,
|
|
106
|
+
settleRun
|
|
107
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DelegationCommitReceipt, DelegationStoreCommand } from "../store/types.js";
|
|
2
|
+
import type { DelegationStoreCommitCurrent } from "./types.js";
|
|
3
|
+
import type { CommitContext } from "./context.js";
|
|
4
|
+
type DeliveryCommand = Extract<DelegationStoreCommand, {
|
|
5
|
+
kind: "delivery_claim" | "delivery_receipt";
|
|
6
|
+
}>;
|
|
7
|
+
export declare function deliveryAttemptIdentity(notificationId: string, attempt: number): {
|
|
8
|
+
attemptId: string;
|
|
9
|
+
claimOperationId: string;
|
|
10
|
+
receiptOperationId: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function duplicateDelivery(command: DeliveryCommand, current: DelegationStoreCommitCurrent): DelegationCommitReceipt | undefined;
|
|
13
|
+
export declare function delivery(context: CommitContext, command: DeliveryCommand): void;
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=delivery.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { delegationInputDigest, delegationSubordinateId } from "../shared/identity.js";
|
|
2
|
+
import { failDelegation } from "../shared/operational-errors.js";
|
|
3
|
+
import { parseDelegationNotificationRecord } from "../tasks/parse.js";
|
|
4
|
+
function deliveryAttemptIdentity(notificationId, attempt) {
|
|
5
|
+
const attemptId = delegationSubordinateId(notificationId, `delivery-attempt:${attempt}`);
|
|
6
|
+
return { attemptId, claimOperationId: delegationSubordinateId(attemptId, "claim"), receiptOperationId: delegationSubordinateId(attemptId, "receipt") };
|
|
7
|
+
}
|
|
8
|
+
function duplicateDelivery(command, current) {
|
|
9
|
+
const notification = current.notification;
|
|
10
|
+
if (!notification || notification.envelope.notificationId !== command.notificationId || notification.envelope.taskId !== command.taskId || notification.envelope.runId !== command.runId) {
|
|
11
|
+
failDelegation("stale_revision", "The exact notification is unavailable.");
|
|
12
|
+
}
|
|
13
|
+
const kind = command.kind === "delivery_claim" ? "claim" : "receipt";
|
|
14
|
+
const retained = notification.delivery?.[kind];
|
|
15
|
+
const other = notification.delivery?.[kind === "claim" ? "receipt" : "claim"];
|
|
16
|
+
if (other?.operationId === command.operationId) failDelegation("operation_conflict", "Delivery operation identity belongs to the other bookkeeping slot.");
|
|
17
|
+
if (retained?.operationId === command.operationId) {
|
|
18
|
+
if (retained.ownerEpoch !== command.owner.epoch) failDelegation("stale_revision", "The retained delivery command belongs to a previous owner.");
|
|
19
|
+
if (retained.attemptId !== command.attemptId || retained.inputDigest !== command.inputDigest || retained.commandDigest !== delegationInputDigest(command)) failDelegation("operation_conflict", "The current delivery identity has different committed input.");
|
|
20
|
+
return { ...retained.receipt, duplicate: true };
|
|
21
|
+
}
|
|
22
|
+
const attempt = notification.attempts + (kind === "claim" ? 1 : 0);
|
|
23
|
+
if (!Number.isSafeInteger(attempt) || attempt < 1) failDelegation("capacity_exceeded", "Delivery attempt ordinal is exhausted.");
|
|
24
|
+
const identity = deliveryAttemptIdentity(command.notificationId, attempt);
|
|
25
|
+
if (command.attemptId !== identity.attemptId || command.operationId !== (kind === "claim" ? identity.claimOperationId : identity.receiptOperationId)) {
|
|
26
|
+
failDelegation("stale_revision", "The delivery attempt has been superseded or is not the next canonical attempt.");
|
|
27
|
+
}
|
|
28
|
+
return void 0;
|
|
29
|
+
}
|
|
30
|
+
function delivery(context, command) {
|
|
31
|
+
const prior = context.current.notification;
|
|
32
|
+
if (prior.revision !== command.expectedNotificationRevision || prior.envelope.policy === "collect") {
|
|
33
|
+
failDelegation("stale_revision", "The exact eligible notification revision is unavailable.");
|
|
34
|
+
}
|
|
35
|
+
context.receipt = { ...context.receipt, notificationId: command.notificationId };
|
|
36
|
+
const kind = command.kind === "delivery_claim" ? "claim" : "receipt";
|
|
37
|
+
const attempt = prior.attempts + (kind === "claim" ? 1 : 0);
|
|
38
|
+
const bookkeeping = {
|
|
39
|
+
operationId: command.operationId,
|
|
40
|
+
inputDigest: command.inputDigest,
|
|
41
|
+
commandDigest: delegationInputDigest(command),
|
|
42
|
+
attemptId: command.attemptId,
|
|
43
|
+
attempt,
|
|
44
|
+
ownerEpoch: command.owner.epoch,
|
|
45
|
+
receipt: context.receipt
|
|
46
|
+
};
|
|
47
|
+
const retained = { ...prior, revision: prior.revision + 1, delivery: { ...prior.delivery, [kind]: bookkeeping } };
|
|
48
|
+
let notification;
|
|
49
|
+
if (command.kind === "delivery_claim") {
|
|
50
|
+
if (prior.state !== "pending") failDelegation("stale_revision", "Only a pending notification can begin a new delivery attempt.");
|
|
51
|
+
if (Date.parse(prior.envelope.expiresAt) <= Date.parse(command.at) && prior.reason !== "uncertain") {
|
|
52
|
+
const { retryAt: _retryAt, reason: _reason, ...expired } = retained;
|
|
53
|
+
notification = { ...expired, attempts: attempt, state: "expired", reason: "expired" };
|
|
54
|
+
} else {
|
|
55
|
+
if (prior.retryAt && Date.parse(prior.retryAt) > Date.parse(command.at)) failDelegation("stale_revision", "The notification retry is not yet eligible.");
|
|
56
|
+
notification = { ...retained, attempts: attempt, state: "claimed", claim: { ownerEpoch: command.owner.epoch, attemptId: command.attemptId } };
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
if (prior.state !== "claimed" || prior.claim?.attemptId !== command.attemptId || prior.claim.ownerEpoch !== command.owner.epoch && command.result.status !== "uncertain") {
|
|
60
|
+
failDelegation("stale_revision", "The receipt does not match this owner or the exact lost-owner claim.");
|
|
61
|
+
}
|
|
62
|
+
const { claim: _claim, retryAt: _retryAt, reason: _reason, inboxId: _inboxId, acceptedAt: _acceptedAt, ...withoutClaim } = retained;
|
|
63
|
+
const result = command.result;
|
|
64
|
+
if (result.status === "blocked" || result.status === "uncertain") {
|
|
65
|
+
const delay = Date.parse(result.retryAt) - Date.parse(command.at);
|
|
66
|
+
if (delay < 1e3 || delay > 3e4) failDelegation("capacity_exceeded", "Delivery retry must be between one and thirty seconds.");
|
|
67
|
+
}
|
|
68
|
+
const change = result.status === "accepted" ? { state: "accepted", inboxId: result.inboxId, acceptedAt: result.acceptedAt } : result.status === "blocked" || result.status === "uncertain" ? {
|
|
69
|
+
state: "pending",
|
|
70
|
+
retryAt: result.retryAt,
|
|
71
|
+
reason: result.status === "blocked" ? result.reason : "uncertain"
|
|
72
|
+
} : { state: result.status, reason: result.reason };
|
|
73
|
+
notification = { ...withoutClaim, ...change };
|
|
74
|
+
}
|
|
75
|
+
context.mutations.push({ kind: "notification", value: parseDelegationNotificationRecord(notification) });
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
delivery,
|
|
79
|
+
deliveryAttemptIdentity,
|
|
80
|
+
duplicateDelivery
|
|
81
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DelegationStoreCommand } from "../store/types.js";
|
|
2
|
+
import { type CommitContext } from "./context.js";
|
|
3
|
+
export declare function dispatchIntent(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
4
|
+
kind: "dispatch_intent";
|
|
5
|
+
}>): void;
|
|
6
|
+
export declare function operationReceipt(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
7
|
+
kind: "operation_receipt";
|
|
8
|
+
}>): void;
|
|
9
|
+
export declare function requestState(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
10
|
+
kind: "request_state";
|
|
11
|
+
}>): void;
|
|
12
|
+
//# sourceMappingURL=execution.d.ts.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { failDelegation } from "../shared/operational-errors.js";
|
|
2
|
+
import { delegationDataBytes } from "../shared/identity.js";
|
|
3
|
+
import { DELEGATION_CRITICAL_SLOT_BYTES } from "../shared/limits.js";
|
|
4
|
+
import { addOperation, criticalKinds, requireRun, same, setRun } from "./context.js";
|
|
5
|
+
const receiptDispositions = {
|
|
6
|
+
admit: [],
|
|
7
|
+
cancel: [],
|
|
8
|
+
prepare: ["completed", "rejected", "uncertain"],
|
|
9
|
+
configure: ["completed", "rejected", "uncertain"],
|
|
10
|
+
turn: ["delegated", "rejected", "uncertain"],
|
|
11
|
+
steer: ["delivered", "rejected", "uncertain"],
|
|
12
|
+
request_resolution: ["delivered", "rejected", "uncertain"],
|
|
13
|
+
interrupt: ["interruption_requested", "completed", "rejected", "uncertain"],
|
|
14
|
+
session_close: ["completed", "rejected", "uncertain"],
|
|
15
|
+
binding_cleanup: ["completed", "rejected", "uncertain"]
|
|
16
|
+
};
|
|
17
|
+
function dispatchIntent(context, command) {
|
|
18
|
+
const run = requireRun(context);
|
|
19
|
+
const kind = command.operationKind;
|
|
20
|
+
if (run.ownerEpoch !== command.owner.epoch && kind !== "prepare") {
|
|
21
|
+
failDelegation("recovery_required", "A new executor cannot replay any old provider or cleanup intent.");
|
|
22
|
+
}
|
|
23
|
+
const prior = context.current.criticalOperations.find((operation) => operation.kind === kind);
|
|
24
|
+
if (prior) {
|
|
25
|
+
if (kind !== "session_close" && kind !== "binding_cleanup" || command.attempt !== 2 || prior.attempts !== 1 || !["rejected", "uncertain"].includes(prior.disposition) || prior.operationId !== command.operationId || prior.inputDigest !== command.inputDigest) {
|
|
26
|
+
failDelegation("operation_conflict", "The reserved control slot is already assigned.");
|
|
27
|
+
}
|
|
28
|
+
context.mutations.push({ kind: "operation", value: {
|
|
29
|
+
...prior,
|
|
30
|
+
attempts: 2,
|
|
31
|
+
disposition: "intent",
|
|
32
|
+
at: command.at,
|
|
33
|
+
ownerEpoch: command.owner.epoch,
|
|
34
|
+
receipt: context.receipt
|
|
35
|
+
} });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if ((command.attempt ?? 1) !== 1) failDelegation("stale_revision", "A cleanup retry requires its retained first attempt.");
|
|
39
|
+
if (kind === "binding_cleanup" && !context.current.criticalOperations.some((operation) => operation.kind === "session_close")) {
|
|
40
|
+
failDelegation("stale_revision", "Combined cleanup must journal session close before binding cleanup.");
|
|
41
|
+
}
|
|
42
|
+
if (!criticalKinds.has(kind) && (context.task.state === "retired" || context.task.state === "recovery_required" || run.cancelRequested)) {
|
|
43
|
+
failDelegation("recovery_required", "This run no longer admits provider execution inputs.");
|
|
44
|
+
}
|
|
45
|
+
if (kind === "prepare") {
|
|
46
|
+
if (run.phase !== "queued" || run.dispatch !== "none") failDelegation("stale_revision", "Only an undispatched queued run can prepare.");
|
|
47
|
+
if (context.current.runs.some((other) => other.runId !== run.runId && ["preparing", "running", "waiting"].includes(other.phase)) || context.capacity.activeRuns >= context.current.limits.maxActiveRuns) failDelegation("capacity_exceeded", "No active executor slot is available.");
|
|
48
|
+
setRun(context, { phase: "preparing", preparation: "intended", ownerEpoch: command.owner.epoch });
|
|
49
|
+
} else if (kind === "turn") {
|
|
50
|
+
if (run.phase !== "preparing" || run.preparation !== "completed" || run.dispatch !== "none" || !command.appliedTarget || !same(command.appliedTarget, run.admittedTarget)) {
|
|
51
|
+
failDelegation("stale_target", "A first turn requires preparation and the exact applied target.");
|
|
52
|
+
}
|
|
53
|
+
setRun(context, { phase: "running", dispatch: "intended", appliedTarget: command.appliedTarget });
|
|
54
|
+
} else if (kind === "configure" && run.phase !== "preparing") {
|
|
55
|
+
failDelegation("stale_revision", "Configuration belongs to session preparation.");
|
|
56
|
+
} else if (kind === "steer" && run.phase !== "running") {
|
|
57
|
+
failDelegation("stale_revision", "Steering requires the active running turn.");
|
|
58
|
+
} else if (kind === "request_resolution") {
|
|
59
|
+
failDelegation("request_unavailable", "Request continuation must commit its exact historical request intent.");
|
|
60
|
+
} else if (kind === "interrupt" && (run.phase === "queued" || run.phase === "settled" || !run.cancelRequested)) {
|
|
61
|
+
failDelegation("stale_revision", "Interruption requires a live canceled run.");
|
|
62
|
+
}
|
|
63
|
+
addOperation(context, kind, command.at);
|
|
64
|
+
context.receipt = { ...context.receipt, status: requireRun(context).phase };
|
|
65
|
+
}
|
|
66
|
+
function operationReceipt(context, command) {
|
|
67
|
+
const prior = context.current.operation;
|
|
68
|
+
if (!prior || prior.runId !== command.runId || prior.inputDigest !== command.inputDigest) {
|
|
69
|
+
failDelegation("operation_conflict", "The exact provider intent is unavailable.");
|
|
70
|
+
}
|
|
71
|
+
if (!receiptDispositions[prior.kind].includes(command.disposition)) {
|
|
72
|
+
failDelegation("operation_conflict", "The receipt disposition is invalid for this operation kind.");
|
|
73
|
+
}
|
|
74
|
+
const rejectedRequest = prior.kind === "request_resolution" && command.disposition === "rejected";
|
|
75
|
+
if (rejectedRequest !== (command.requestState !== void 0)) {
|
|
76
|
+
failDelegation("operation_conflict", "Only a rejected request receipt requires authoritative request eligibility.");
|
|
77
|
+
}
|
|
78
|
+
if (["delivered", "rejected", "completed"].includes(prior.disposition) || prior.kind === "request_resolution" && prior.disposition === "uncertain") {
|
|
79
|
+
failDelegation("operation_conflict", "A final operation disposition is immutable.");
|
|
80
|
+
}
|
|
81
|
+
if (prior.ownerEpoch !== command.owner.epoch) failDelegation("recovery_required", "A new owner cannot invent a prior executor receipt.");
|
|
82
|
+
if (prior.kind === "binding_cleanup" && command.disposition === "completed" && !context.current.criticalOperations.some((operation2) => operation2.kind === "session_close" && operation2.disposition === "completed")) {
|
|
83
|
+
failDelegation("stale_revision", "Binding cleanup cannot complete before confirmed session close.");
|
|
84
|
+
}
|
|
85
|
+
const operation = {
|
|
86
|
+
...prior,
|
|
87
|
+
disposition: command.disposition,
|
|
88
|
+
at: command.at,
|
|
89
|
+
...command.requestState ? { requestState: command.requestState } : {},
|
|
90
|
+
...command.message ? { message: command.message } : {},
|
|
91
|
+
receipt: { ...context.receipt, operationId: command.operationId }
|
|
92
|
+
};
|
|
93
|
+
if (delegationDataBytes(operation) > DELEGATION_CRITICAL_SLOT_BYTES) failDelegation("capacity_exceeded", "Operation receipt exceeds its fixed slot.");
|
|
94
|
+
context.mutations.push({ kind: "operation", value: operation });
|
|
95
|
+
if (prior.kind === "request_resolution") {
|
|
96
|
+
const run = requireRun(context);
|
|
97
|
+
if (!prior.request) failDelegation("operation_conflict", "Request delivery requires its exact retained request identity.");
|
|
98
|
+
if (run.pendingRequest?.requestId === prior.request.requestId && run.pendingRequest.requestKind === prior.request.requestKind) {
|
|
99
|
+
if (run.pendingRequest.state !== "resolution_intended") failDelegation("request_unavailable", "The exact request has no entered resolution intent.");
|
|
100
|
+
const state = command.disposition === "delivered" ? "resolved" : command.requestState === "pending" ? "waiting" : "unavailable";
|
|
101
|
+
setRun(context, {
|
|
102
|
+
phase: run.phase === "settled" ? "settled" : state === "waiting" ? "waiting" : "running",
|
|
103
|
+
pendingRequest: { ...run.pendingRequest, state }
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
context.receipt = { ...context.receipt, status: requireRun(context).phase };
|
|
107
|
+
}
|
|
108
|
+
if (prior.kind === "turn" && command.disposition === "delegated") setRun(context, { dispatch: "delegated" });
|
|
109
|
+
if (prior.kind === "prepare") {
|
|
110
|
+
if (command.disposition === "completed") setRun(context, { preparation: "completed" });
|
|
111
|
+
if (command.disposition === "uncertain") setRun(context, { preparation: "uncertain" });
|
|
112
|
+
if (command.disposition === "rejected") setRun(context, { preparation: "none" });
|
|
113
|
+
}
|
|
114
|
+
if (command.disposition === "uncertain" && prior.kind === "steer") setRun(context, { recoveryReason: "steering_uncertain" });
|
|
115
|
+
if (command.disposition === "uncertain" && (prior.kind === "configure" || prior.kind === "request_resolution")) {
|
|
116
|
+
setRun(context, { recoveryReason: prior.kind === "request_resolution" ? "request_executor_lost" : "dispatch_uncertain" });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function requestState(context, command) {
|
|
120
|
+
const run = requireRun(context);
|
|
121
|
+
if (command.state === "opened") {
|
|
122
|
+
if (run.phase !== "running" || command.request.state !== "waiting" || run.ownerEpoch !== command.owner.epoch) {
|
|
123
|
+
failDelegation("request_unavailable", "Only the current active executor stream can open a waiting request.");
|
|
124
|
+
}
|
|
125
|
+
setRun(context, { phase: "waiting", pendingRequest: command.request });
|
|
126
|
+
} else {
|
|
127
|
+
if (!run.pendingRequest || run.pendingRequest.requestId !== command.request.requestId || run.pendingRequest.requestKind !== command.request.requestKind) failDelegation("request_unavailable", "The exact historical request is unavailable.");
|
|
128
|
+
if (command.state === "resolution_intended") {
|
|
129
|
+
if (run.phase !== "waiting" || run.pendingRequest.state !== "waiting" || run.ownerEpoch !== command.owner.epoch || run.cancelRequested || run.pendingRequest.expiresAt && Date.parse(run.pendingRequest.expiresAt) <= Date.parse(command.at)) {
|
|
130
|
+
failDelegation("request_unavailable", "This request cannot accept a continuation intent.");
|
|
131
|
+
}
|
|
132
|
+
addOperation(
|
|
133
|
+
context,
|
|
134
|
+
"request_resolution",
|
|
135
|
+
command.at,
|
|
136
|
+
1,
|
|
137
|
+
{ requestId: run.pendingRequest.requestId, requestKind: run.pendingRequest.requestKind }
|
|
138
|
+
);
|
|
139
|
+
setRun(context, { phase: "running", pendingRequest: { ...run.pendingRequest, state: "resolution_intended" } });
|
|
140
|
+
} else {
|
|
141
|
+
if (command.state === "resolved" && run.pendingRequest.state !== "resolution_intended") failDelegation("request_unavailable", "Resolution requires its prior intent.");
|
|
142
|
+
setRun(context, { pendingRequest: { ...run.pendingRequest, state: command.state } });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
context.receipt = { ...context.receipt, status: requireRun(context).phase };
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
dispatchIntent,
|
|
149
|
+
operationReceipt,
|
|
150
|
+
requestState
|
|
151
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { planDelegationStoreCommit } from "./plan.js";
|
|
2
|
+
export type { DelegationStoreCommitCurrent, DelegationStoreCommitPlan, DelegationStoreRowMutation, } from "./types.js";
|
|
3
|
+
export { delegationCanonicalJson, delegationDataBytes, delegationInputDigest, delegationSubordinateId } from "../shared/identity.js";
|
|
4
|
+
export { parseDelegationStoreCommand, parseDelegationStoreReadInput, parseDelegationStoreScanInput } from "../store/parse.js";
|
|
5
|
+
export { delegationCursorPrefix, parseDelegationPageCursor, summarizeDelegationRun } from "../store/pages.js";
|
|
6
|
+
export { DELEGATION_CRITICAL_SLOT_BYTES, DELEGATION_CRITICAL_SLOTS, DELEGATION_FINAL_RESERVATION_BYTES, DELEGATION_RUN_RESERVATION_BYTES, } from "../shared/limits.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { planDelegationStoreCommit } from "./plan.js";
|
|
2
|
+
import { delegationCanonicalJson, delegationDataBytes, delegationInputDigest, delegationSubordinateId } from "../shared/identity.js";
|
|
3
|
+
import { parseDelegationStoreCommand, parseDelegationStoreReadInput, parseDelegationStoreScanInput } from "../store/parse.js";
|
|
4
|
+
import { delegationCursorPrefix, parseDelegationPageCursor, summarizeDelegationRun } from "../store/pages.js";
|
|
5
|
+
import {
|
|
6
|
+
DELEGATION_CRITICAL_SLOT_BYTES,
|
|
7
|
+
DELEGATION_CRITICAL_SLOTS,
|
|
8
|
+
DELEGATION_FINAL_RESERVATION_BYTES,
|
|
9
|
+
DELEGATION_RUN_RESERVATION_BYTES
|
|
10
|
+
} from "../shared/limits.js";
|
|
11
|
+
export {
|
|
12
|
+
DELEGATION_CRITICAL_SLOTS,
|
|
13
|
+
DELEGATION_CRITICAL_SLOT_BYTES,
|
|
14
|
+
DELEGATION_FINAL_RESERVATION_BYTES,
|
|
15
|
+
DELEGATION_RUN_RESERVATION_BYTES,
|
|
16
|
+
delegationCanonicalJson,
|
|
17
|
+
delegationCursorPrefix,
|
|
18
|
+
delegationDataBytes,
|
|
19
|
+
delegationInputDigest,
|
|
20
|
+
delegationSubordinateId,
|
|
21
|
+
parseDelegationPageCursor,
|
|
22
|
+
parseDelegationStoreCommand,
|
|
23
|
+
parseDelegationStoreReadInput,
|
|
24
|
+
parseDelegationStoreScanInput,
|
|
25
|
+
planDelegationStoreCommit,
|
|
26
|
+
summarizeDelegationRun
|
|
27
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DelegationStoreCommand } from "../store/types.js";
|
|
2
|
+
import { type CommitContext } from "./context.js";
|
|
3
|
+
export declare function observeRun(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
4
|
+
kind: "observe";
|
|
5
|
+
}>): void;
|
|
6
|
+
export declare function cancelRun(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
7
|
+
kind: "cancel";
|
|
8
|
+
}>): void;
|
|
9
|
+
export declare function settle(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
10
|
+
kind: "settle";
|
|
11
|
+
}>): void;
|
|
12
|
+
export declare function retireRecovery(context: CommitContext, command: Extract<DelegationStoreCommand, {
|
|
13
|
+
kind: "retire_recovery";
|
|
14
|
+
}>): void;
|
|
15
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { failDelegation } from "../shared/operational-errors.js";
|
|
2
|
+
import { delegationDataBytes, delegationInputDigest } from "../shared/identity.js";
|
|
3
|
+
import { addOperation, requireRun, setRun, settleRun } from "./context.js";
|
|
4
|
+
function observeRun(context, command) {
|
|
5
|
+
const run = requireRun(context);
|
|
6
|
+
const observation = command.observation;
|
|
7
|
+
if (run.phase === "queued" || run.phase === "settled" || run.ownerEpoch !== command.owner.epoch || observation.storeId !== context.current.storeId || observation.taskId !== run.taskId || observation.runId !== run.runId || observation.index !== run.observationIndex + 1 || observation.kind === "omitted") failDelegation("stale_revision", "Observation does not follow the live run's canonical index.");
|
|
8
|
+
const bytes = delegationDataBytes(observation);
|
|
9
|
+
const limits = context.current.limits;
|
|
10
|
+
const digest = delegationInputDigest(observation);
|
|
11
|
+
if (bytes > limits.maxObservationBytes || run.observationCount >= limits.maxRunObservations || run.observationBytes + bytes > limits.maxRunObservationBytes || context.capacity.observationBytes + bytes > limits.maxRetainedObservationBytes) {
|
|
12
|
+
const omitted = run.omittedObservations + 1;
|
|
13
|
+
const marker = context.current.omissionObservation;
|
|
14
|
+
context.mutations.push({ kind: "observation", value: marker ? { ...marker, omitted } : {
|
|
15
|
+
storeId: context.current.storeId,
|
|
16
|
+
taskId: run.taskId,
|
|
17
|
+
runId: run.runId,
|
|
18
|
+
index: observation.index,
|
|
19
|
+
at: observation.at,
|
|
20
|
+
kind: "omitted",
|
|
21
|
+
omitted
|
|
22
|
+
} });
|
|
23
|
+
setRun(context, { observationIndex: observation.index, omittedObservations: omitted, lastObservationDigest: digest });
|
|
24
|
+
context.receipt = { ...context.receipt, status: "omitted" };
|
|
25
|
+
} else {
|
|
26
|
+
context.mutations.push({ kind: "observation", value: observation });
|
|
27
|
+
setRun(context, {
|
|
28
|
+
observationIndex: observation.index,
|
|
29
|
+
observationCount: run.observationCount + 1,
|
|
30
|
+
observationBytes: run.observationBytes + bytes,
|
|
31
|
+
lastObservationDigest: digest
|
|
32
|
+
});
|
|
33
|
+
context.capacity = { ...context.capacity, observationBytes: context.capacity.observationBytes + bytes };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function cancelRun(context, command) {
|
|
37
|
+
const run = requireRun(context);
|
|
38
|
+
if (run.phase === "settled") {
|
|
39
|
+
context.receipt = { ...context.receipt, status: "settled" };
|
|
40
|
+
addOperation(context, "cancel", command.at);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setRun(context, { cancelRequested: true });
|
|
44
|
+
if (run.phase === "queued" && run.preparation === "none" && run.dispatch === "none") {
|
|
45
|
+
settleRun(context, { kind: "canceled", confirmation: "not_dispatched" }, command.at);
|
|
46
|
+
}
|
|
47
|
+
addOperation(context, "cancel", command.at);
|
|
48
|
+
}
|
|
49
|
+
function settle(context, command) {
|
|
50
|
+
const run = requireRun(context);
|
|
51
|
+
if ((command.outcome.kind === "succeeded" || command.outcome.kind === "canceled" && command.outcome.confirmation === "provider_terminal") && run.phase !== "running" && run.phase !== "waiting") {
|
|
52
|
+
failDelegation("stale_revision", "Provider terminal truth requires a previously running turn.");
|
|
53
|
+
}
|
|
54
|
+
if (command.outcome.kind === "failed" && (run.preparation === "intended" || run.preparation === "uncertain") && run.phase === "preparing") failDelegation("recovery_required", "An unresolved preparation intent has no definitive failure receipt.");
|
|
55
|
+
if (command.outcome.kind === "canceled" && command.outcome.confirmation === "not_dispatched" && (run.phase !== "queued" || run.preparation !== "none" || run.dispatch !== "none")) {
|
|
56
|
+
failDelegation("stale_revision", "An execution intent cannot be settled as never dispatched.");
|
|
57
|
+
}
|
|
58
|
+
if (run.ownerEpoch !== command.owner.epoch && command.outcome.kind !== "recovery_required" && !(run.phase === "queued" && run.preparation === "none" && run.dispatch === "none")) {
|
|
59
|
+
failDelegation("recovery_required", "A new owner cannot reconstruct an old executor's terminal truth.");
|
|
60
|
+
}
|
|
61
|
+
settleRun(context, command.outcome, command.at);
|
|
62
|
+
}
|
|
63
|
+
function retireRecovery(context, command) {
|
|
64
|
+
if (context.task.state !== "recovery_required" || context.current.runs.some((run) => run.phase !== "settled")) {
|
|
65
|
+
failDelegation("recovery_required", "Only a fully settled recovery task can be retired.");
|
|
66
|
+
}
|
|
67
|
+
context.task = {
|
|
68
|
+
...context.task,
|
|
69
|
+
state: "retired",
|
|
70
|
+
retiredAt: command.at,
|
|
71
|
+
retirement: { operationId: command.operationId, inputDigest: command.inputDigest, reason: command.reason }
|
|
72
|
+
};
|
|
73
|
+
context.receipt = { ...context.receipt, status: "retired" };
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
cancelRun,
|
|
77
|
+
observeRun,
|
|
78
|
+
retireRecovery,
|
|
79
|
+
settle
|
|
80
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DelegationStoreCommand } from "../store/types.js";
|
|
2
|
+
import type { DelegationStoreCommitCurrent, DelegationStoreCommitPlan } from "./types.js";
|
|
3
|
+
export declare function planDelegationStoreCommit(input: {
|
|
4
|
+
readonly command: DelegationStoreCommand;
|
|
5
|
+
readonly current: DelegationStoreCommitCurrent;
|
|
6
|
+
}): DelegationStoreCommitPlan;
|
|
7
|
+
//# sourceMappingURL=plan.d.ts.map
|