@obversa/runtime 0.1.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 +192 -0
- package/dist/api.d.ts +72 -0
- package/dist/api.js +9775 -0
- package/dist/api.js.map +1 -0
- package/dist/artifacts/conformance.d.ts +1 -0
- package/dist/artifacts/file-store.d.ts +8 -0
- package/dist/artifacts/store.d.ts +1 -0
- package/dist/callback/approval.d.ts +8 -0
- package/dist/callback/client.d.ts +38 -0
- package/dist/callback/gate.d.ts +1 -0
- package/dist/callback/stored-client.d.ts +5 -0
- package/dist/chunk-3L6YNPN6.js +3 -0
- package/dist/chunk-3L6YNPN6.js.map +1 -0
- package/dist/chunk-5GLEABOU.js +3 -0
- package/dist/chunk-5GLEABOU.js.map +1 -0
- package/dist/chunk-DEW5R23M.js +338 -0
- package/dist/chunk-DEW5R23M.js.map +1 -0
- package/dist/chunk-DV5P4QLI.js +3056 -0
- package/dist/chunk-DV5P4QLI.js.map +1 -0
- package/dist/chunk-NIBHM5I5.js +34 -0
- package/dist/chunk-NIBHM5I5.js.map +1 -0
- package/dist/chunk-RZLMX3IA.js +368 -0
- package/dist/chunk-RZLMX3IA.js.map +1 -0
- package/dist/core/agent-md.d.ts +36 -0
- package/dist/core/agent.d.ts +86 -0
- package/dist/core/approval-job.d.ts +43 -0
- package/dist/core/assert-graph.d.ts +34 -0
- package/dist/core/budget.d.ts +49 -0
- package/dist/core/concurrency.d.ts +2 -0
- package/dist/core/condition.d.ts +209 -0
- package/dist/core/context.d.ts +36 -0
- package/dist/core/cost.d.ts +59 -0
- package/dist/core/dag.d.ts +20 -0
- package/dist/core/decision.d.ts +29 -0
- package/dist/core/describe.d.ts +56 -0
- package/dist/core/engine-meta.d.ts +5 -0
- package/dist/core/env-overlay.d.ts +35 -0
- package/dist/core/errors.d.ts +46 -0
- package/dist/core/feedback.d.ts +68 -0
- package/dist/core/git.d.ts +152 -0
- package/dist/core/guards.d.ts +70 -0
- package/dist/core/isolated.d.ts +40 -0
- package/dist/core/job.d.ts +134 -0
- package/dist/core/limits.d.ts +22 -0
- package/dist/core/loop.d.ts +24 -0
- package/dist/core/merge.d.ts +30 -0
- package/dist/core/pipeline.d.ts +35 -0
- package/dist/core/process.d.ts +11 -0
- package/dist/core/progress.d.ts +82 -0
- package/dist/core/redact.d.ts +1 -0
- package/dist/core/stats.d.ts +63 -0
- package/dist/core/team.d.ts +34 -0
- package/dist/core/text.d.ts +8 -0
- package/dist/core/tournament.d.ts +25 -0
- package/dist/core/types.d.ts +650 -0
- package/dist/engines/command-runner.d.ts +1 -0
- package/dist/engines/conformance.d.ts +1 -0
- package/dist/engines/engine.d.ts +4 -0
- package/dist/engines/failure.d.ts +1 -0
- package/dist/engines/fallback.d.ts +35 -0
- package/dist/engines/message-map.d.ts +1 -0
- package/dist/engines/mock.d.ts +1 -0
- package/dist/engines/preflight.d.ts +36 -0
- package/dist/env/command.d.ts +50 -0
- package/dist/env/command.js +65 -0
- package/dist/env/command.js.map +1 -0
- package/dist/env/environment.d.ts +4 -0
- package/dist/env/mock.d.ts +24 -0
- package/dist/events/conformance.d.ts +1 -0
- package/dist/events/envelope.d.ts +1 -0
- package/dist/events/jsonl-store.d.ts +8 -0
- package/dist/events/store.d.ts +1 -0
- package/dist/graph/commands.d.ts +5 -0
- package/dist/graph/conformance.d.ts +32 -0
- package/dist/graph/kernel.d.ts +5 -0
- package/dist/graph/plan.d.ts +1 -0
- package/dist/graph/type.d.ts +7 -0
- package/dist/graph/value.d.ts +1 -0
- package/dist/graph-types/dag.d.ts +137 -0
- package/dist/graph-types/loop.d.ts +194 -0
- package/dist/graph-types/team.d.ts +68 -0
- package/dist/memory.d.ts +82 -0
- package/dist/memory.js +397 -0
- package/dist/memory.js.map +1 -0
- package/dist/proof/acceptance.d.ts +5 -0
- package/dist/proof/artifact.d.ts +6 -0
- package/dist/proof/cache.d.ts +4 -0
- package/dist/runtime/attempt.d.ts +19 -0
- package/dist/runtime/budget.d.ts +4 -0
- package/dist/runtime/engine-availability.d.ts +18 -0
- package/dist/runtime/graph-executor.d.ts +7 -0
- package/dist/runtime/monitor.d.ts +80 -0
- package/dist/runtime/node-lifecycle.d.ts +84 -0
- package/dist/runtime/paths.d.ts +2 -0
- package/dist/runtime/persist.d.ts +31 -0
- package/dist/runtime/preflight-record.d.ts +149 -0
- package/dist/runtime/process-tree.d.ts +1 -0
- package/dist/runtime/result-contract.d.ts +4 -0
- package/dist/runtime/result-parts.d.ts +1 -0
- package/dist/runtime/run-definition.d.ts +24 -0
- package/dist/runtime/run-event.d.ts +9 -0
- package/dist/runtime/runner.d.ts +139 -0
- package/dist/runtime/supervisor.d.ts +111 -0
- package/dist/runtime/team-rooms.d.ts +13 -0
- package/dist/runtime/workspace-policy.d.ts +25 -0
- package/dist/storage/error.d.ts +1 -0
- package/dist/storage/id.d.ts +1 -0
- package/dist/storage/local.d.ts +12 -0
- package/dist/storage/local.js +1492 -0
- package/dist/storage/local.js.map +1 -0
- package/dist/testing.d.ts +15 -0
- package/dist/testing.js +274 -0
- package/dist/testing.js.map +1 -0
- package/dist/workflow-agent-response.d.ts +3 -0
- package/dist/workflow-support.d.ts +36 -0
- package/dist/workflow-support.js +5 -0
- package/dist/workflow-support.js.map +1 -0
- package/dist/workflow.d.ts +73 -0
- package/dist/workspace/conformance.d.ts +1 -0
- package/dist/workspace/git-provider.d.ts +26 -0
- package/dist/workspace/provider.d.ts +2 -0
- package/package.json +91 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { runArtifactStoreConformance, assertArtifactStoreConformance, type ArtifactStoreConformanceOptions, type ArtifactStoreConformanceFactory, type ArtifactStoreConformanceFailure, type ArtifactStoreConformanceReport, } from '@obversa/api/testing';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ArtifactStore } from './store.js';
|
|
2
|
+
export interface LocalArtifactStoreOptions {
|
|
3
|
+
readonly root: string;
|
|
4
|
+
readonly maxArtifactBytes?: number;
|
|
5
|
+
readonly maxTotalArtifactBytesPerRun?: number;
|
|
6
|
+
readonly knownSecrets?: readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function createLocalArtifactStore(options: LocalArtifactStoreOptions): ArtifactStore;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { validateArtifactScope, validateNewArtifact, validateArtifactReference, type ArtifactContentMode, type ArtifactScope, type NewArtifact, type ArtifactBatch, type ArtifactReference, type ArtifactStore, } from '@obversa/api';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ApprovalRecord, type ApprovalResolutionInput, type PrepareApprovalRecordInput, type NewApprovalEvent, type ActionDecision } from '@obversa/api';
|
|
2
|
+
import { type RunStorageBinding } from '../runtime/run-definition.js';
|
|
3
|
+
export { ApprovalSubjectError, approvalSubjectDigest, createApprovalCallbackGate, validateApprovalRecord, validateApprovalSubject, snapshotApprovalSubject, assertApprovalPermissionsAdmitted, type ApprovalSubmission, type ApprovalSubjectInput, type ApprovalResolutionInput, type ApprovalSubject, type ApprovalBinding, type ApprovalRecord, type ApprovalEventPayload, type NewApprovalEvent, type PrepareApprovalRecordInput } from '@obversa/api';
|
|
4
|
+
export declare function prepareApprovalRecord(runId: string, input: PrepareApprovalRecordInput): Readonly<{
|
|
5
|
+
readonly record: ApprovalRecord;
|
|
6
|
+
readonly event: NewApprovalEvent;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function resolveApproval(storage: RunStorageBinding, runId: string, current: ApprovalResolutionInput): Promise<ActionDecision>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The callback client (roadmap D7): the router-facing side of the Callback
|
|
3
|
+
* Gate. Pending requests are observable without starting any effect; a
|
|
4
|
+
* router claims a request through atomic assignment — two racing routers,
|
|
5
|
+
* exactly one winner — submits a structured response validated against
|
|
6
|
+
* the request's response schema and its digest, and can release or be
|
|
7
|
+
* reassigned.
|
|
8
|
+
*
|
|
9
|
+
* The client is event-sourced: every mutation is recorded as an event, and
|
|
10
|
+
* the request states are a fold of the log — `replayCallbackClient`
|
|
11
|
+
* rebuilds a full client from any history, so no state is hidden outside
|
|
12
|
+
* the events. A newer request from the same gate supersedes the older
|
|
13
|
+
* unanswered ones with a recorded event, and a submit whose digest does
|
|
14
|
+
* not match the posted request is refused as stale.
|
|
15
|
+
*
|
|
16
|
+
* The direct-router helper takes a plain responder function and drives
|
|
17
|
+
* the whole loop. It imports no Surfacer, agent, or service code — it is
|
|
18
|
+
* the smallest possible router, and the proof that the contract is
|
|
19
|
+
* replaceable.
|
|
20
|
+
*/
|
|
21
|
+
import type { CallbackRequest } from './gate.js';
|
|
22
|
+
import { type CallbackEvent, type CallbackClient, type SubmitResult, type Responder } from '@obversa/api';
|
|
23
|
+
export { type CallbackEvent, validateCallbackEvent, type ClaimOk, type ClaimRefused, type ClaimResult, type SubmitOk, type SubmitRefused, type SubmitResult, type ReleaseOk, type ReleaseRefused, type ReleaseResult, type CallbackClient, type Responder, } from '@obversa/api';
|
|
24
|
+
/** Rebuild a complete client from a callback history. A pure fold. */
|
|
25
|
+
export declare function replayCallbackClient(events: readonly CallbackEvent[]): CallbackClient;
|
|
26
|
+
/**
|
|
27
|
+
* An event-sourced callback client. Seeding from a history replays it
|
|
28
|
+
* through the same fold the live client applies, so the log is the only
|
|
29
|
+
* state there is.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createCallbackClient(seed?: readonly CallbackEvent[]): CallbackClient;
|
|
32
|
+
/**
|
|
33
|
+
* The smallest router: claim the pending request for one gate, ask the
|
|
34
|
+
* responder function, and submit its structured answer with the digest the
|
|
35
|
+
* request carries. Imports nothing beyond the contract — no Surfacer,
|
|
36
|
+
* agent, or service code.
|
|
37
|
+
*/
|
|
38
|
+
export declare function directRouter(client: CallbackClient, request: CallbackRequest, routerId: string, responder: Responder): Promise<SubmitResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { callbackRequestDigest, createCallbackGate, validateCallbackRequest, validateCallbackResponse, type CallbackGateDefinition, type CallbackRequest, } from '@obversa/api';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { StoredCallbackClient } from '@obversa/api';
|
|
2
|
+
import { type RunStorageBinding } from '../runtime/run-definition.js';
|
|
3
|
+
export type { NewCallbackHistoryEvent, StoredCallbackClient } from '@obversa/api';
|
|
4
|
+
/** Open an awaited callback writer over the run's own event stream. */
|
|
5
|
+
export declare function createStoredCallbackClient(storage: RunStorageBinding, runId: string): Promise<Readonly<StoredCallbackClient>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-3L6YNPN6.js","sourcesContent":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-5GLEABOU.js","sourcesContent":[]}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { validateGraphDescription } from './chunk-3L6YNPN6.js';
|
|
2
|
+
import { GraphValidationError, cloneFrozenJson, JsonValueError } from './chunk-5GLEABOU.js';
|
|
3
|
+
import { compileGraphDefinition, GraphValidationError as GraphValidationError$1 } from '@obversa/api';
|
|
4
|
+
import { isDeepStrictEqual } from 'util';
|
|
5
|
+
|
|
6
|
+
function unknownNode(id) {
|
|
7
|
+
return new GraphValidationError$1(`Graph node "${id}" does not exist.`, [
|
|
8
|
+
{ code: "UNKNOWN_NODE", path: "/nodeId", message: `Node "${id}" is not declared.` }
|
|
9
|
+
]);
|
|
10
|
+
}
|
|
11
|
+
function uniqueNodeIds(edges, select) {
|
|
12
|
+
const ids = [];
|
|
13
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14
|
+
for (const edge of edges) {
|
|
15
|
+
const id = select(edge);
|
|
16
|
+
if (seen.has(id)) continue;
|
|
17
|
+
seen.add(id);
|
|
18
|
+
ids.push(id);
|
|
19
|
+
}
|
|
20
|
+
return Object.freeze(ids);
|
|
21
|
+
}
|
|
22
|
+
function createGraphKernel(definition) {
|
|
23
|
+
const snapshot = compileGraphDefinition(definition);
|
|
24
|
+
const value = snapshot.value;
|
|
25
|
+
const nodes = value.nodes;
|
|
26
|
+
const edges = value.edges;
|
|
27
|
+
const nodeById = new Map(
|
|
28
|
+
nodes.map((node) => [node.id, node])
|
|
29
|
+
);
|
|
30
|
+
const edgeById = new Map(
|
|
31
|
+
edges.map((edge) => [edge.id, edge])
|
|
32
|
+
);
|
|
33
|
+
const inbound = /* @__PURE__ */ new Map();
|
|
34
|
+
const outbound = /* @__PURE__ */ new Map();
|
|
35
|
+
for (const node of nodes) {
|
|
36
|
+
inbound.set(node.id, []);
|
|
37
|
+
outbound.set(node.id, []);
|
|
38
|
+
}
|
|
39
|
+
for (const edge of edges) {
|
|
40
|
+
inbound.get(edge.target).push(edge);
|
|
41
|
+
outbound.get(edge.source).push(edge);
|
|
42
|
+
}
|
|
43
|
+
const inboundFrozen = /* @__PURE__ */ new Map();
|
|
44
|
+
const outboundFrozen = /* @__PURE__ */ new Map();
|
|
45
|
+
const predecessors = /* @__PURE__ */ new Map();
|
|
46
|
+
const successors = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const node of nodes) {
|
|
48
|
+
const nodeInbound = Object.freeze(inbound.get(node.id));
|
|
49
|
+
const nodeOutbound = Object.freeze(outbound.get(node.id));
|
|
50
|
+
inboundFrozen.set(node.id, nodeInbound);
|
|
51
|
+
outboundFrozen.set(node.id, nodeOutbound);
|
|
52
|
+
predecessors.set(
|
|
53
|
+
node.id,
|
|
54
|
+
uniqueNodeIds(nodeInbound, (edge) => edge.source)
|
|
55
|
+
);
|
|
56
|
+
successors.set(
|
|
57
|
+
node.id,
|
|
58
|
+
uniqueNodeIds(nodeOutbound, (edge) => edge.target)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const requireNode = (id) => {
|
|
62
|
+
if (!nodeById.has(id)) throw unknownNode(id);
|
|
63
|
+
};
|
|
64
|
+
return Object.freeze({
|
|
65
|
+
definition: snapshot,
|
|
66
|
+
node: (id) => nodeById.get(id),
|
|
67
|
+
edge: (id) => edgeById.get(id),
|
|
68
|
+
predecessors: (id) => {
|
|
69
|
+
requireNode(id);
|
|
70
|
+
return predecessors.get(id);
|
|
71
|
+
},
|
|
72
|
+
successors: (id) => {
|
|
73
|
+
requireNode(id);
|
|
74
|
+
return successors.get(id);
|
|
75
|
+
},
|
|
76
|
+
inboundEdges: (id) => {
|
|
77
|
+
requireNode(id);
|
|
78
|
+
return inboundFrozen.get(id);
|
|
79
|
+
},
|
|
80
|
+
outboundEdges: (id) => {
|
|
81
|
+
requireNode(id);
|
|
82
|
+
return outboundFrozen.get(id);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function issue(path, message) {
|
|
87
|
+
return { code: "INVALID_GRAPH_COMMAND", path, message };
|
|
88
|
+
}
|
|
89
|
+
function invalid(path, message) {
|
|
90
|
+
return new GraphValidationError(`Invalid graph command: ${message}`, [
|
|
91
|
+
issue(path, message)
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
function text(value, path, label) {
|
|
95
|
+
if (typeof value !== "string" || value.trim().length === 0 || /[\u0000-\u001f\u007f]/.test(value)) {
|
|
96
|
+
throw invalid(path, `${label} must be a non-empty string without control characters.`);
|
|
97
|
+
}
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
function exactKeys(value, expected, path) {
|
|
101
|
+
const actual = Object.keys(value).sort();
|
|
102
|
+
const wanted = [...expected].sort();
|
|
103
|
+
if (JSON.stringify(actual) !== JSON.stringify(wanted)) {
|
|
104
|
+
throw invalid(path, `Expected fields ${wanted.join(", ")}; received ${actual.join(", ")}.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function validateGraphCommands(commands, kernel) {
|
|
108
|
+
if (!Array.isArray(commands)) {
|
|
109
|
+
throw invalid("", "A graph decision must be an array.");
|
|
110
|
+
}
|
|
111
|
+
let frozen;
|
|
112
|
+
try {
|
|
113
|
+
frozen = cloneFrozenJson(
|
|
114
|
+
commands
|
|
115
|
+
);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (!(error instanceof JsonValueError)) throw error;
|
|
118
|
+
throw invalid(error.path, error.message);
|
|
119
|
+
}
|
|
120
|
+
for (let index = 0; index < frozen.length; index += 1) {
|
|
121
|
+
const path = `/${index}`;
|
|
122
|
+
const command = frozen[index];
|
|
123
|
+
if (!command || typeof command !== "object" || Array.isArray(command)) {
|
|
124
|
+
throw invalid(path, "Each command must be an object.");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const terminal = frozen.filter((command) => command.kind !== "dispatch");
|
|
128
|
+
if (terminal.length > 0 && frozen.length !== 1) {
|
|
129
|
+
throw invalid("", "A terminal command must be the only command in a decision.");
|
|
130
|
+
}
|
|
131
|
+
const dispatchPositions = /* @__PURE__ */ new Set();
|
|
132
|
+
for (let index = 0; index < frozen.length; index += 1) {
|
|
133
|
+
const command = frozen[index];
|
|
134
|
+
const path = `/${index}`;
|
|
135
|
+
switch (command.kind) {
|
|
136
|
+
case "dispatch": {
|
|
137
|
+
exactKeys(command, [
|
|
138
|
+
"kind",
|
|
139
|
+
"nodeId",
|
|
140
|
+
"input",
|
|
141
|
+
"position"
|
|
142
|
+
], path);
|
|
143
|
+
const nodeId = text(command.nodeId, `${path}/nodeId`, "nodeId");
|
|
144
|
+
const position = text(command.position, `${path}/position`, "position");
|
|
145
|
+
if (!kernel.node(nodeId)) {
|
|
146
|
+
throw invalid(`${path}/nodeId`, `Dispatch refers to unknown node "${nodeId}".`);
|
|
147
|
+
}
|
|
148
|
+
if (dispatchPositions.has(position)) {
|
|
149
|
+
throw invalid(
|
|
150
|
+
`${path}/position`,
|
|
151
|
+
`Decision contains duplicate dispatch position "${position}".`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
dispatchPositions.add(position);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "pause":
|
|
158
|
+
exactKeys(command, ["kind", "reason"], path);
|
|
159
|
+
text(command.reason, `${path}/reason`, "reason");
|
|
160
|
+
break;
|
|
161
|
+
case "complete":
|
|
162
|
+
exactKeys(command, ["kind", "output"], path);
|
|
163
|
+
break;
|
|
164
|
+
case "fail":
|
|
165
|
+
exactKeys(command, [
|
|
166
|
+
"kind",
|
|
167
|
+
"code",
|
|
168
|
+
"message"
|
|
169
|
+
], path);
|
|
170
|
+
text(command.code, `${path}/code`, "code");
|
|
171
|
+
text(command.message, `${path}/message`, "message");
|
|
172
|
+
break;
|
|
173
|
+
default:
|
|
174
|
+
throw invalid(
|
|
175
|
+
`${path}/kind`,
|
|
176
|
+
`Unknown command kind "${String(command.kind)}".`
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return frozen;
|
|
181
|
+
}
|
|
182
|
+
function issue2(path, message) {
|
|
183
|
+
return { code: "INVALID_GRAPH_TYPE", path, message };
|
|
184
|
+
}
|
|
185
|
+
function fail(path, message) {
|
|
186
|
+
throw new GraphValidationError("Invalid graph type.", [issue2(path, message)]);
|
|
187
|
+
}
|
|
188
|
+
function name(value, path, label) {
|
|
189
|
+
if (typeof value !== "string" || value.trim().length === 0 || /[\u0000-\u001f\u007f]/.test(value)) {
|
|
190
|
+
fail(path, `${label} must be a non-empty string without control characters.`);
|
|
191
|
+
}
|
|
192
|
+
return value;
|
|
193
|
+
}
|
|
194
|
+
function version(value, path) {
|
|
195
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
196
|
+
fail(path, "Graph type version must be a positive safe integer.");
|
|
197
|
+
}
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
function json(value, path) {
|
|
201
|
+
try {
|
|
202
|
+
return cloneFrozenJson(value);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (!(error instanceof JsonValueError)) throw error;
|
|
205
|
+
fail(`${path}${error.path}`, error.message);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function validateEvent(value) {
|
|
209
|
+
const event = json(value, "/event");
|
|
210
|
+
if (event === null || typeof event !== "object" || Array.isArray(event)) {
|
|
211
|
+
fail("/event", "Event must be an object.");
|
|
212
|
+
}
|
|
213
|
+
const fields = Object.keys(event).sort();
|
|
214
|
+
const expected = ["payload", "type", "version"];
|
|
215
|
+
if (!isSameStringList(fields, expected)) {
|
|
216
|
+
fail(
|
|
217
|
+
"/event",
|
|
218
|
+
`Event must contain exactly type, version, and payload; received ${fields.join(", ") || "no fields"}.`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
const safeEvent = event;
|
|
222
|
+
name(safeEvent.type, "/event/type", "Event type");
|
|
223
|
+
if (!Number.isSafeInteger(safeEvent.version) || safeEvent.version < 1) {
|
|
224
|
+
fail("/event/version", "Event version must be a positive safe integer.");
|
|
225
|
+
}
|
|
226
|
+
return safeEvent;
|
|
227
|
+
}
|
|
228
|
+
function isSameStringList(left, right) {
|
|
229
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
230
|
+
}
|
|
231
|
+
function descriptionMismatch(path, message) {
|
|
232
|
+
throw new GraphValidationError(`Invalid graph plan: ${message}`, [{
|
|
233
|
+
code: "DESCRIPTION_MISMATCH",
|
|
234
|
+
path,
|
|
235
|
+
message
|
|
236
|
+
}]);
|
|
237
|
+
}
|
|
238
|
+
function assertCompiledDescription(description, expected) {
|
|
239
|
+
const { definition } = expected.kernel;
|
|
240
|
+
if (description.graph.id !== definition.value.id || description.graph.definitionVersion !== definition.value.definitionVersion || description.graph.definitionDigest !== definition.digest || description.graph.kind !== expected.kind || description.graph.typeVersion !== expected.typeVersion || !isDeepStrictEqual(description.requirements, expected.requirements)) {
|
|
241
|
+
descriptionMismatch("/graph", "Description metadata does not match the compiled graph.");
|
|
242
|
+
}
|
|
243
|
+
if (!isDeepStrictEqual(
|
|
244
|
+
description.nodes.map((node) => node.id),
|
|
245
|
+
definition.value.nodes.map((node) => node.id)
|
|
246
|
+
)) {
|
|
247
|
+
descriptionMismatch("/nodes", "Description node order does not match the definition.");
|
|
248
|
+
}
|
|
249
|
+
if (!isDeepStrictEqual(description.edges, definition.value.edges.map((edge) => ({
|
|
250
|
+
id: edge.id,
|
|
251
|
+
source: edge.source,
|
|
252
|
+
target: edge.target
|
|
253
|
+
})))) {
|
|
254
|
+
descriptionMismatch("/edges", "Description edges do not match the definition.");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function compileGraph(graphType, definition) {
|
|
258
|
+
const kind = name(graphType.kind, "/kind", "Graph kind");
|
|
259
|
+
const typeVersion = version(graphType.version, "/version");
|
|
260
|
+
const kernel = createGraphKernel(definition);
|
|
261
|
+
const implementation = graphType.compile(kernel.definition.value, kernel);
|
|
262
|
+
if (!implementation || typeof implementation !== "object") {
|
|
263
|
+
fail("/compile", "compile() must return a compiled graph object.");
|
|
264
|
+
}
|
|
265
|
+
const requirements = json(implementation.requirements, "/compile/requirements");
|
|
266
|
+
if (requirements.memory !== "required" && requirements.memory !== "unused") {
|
|
267
|
+
fail("/compile/requirements/memory", "Memory must be required or unused.");
|
|
268
|
+
}
|
|
269
|
+
for (const method of ["initialState", "reduce", "decide", "describe"]) {
|
|
270
|
+
if (typeof implementation[method] !== "function") {
|
|
271
|
+
fail(`/compile/${method}`, `${method} must be a function.`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (implementation.validateNodeResult !== void 0 && typeof implementation.validateNodeResult !== "function") {
|
|
275
|
+
fail("/compile/validateNodeResult", "validateNodeResult must be a function.");
|
|
276
|
+
}
|
|
277
|
+
const initialState = json(implementation.initialState(), "/initialState");
|
|
278
|
+
const descriptionInput = json(
|
|
279
|
+
implementation.describe(),
|
|
280
|
+
"/description"
|
|
281
|
+
);
|
|
282
|
+
const description = validateGraphDescription({
|
|
283
|
+
...descriptionInput,
|
|
284
|
+
schemaVersion: 1,
|
|
285
|
+
graph: {
|
|
286
|
+
id: kernel.definition.value.id,
|
|
287
|
+
definitionVersion: kernel.definition.value.definitionVersion,
|
|
288
|
+
kind,
|
|
289
|
+
typeVersion,
|
|
290
|
+
definitionDigest: kernel.definition.digest
|
|
291
|
+
},
|
|
292
|
+
edges: kernel.definition.value.edges.map((edge) => ({
|
|
293
|
+
id: edge.id,
|
|
294
|
+
source: edge.source,
|
|
295
|
+
target: edge.target
|
|
296
|
+
})),
|
|
297
|
+
requirements
|
|
298
|
+
});
|
|
299
|
+
assertCompiledDescription(description, {
|
|
300
|
+
kernel,
|
|
301
|
+
kind,
|
|
302
|
+
typeVersion,
|
|
303
|
+
requirements
|
|
304
|
+
});
|
|
305
|
+
return Object.freeze({
|
|
306
|
+
definition: kernel.definition,
|
|
307
|
+
requirements,
|
|
308
|
+
initialState: () => initialState,
|
|
309
|
+
...implementation.validateNodeResult === void 0 ? {} : {
|
|
310
|
+
validateNodeResult(nodeId, result) {
|
|
311
|
+
if (kernel.node(nodeId) === void 0) {
|
|
312
|
+
fail("/nodeId", `Unknown node "${nodeId}".`);
|
|
313
|
+
}
|
|
314
|
+
const returned = implementation.validateNodeResult(nodeId, json(result, "/result"));
|
|
315
|
+
if (returned === null) return null;
|
|
316
|
+
const safeIssue = json(returned, "/validateNodeResult");
|
|
317
|
+
if (safeIssue === null || typeof safeIssue !== "object" || Array.isArray(safeIssue) || !isSameStringList(Object.keys(safeIssue).sort(), ["code", "message", "path"]) || typeof safeIssue.code !== "string" || typeof safeIssue.path !== "string" || typeof safeIssue.message !== "string") {
|
|
318
|
+
fail("/validateNodeResult", "validateNodeResult must return null or an issue with code, path, and message strings.");
|
|
319
|
+
}
|
|
320
|
+
return safeIssue;
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
reduce(state, event) {
|
|
324
|
+
const safeState = json(state, "/state");
|
|
325
|
+
const safeEvent = validateEvent(event);
|
|
326
|
+
return json(implementation.reduce(safeState, safeEvent), "/reducedState");
|
|
327
|
+
},
|
|
328
|
+
decide(state) {
|
|
329
|
+
const safeState = json(state, "/state");
|
|
330
|
+
return validateGraphCommands(implementation.decide(safeState), kernel);
|
|
331
|
+
},
|
|
332
|
+
describe: () => description
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export { compileGraph, createGraphKernel };
|
|
337
|
+
//# sourceMappingURL=chunk-DEW5R23M.js.map
|
|
338
|
+
//# sourceMappingURL=chunk-DEW5R23M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/graph/kernel.ts","../src/graph/commands.ts","../src/graph/type.ts"],"names":["GraphValidationError","issue"],"mappings":"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","file":"chunk-DEW5R23M.js","sourcesContent":["import { GraphValidationError, compileGraphDefinition } from '@obversa/api';\n\nexport { GraphValidationError } from './value.js';\nexport type { GraphValidationIssue } from './value.js';\n\nimport type { EdgeId, NodeId, GraphEdge, GraphDefinition, GraphKernel } from '@obversa/api';\nexport type { GraphId, NodeId, EdgeId, GraphNode, GraphEdge, GraphDefinition, CompiledGraphDefinition, GraphKernel } from '@obversa/api';\n\ntype DefinitionNode<Definition extends GraphDefinition> =\n Definition['nodes'][number];\ntype DefinitionEdge<Definition extends GraphDefinition> =\n Definition['edges'][number];\n\nfunction unknownNode(id: NodeId): GraphValidationError {\n return new GraphValidationError(`Graph node \"${id}\" does not exist.`, [\n { code: 'UNKNOWN_NODE', path: '/nodeId', message: `Node \"${id}\" is not declared.` },\n ]);\n}\n\nfunction uniqueNodeIds(\n edges: readonly GraphEdge[],\n select: (edge: GraphEdge) => NodeId,\n): readonly NodeId[] {\n const ids: NodeId[] = [];\n const seen = new Set<NodeId>();\n for (const edge of edges) {\n const id = select(edge);\n if (seen.has(id)) continue;\n seen.add(id);\n ids.push(id);\n }\n return Object.freeze(ids);\n}\n\nexport function createGraphKernel<Definition extends GraphDefinition>(\n definition: Definition,\n): GraphKernel<Definition> {\n const snapshot = compileGraphDefinition(definition);\n const value = snapshot.value;\n const nodes = value.nodes as readonly DefinitionNode<Definition>[];\n const edges = value.edges as readonly DefinitionEdge<Definition>[];\n\n const nodeById = new Map<NodeId, DefinitionNode<Definition>>(\n nodes.map((node) => [node.id, node]),\n );\n const edgeById = new Map<EdgeId, DefinitionEdge<Definition>>(\n edges.map((edge) => [edge.id, edge]),\n );\n const inbound = new Map<NodeId, DefinitionEdge<Definition>[]>();\n const outbound = new Map<NodeId, DefinitionEdge<Definition>[]>();\n for (const node of nodes) {\n inbound.set(node.id, []);\n outbound.set(node.id, []);\n }\n for (const edge of edges) {\n inbound.get(edge.target)!.push(edge);\n outbound.get(edge.source)!.push(edge);\n }\n\n const inboundFrozen = new Map<NodeId, readonly DefinitionEdge<Definition>[]>();\n const outboundFrozen = new Map<NodeId, readonly DefinitionEdge<Definition>[]>();\n const predecessors = new Map<NodeId, readonly NodeId[]>();\n const successors = new Map<NodeId, readonly NodeId[]>();\n for (const node of nodes) {\n const nodeInbound = Object.freeze(inbound.get(node.id)!);\n const nodeOutbound = Object.freeze(outbound.get(node.id)!);\n inboundFrozen.set(node.id, nodeInbound);\n outboundFrozen.set(node.id, nodeOutbound);\n predecessors.set(\n node.id,\n uniqueNodeIds(nodeInbound, (edge) => edge.source),\n );\n successors.set(\n node.id,\n uniqueNodeIds(nodeOutbound, (edge) => edge.target),\n );\n }\n\n const requireNode = (id: NodeId): void => {\n if (!nodeById.has(id)) throw unknownNode(id);\n };\n\n return Object.freeze({\n definition: snapshot,\n node: (id: NodeId) => nodeById.get(id),\n edge: (id: EdgeId) => edgeById.get(id),\n predecessors: (id: NodeId) => {\n requireNode(id);\n return predecessors.get(id)!;\n },\n successors: (id: NodeId) => {\n requireNode(id);\n return successors.get(id)!;\n },\n inboundEdges: (id: NodeId) => {\n requireNode(id);\n return inboundFrozen.get(id)!;\n },\n outboundEdges: (id: NodeId) => {\n requireNode(id);\n return outboundFrozen.get(id)!;\n },\n });\n}\n","import type { GraphKernel } from './kernel.js';\nimport {\n cloneFrozenJson,\n GraphValidationError,\n JsonValueError,\n type GraphValidationIssue,\n type JsonValue,\n} from './value.js';\n\nimport type { GraphCommand } from '@obversa/api';\nexport { type DispatchGraphCommand, type PauseGraphCommand, type CompleteGraphCommand, type FailGraphCommand, type GraphCommand } from '@obversa/api';\n\nfunction issue(path: string, message: string): GraphValidationIssue {\n return { code: 'INVALID_GRAPH_COMMAND', path, message };\n}\n\nfunction invalid(path: string, message: string): GraphValidationError {\n return new GraphValidationError(`Invalid graph command: ${message}`, [\n issue(path, message),\n ]);\n}\n\nfunction text(value: unknown, path: string, label: string): string {\n if (\n typeof value !== 'string'\n || value.trim().length === 0\n || /[\\u0000-\\u001f\\u007f]/.test(value)\n ) {\n throw invalid(path, `${label} must be a non-empty string without control characters.`);\n }\n return value;\n}\n\nfunction exactKeys(\n value: Record<string, unknown>,\n expected: readonly string[],\n path: string,\n): void {\n const actual = Object.keys(value).sort();\n const wanted = [...expected].sort();\n if (JSON.stringify(actual) !== JSON.stringify(wanted)) {\n throw invalid(path, `Expected fields ${wanted.join(', ')}; received ${actual.join(', ')}.`);\n }\n}\n\n/** Validate one pure graph decision before the runtime can act on it. */\nexport function validateGraphCommands(\n commands: readonly GraphCommand[],\n kernel: GraphKernel,\n): readonly GraphCommand[] {\n if (!Array.isArray(commands)) {\n throw invalid('', 'A graph decision must be an array.');\n }\n let frozen: readonly GraphCommand[];\n try {\n frozen = cloneFrozenJson(\n commands as readonly JsonValue[],\n ) as unknown as readonly GraphCommand[];\n } catch (error) {\n if (!(error instanceof JsonValueError)) throw error;\n throw invalid(error.path, error.message);\n }\n for (let index = 0; index < frozen.length; index += 1) {\n const path = `/${index}`;\n const command = frozen[index];\n if (!command || typeof command !== 'object' || Array.isArray(command)) {\n throw invalid(path, 'Each command must be an object.');\n }\n }\n\n const terminal = frozen.filter((command) => command.kind !== 'dispatch');\n if (terminal.length > 0 && frozen.length !== 1) {\n throw invalid('', 'A terminal command must be the only command in a decision.');\n }\n\n const dispatchPositions = new Set<string>();\n for (let index = 0; index < frozen.length; index += 1) {\n const command = frozen[index] as GraphCommand;\n const path = `/${index}`;\n\n switch (command.kind) {\n case 'dispatch': {\n exactKeys(command as unknown as Record<string, unknown>, [\n 'kind', 'nodeId', 'input', 'position',\n ], path);\n const nodeId = text(command.nodeId, `${path}/nodeId`, 'nodeId');\n const position = text(command.position, `${path}/position`, 'position');\n if (!kernel.node(nodeId)) {\n throw invalid(`${path}/nodeId`, `Dispatch refers to unknown node \"${nodeId}\".`);\n }\n if (dispatchPositions.has(position)) {\n throw invalid(\n `${path}/position`,\n `Decision contains duplicate dispatch position \"${position}\".`,\n );\n }\n dispatchPositions.add(position);\n break;\n }\n case 'pause':\n exactKeys(command as unknown as Record<string, unknown>, ['kind', 'reason'], path);\n text(command.reason, `${path}/reason`, 'reason');\n break;\n case 'complete':\n exactKeys(command as unknown as Record<string, unknown>, ['kind', 'output'], path);\n break;\n case 'fail':\n exactKeys(command as unknown as Record<string, unknown>, [\n 'kind', 'code', 'message',\n ], path);\n text(command.code, `${path}/code`, 'code');\n text(command.message, `${path}/message`, 'message');\n break;\n default:\n throw invalid(\n `${path}/kind`,\n `Unknown command kind \"${String((command as { kind?: unknown }).kind)}\".`,\n );\n }\n }\n\n return frozen;\n}\n","import { isDeepStrictEqual } from 'node:util';\n\n\nimport { validateGraphCommands, type GraphCommand } from './commands.js';\nimport {\n createGraphKernel,\n type GraphDefinition,\n type GraphKernel,\n type NodeId,\n} from './kernel.js';\nimport {\n validateGraphDescription,\n type GraphDescription,\n type GraphDescriptionInput,\n type GraphRequirements,\n} from './plan.js';\nimport {\n cloneFrozenJson,\n GraphValidationError,\n JsonValueError,\n type GraphValidationIssue,\n type JsonValue,\n} from './value.js';\n\nimport type { GraphEvent, CompiledGraphType, GraphType } from '@obversa/api';\nexport { type GraphEvent, type GraphEngineIdentity, type EngineAttemptRecordedPayload, type GraphBindings, type GraphTypeCompilation, type CompiledGraphType, type GraphType } from '@obversa/api';\n\nfunction issue(path: string, message: string): GraphValidationIssue {\n return { code: 'INVALID_GRAPH_TYPE', path, message };\n}\n\nfunction fail(path: string, message: string): never {\n throw new GraphValidationError('Invalid graph type.', [issue(path, message)]);\n}\n\nfunction name(value: unknown, path: string, label: string): string {\n if (\n typeof value !== 'string'\n || value.trim().length === 0\n || /[\\u0000-\\u001f\\u007f]/.test(value)\n ) {\n fail(path, `${label} must be a non-empty string without control characters.`);\n }\n return value;\n}\n\nfunction version(value: unknown, path: string): number {\n if (!Number.isSafeInteger(value) || (value as number) < 1) {\n fail(path, 'Graph type version must be a positive safe integer.');\n }\n return value as number;\n}\n\nfunction json<Value>(value: Value, path: string): Value {\n try {\n return cloneFrozenJson(value as unknown as JsonValue) as unknown as Value;\n } catch (error) {\n if (!(error instanceof JsonValueError)) throw error;\n fail(`${path}${error.path}`, error.message);\n }\n}\n\nfunction validateEvent<Event extends GraphEvent>(value: Event): Event {\n const event = json(value, '/event') as unknown;\n if (event === null || typeof event !== 'object' || Array.isArray(event)) {\n fail('/event', 'Event must be an object.');\n }\n const fields = Object.keys(event).sort();\n const expected = ['payload', 'type', 'version'];\n if (!isSameStringList(fields, expected)) {\n fail(\n '/event',\n `Event must contain exactly type, version, and payload; received ${fields.join(', ') || 'no fields'}.`,\n );\n }\n const safeEvent = event as Event;\n name(safeEvent.type, '/event/type', 'Event type');\n if (!Number.isSafeInteger(safeEvent.version) || safeEvent.version < 1) {\n fail('/event/version', 'Event version must be a positive safe integer.');\n }\n return safeEvent;\n}\n\nfunction isSameStringList(left: readonly string[], right: readonly string[]): boolean {\n return left.length === right.length && left.every((value, index) => value === right[index]);\n}\n\nfunction descriptionMismatch(path: string, message: string): never {\n throw new GraphValidationError(`Invalid graph plan: ${message}`, [{\n code: 'DESCRIPTION_MISMATCH',\n path,\n message,\n }]);\n}\n\nfunction assertCompiledDescription(\n description: GraphDescription,\n expected: {\n readonly kernel: GraphKernel;\n readonly kind: string;\n readonly typeVersion: number;\n readonly requirements: GraphRequirements;\n },\n): void {\n const { definition } = expected.kernel;\n if (\n description.graph.id !== definition.value.id\n || description.graph.definitionVersion !== definition.value.definitionVersion\n || description.graph.definitionDigest !== definition.digest\n || description.graph.kind !== expected.kind\n || description.graph.typeVersion !== expected.typeVersion\n || !isDeepStrictEqual(description.requirements, expected.requirements)\n ) {\n descriptionMismatch('/graph', 'Description metadata does not match the compiled graph.');\n }\n if (!isDeepStrictEqual(\n description.nodes.map((node) => node.id),\n definition.value.nodes.map((node) => node.id),\n )) {\n descriptionMismatch('/nodes', 'Description node order does not match the definition.');\n }\n if (!isDeepStrictEqual(description.edges, definition.value.edges.map((edge) => ({\n id: edge.id,\n source: edge.source,\n target: edge.target,\n })))) {\n descriptionMismatch('/edges', 'Description edges do not match the definition.');\n }\n}\n\n/** Validate a definition, then compile its trusted graph-type implementation. */\nexport function compileGraph<\n Definition extends GraphDefinition,\n State extends JsonValue,\n Event extends GraphEvent,\n Requirements extends GraphRequirements,\n>(\n graphType: GraphType<Definition, State, Event, Requirements>,\n definition: Definition,\n): CompiledGraphType<Definition, State, Event, Requirements> {\n const kind = name(graphType.kind, '/kind', 'Graph kind');\n const typeVersion = version(graphType.version, '/version');\n const kernel = createGraphKernel(definition);\n const implementation = graphType.compile(kernel.definition.value, kernel);\n if (!implementation || typeof implementation !== 'object') {\n fail('/compile', 'compile() must return a compiled graph object.');\n }\n const requirements = json(implementation.requirements, '/compile/requirements');\n if (requirements.memory !== 'required' && requirements.memory !== 'unused') {\n fail('/compile/requirements/memory', 'Memory must be required or unused.');\n }\n for (const method of ['initialState', 'reduce', 'decide', 'describe'] as const) {\n if (typeof implementation[method] !== 'function') {\n fail(`/compile/${method}`, `${method} must be a function.`);\n }\n }\n if (implementation.validateNodeResult !== undefined\n && typeof implementation.validateNodeResult !== 'function') {\n fail('/compile/validateNodeResult', 'validateNodeResult must be a function.');\n }\n\n const initialState = json(implementation.initialState(), '/initialState');\n const descriptionInput = json(\n implementation.describe(),\n '/description',\n ) as GraphDescriptionInput;\n const description = validateGraphDescription({\n ...descriptionInput,\n schemaVersion: 1,\n graph: {\n id: kernel.definition.value.id,\n definitionVersion: kernel.definition.value.definitionVersion,\n kind,\n typeVersion,\n definitionDigest: kernel.definition.digest,\n },\n edges: kernel.definition.value.edges.map((edge) => ({\n id: edge.id,\n source: edge.source,\n target: edge.target,\n })),\n requirements,\n });\n assertCompiledDescription(description, {\n kernel,\n kind,\n typeVersion,\n requirements,\n });\n\n return Object.freeze({\n definition: kernel.definition,\n requirements,\n initialState: () => initialState,\n ...(implementation.validateNodeResult === undefined ? {} : {\n validateNodeResult(nodeId: NodeId, result: JsonValue): GraphValidationIssue | null {\n if (kernel.node(nodeId) === undefined) {\n fail('/nodeId', `Unknown node \"${nodeId}\".`);\n }\n const returned = implementation.validateNodeResult!(nodeId, json(result, '/result'));\n if (returned === null) return null;\n const safeIssue = json(returned, '/validateNodeResult');\n if (safeIssue === null || typeof safeIssue !== 'object' || Array.isArray(safeIssue)\n || !isSameStringList(Object.keys(safeIssue).sort(), ['code', 'message', 'path'])\n || typeof safeIssue.code !== 'string' || typeof safeIssue.path !== 'string'\n || typeof safeIssue.message !== 'string') {\n fail('/validateNodeResult', 'validateNodeResult must return null or an issue with code, path, and message strings.');\n }\n return safeIssue;\n },\n }),\n reduce(state: State, event: Event): State {\n const safeState = json(state, '/state');\n const safeEvent = validateEvent(event);\n return json(implementation.reduce(safeState, safeEvent), '/reducedState');\n },\n decide(state: State): readonly GraphCommand[] {\n const safeState = json(state, '/state');\n return validateGraphCommands(implementation.decide(safeState), kernel);\n },\n describe: () => description,\n });\n}\n"]}
|