holarchy-eidolon-adapter 0.2.0 → 0.2.2

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.
@@ -1,388 +0,0 @@
1
- import {
2
- parseActorRegistrationReceipt,
3
- type ActorRegistrationReceipt,
4
- } from "depa-actor"
5
- import type { AIAgentSelector } from "ai-workflow-contract"
6
-
7
- import { HolarchyEidolonAdapterError } from "./HolarchyEidolonAdapterError"
8
-
9
- export const HOLON_DEPLOYMENT_RUNTIME_SCHEMA_VERSION =
10
- "eidolon.holon-deployment-runtime/v1" as const
11
-
12
- export type HolonCoordinatorLifecycleStatus = "registered" | "ready" | "stopped"
13
- export type HolonMemberRuntimeLifecycleStatus = "registered" | "ready" | "stopped"
14
- export type HolonTaskSpaceSubscriptionStatus = "observing" | "paused" | "closed"
15
-
16
- export type HolonMemberRuntimeIsolation =
17
- | Readonly<{ readonly mode: "shared" }>
18
- | Readonly<{
19
- readonly mode: "isolated"
20
- readonly scope: "task-space" | "workflow-run"
21
- readonly isolationKey: string
22
- }>
23
-
24
- export type HolonGenericSessionRef =
25
- | Readonly<{
26
- readonly mode: "task-attempt"
27
- readonly taskSpaceId: string
28
- readonly taskId: string
29
- readonly claimId: string
30
- readonly attempt: number
31
- readonly workflowInstanceId?: string
32
- readonly runId?: string
33
- readonly sessionRef: string
34
- }>
35
- | Readonly<{
36
- readonly mode: "targeted-agent-instance"
37
- readonly selector: AIAgentSelector
38
- readonly sessionRef: string
39
- }>
40
-
41
- export interface HolonCoordinatorLifecycleFact {
42
- readonly holonRef: string
43
- readonly status: HolonCoordinatorLifecycleStatus
44
- readonly actorRef: string
45
- readonly registrationReceipt: ActorRegistrationReceipt
46
- }
47
-
48
- export interface HolonMemberRuntimeLifecycleFact {
49
- readonly runtimeRef: string
50
- readonly holonRef: string
51
- readonly memberRef: string
52
- readonly isolation: HolonMemberRuntimeIsolation
53
- readonly status: HolonMemberRuntimeLifecycleStatus
54
- readonly actorRef: string
55
- readonly registrationReceipt: ActorRegistrationReceipt
56
- readonly sessions: readonly HolonGenericSessionRef[]
57
- }
58
-
59
- export interface HolonTaskSpaceSubscriptionFact {
60
- readonly taskSpaceId: string
61
- readonly holonRef: string
62
- readonly cursor: string
63
- readonly status: HolonTaskSpaceSubscriptionStatus
64
- }
65
-
66
- export interface HolonDeploymentRuntimeSnapshot {
67
- readonly schemaVersion: typeof HOLON_DEPLOYMENT_RUNTIME_SCHEMA_VERSION
68
- readonly deploymentId: string
69
- readonly definitionSemanticFingerprint: `sha256:${string}`
70
- readonly revision: number
71
- readonly coordinators: readonly HolonCoordinatorLifecycleFact[]
72
- readonly members: readonly HolonMemberRuntimeLifecycleFact[]
73
- readonly subscriptions: readonly HolonTaskSpaceSubscriptionFact[]
74
- }
75
-
76
- const compareUtf16 = (left: string, right: string): number =>
77
- left < right ? -1 : left > right ? 1 : 0
78
-
79
- const invalid = (location: string, message: string): never => {
80
- throw new HolarchyEidolonAdapterError(
81
- "EIDOLON_HOLON_DEPLOYMENT_RUNTIME_INVALID",
82
- `${location}: ${message}`,
83
- )
84
- }
85
-
86
- function closedObject(value: unknown, location: string): Readonly<Record<string, unknown>> {
87
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
88
- return invalid(location, "Expected a plain object")
89
- }
90
- const prototype = Object.getPrototypeOf(value)
91
- if (prototype !== Object.prototype && prototype !== null) {
92
- return invalid(location, "Expected a plain object")
93
- }
94
- const descriptors = Object.getOwnPropertyDescriptors(value)
95
- const keys = Reflect.ownKeys(descriptors)
96
- if (keys.some((key) => typeof key !== "string")) {
97
- return invalid(location, "Symbol properties are not allowed")
98
- }
99
- const result: Record<string, unknown> = Object.create(null)
100
- for (const key of keys as string[]) {
101
- const descriptor = descriptors[key]
102
- if (!descriptor || !("value" in descriptor) || descriptor.enumerable !== true) {
103
- return invalid(`${location}.${key}`, "Expected one enumerable own-data property")
104
- }
105
- result[key] = descriptor.value
106
- }
107
- return result
108
- }
109
-
110
- function exactKeys(value: Readonly<Record<string, unknown>>, expected: readonly string[], location: string): void {
111
- const allowed = new Set(expected)
112
- const extra = Object.keys(value).find((key) => !allowed.has(key))
113
- if (extra !== undefined) invalid(`${location}.${extra}`, "Unsupported field")
114
- const missing = expected.find((key) => !Object.prototype.hasOwnProperty.call(value, key))
115
- if (missing !== undefined) invalid(`${location}.${missing}`, "Required field is missing")
116
- }
117
-
118
- function denseArray(value: unknown, location: string): readonly unknown[] {
119
- if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype) {
120
- return invalid(location, "Expected a plain dense array")
121
- }
122
- const descriptors = Object.getOwnPropertyDescriptors(value)
123
- for (let index = 0; index < value.length; index += 1) {
124
- const descriptor = descriptors[String(index)]
125
- if (!descriptor || !("value" in descriptor) || descriptor.enumerable !== true) {
126
- return invalid(`${location}[${index}]`, "Expected a dense enumerable own-data entry")
127
- }
128
- }
129
- for (const key of Reflect.ownKeys(descriptors)) {
130
- if (key === "length") continue
131
- if (typeof key !== "string" || !/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= value.length) {
132
- return invalid(location, "Symbol and extra array properties are not allowed")
133
- }
134
- }
135
- return value
136
- }
137
-
138
- function exactString(value: unknown, location: string): string {
139
- if (typeof value !== "string" || value.length === 0 || value !== value.trim()
140
- || value !== value.normalize("NFC") || /[\u0000-\u001f\u007f]/.test(value)) {
141
- return invalid(location, "Expected one exact canonical non-empty string")
142
- }
143
- return value
144
- }
145
-
146
- function exactLiteral<T extends string>(value: unknown, expected: T, location: string): T {
147
- if (value !== expected) invalid(location, `Expected '${expected}'`)
148
- return expected
149
- }
150
-
151
- function exactUnion<T extends string>(value: unknown, expected: readonly T[], location: string): T {
152
- const exact = exactString(value, location)
153
- if (!expected.includes(exact as T)) invalid(location, `Expected ${expected.join(" | ")}`)
154
- return exact as T
155
- }
156
-
157
- function digest(value: unknown, location: string): `sha256:${string}` {
158
- if (typeof value !== "string" || !/^sha256:[0-9a-f]{64}$/.test(value)) {
159
- return invalid(location, "Expected one canonical sha256 digest")
160
- }
161
- return value as `sha256:${string}`
162
- }
163
-
164
- function receipt(value: unknown, location: string): ActorRegistrationReceipt {
165
- try {
166
- return parseActorRegistrationReceipt(value)
167
- } catch (error) {
168
- return invalid(location, error instanceof Error ? error.message : "Invalid depa-actor registration receipt")
169
- }
170
- }
171
-
172
- function isolation(value: unknown, location: string): HolonMemberRuntimeIsolation {
173
- const record = closedObject(value, location)
174
- const mode = exactString(record.mode, `${location}.mode`)
175
- if (mode === "shared") {
176
- exactKeys(record, ["mode"], location)
177
- return Object.freeze({ mode })
178
- }
179
- if (mode === "isolated") {
180
- exactKeys(record, ["mode", "scope", "isolationKey"], location)
181
- return Object.freeze({
182
- mode,
183
- scope: exactUnion(record.scope, ["task-space", "workflow-run"] as const, `${location}.scope`),
184
- isolationKey: exactString(record.isolationKey, `${location}.isolationKey`),
185
- })
186
- }
187
- return invalid(`${location}.mode`, "Expected shared | isolated")
188
- }
189
-
190
- function coordinator(value: unknown, index: number): HolonCoordinatorLifecycleFact {
191
- const location = `$.coordinators[${index}]`
192
- const record = closedObject(value, location)
193
- exactKeys(record, ["holonRef", "status", "actorRef", "registrationReceipt"], location)
194
- const registrationReceipt = receipt(record.registrationReceipt, `${location}.registrationReceipt`)
195
- if (registrationReceipt.address.actorKind !== "coordinator") {
196
- invalid(`${location}.registrationReceipt.address.actorKind`, "Expected coordinator")
197
- }
198
- return Object.freeze({
199
- holonRef: exactString(record.holonRef, `${location}.holonRef`),
200
- status: exactUnion(record.status, ["registered", "ready", "stopped"] as const, `${location}.status`),
201
- actorRef: exactString(record.actorRef, `${location}.actorRef`),
202
- registrationReceipt,
203
- })
204
- }
205
-
206
- function session(value: unknown, location: string): HolonGenericSessionRef {
207
- const record = closedObject(value, location)
208
- const mode = exactString(record.mode, `${location}.mode`)
209
- if (mode === "task-attempt") {
210
- const optional = ["workflowInstanceId", "runId"].filter((key) => (
211
- Object.prototype.hasOwnProperty.call(record, key)
212
- ))
213
- exactKeys(record, [
214
- "mode", "taskSpaceId", "taskId", "claimId", "attempt", "sessionRef", ...optional,
215
- ], location)
216
- if (!Number.isSafeInteger(record.attempt) || (record.attempt as number) <= 0) {
217
- invalid(`${location}.attempt`, "Expected one positive safe integer")
218
- }
219
- return Object.freeze({
220
- mode,
221
- taskSpaceId: exactString(record.taskSpaceId, `${location}.taskSpaceId`),
222
- taskId: exactString(record.taskId, `${location}.taskId`),
223
- claimId: exactString(record.claimId, `${location}.claimId`),
224
- attempt: record.attempt as number,
225
- ...(record.workflowInstanceId === undefined
226
- ? {}
227
- : { workflowInstanceId: exactString(record.workflowInstanceId, `${location}.workflowInstanceId`) }),
228
- ...(record.runId === undefined ? {} : { runId: exactString(record.runId, `${location}.runId`) }),
229
- sessionRef: exactString(record.sessionRef, `${location}.sessionRef`),
230
- })
231
- }
232
- if (mode === "targeted-agent-instance") {
233
- exactKeys(record, ["mode", "selector", "sessionRef"], location)
234
- const selectorRecord = closedObject(record.selector, `${location}.selector`)
235
- const hasId = Object.prototype.hasOwnProperty.call(selectorRecord, "byId")
236
- const hasName = Object.prototype.hasOwnProperty.call(selectorRecord, "byName")
237
- if (hasId === hasName) invalid(`${location}.selector`, "Expected exactly one targeted Agent selector")
238
- exactKeys(selectorRecord, [hasId ? "byId" : "byName"], `${location}.selector`)
239
- const selector = (hasId
240
- ? Object.freeze({ byId: exactString(selectorRecord.byId, `${location}.selector.byId`) })
241
- : Object.freeze({ byName: exactString(selectorRecord.byName, `${location}.selector.byName`) })) as unknown as AIAgentSelector
242
- return Object.freeze({
243
- mode,
244
- selector,
245
- sessionRef: exactString(record.sessionRef, `${location}.sessionRef`),
246
- })
247
- }
248
- return invalid(`${location}.mode`, "Expected task-attempt | targeted-agent-instance")
249
- }
250
-
251
- function sessionIdentity(value: HolonGenericSessionRef): string {
252
- return value.mode === "task-attempt"
253
- ? JSON.stringify([value.mode, value.taskSpaceId, value.taskId, value.claimId, value.attempt])
254
- : JSON.stringify([value.mode, value.selector])
255
- }
256
-
257
- function member(value: unknown, index: number): HolonMemberRuntimeLifecycleFact {
258
- const location = `$.members[${index}]`
259
- const record = closedObject(value, location)
260
- exactKeys(record, [
261
- "runtimeRef",
262
- "holonRef",
263
- "memberRef",
264
- "isolation",
265
- "status",
266
- "actorRef",
267
- "registrationReceipt",
268
- "sessions",
269
- ], location)
270
- const registrationReceipt = receipt(record.registrationReceipt, `${location}.registrationReceipt`)
271
- if (registrationReceipt.address.actorKind !== "member") {
272
- invalid(`${location}.registrationReceipt.address.actorKind`, "Expected member")
273
- }
274
- const sessions = denseArray(record.sessions, `${location}.sessions`)
275
- .map((entry, sessionIndex) => session(entry, `${location}.sessions[${sessionIndex}]`))
276
- .sort((left, right) => compareUtf16(sessionIdentity(left), sessionIdentity(right)))
277
- if (new Set(sessions.map(sessionIdentity)).size !== sessions.length) {
278
- invalid(`${location}.sessions`, "Session scope identities must be unique")
279
- }
280
- return Object.freeze({
281
- runtimeRef: exactString(record.runtimeRef, `${location}.runtimeRef`),
282
- holonRef: exactString(record.holonRef, `${location}.holonRef`),
283
- memberRef: exactString(record.memberRef, `${location}.memberRef`),
284
- isolation: isolation(record.isolation, `${location}.isolation`),
285
- status: exactUnion(record.status, ["registered", "ready", "stopped"] as const, `${location}.status`),
286
- actorRef: exactString(record.actorRef, `${location}.actorRef`),
287
- registrationReceipt,
288
- sessions: Object.freeze(sessions),
289
- })
290
- }
291
-
292
- function subscription(value: unknown, index: number): HolonTaskSpaceSubscriptionFact {
293
- const location = `$.subscriptions[${index}]`
294
- const record = closedObject(value, location)
295
- exactKeys(record, ["taskSpaceId", "holonRef", "cursor", "status"], location)
296
- return Object.freeze({
297
- taskSpaceId: exactString(record.taskSpaceId, `${location}.taskSpaceId`),
298
- holonRef: exactString(record.holonRef, `${location}.holonRef`),
299
- cursor: exactString(record.cursor, `${location}.cursor`),
300
- status: exactUnion(record.status, ["observing", "paused", "closed"] as const, `${location}.status`),
301
- })
302
- }
303
-
304
- function unique<T>(values: readonly T[], identity: (value: T) => string, location: string): void {
305
- if (new Set(values.map(identity)).size !== values.length) invalid(location, "Contains a duplicate identity")
306
- }
307
-
308
- export function normalizeHolonDeploymentRuntimeSnapshot(value: unknown): HolonDeploymentRuntimeSnapshot {
309
- const record = closedObject(value, "$")
310
- exactKeys(record, [
311
- "schemaVersion",
312
- "deploymentId",
313
- "definitionSemanticFingerprint",
314
- "revision",
315
- "coordinators",
316
- "members",
317
- "subscriptions",
318
- ], "$")
319
- if (!Number.isSafeInteger(record.revision) || (record.revision as number) < 0) {
320
- invalid("$.revision", "Expected one non-negative safe integer")
321
- }
322
- const coordinators = denseArray(record.coordinators, "$.coordinators")
323
- .map(coordinator)
324
- .sort((left, right) => compareUtf16(left.holonRef, right.holonRef))
325
- const members = denseArray(record.members, "$.members")
326
- .map(member)
327
- .sort((left, right) => compareUtf16(left.runtimeRef, right.runtimeRef))
328
- const subscriptions = denseArray(record.subscriptions, "$.subscriptions")
329
- .map(subscription)
330
- .sort((left, right) => compareUtf16(left.taskSpaceId, right.taskSpaceId))
331
- unique(coordinators, (entry) => entry.holonRef, "$.coordinators")
332
- unique(members, (entry) => entry.runtimeRef, "$.members")
333
- unique(subscriptions, (entry) => entry.taskSpaceId, "$.subscriptions")
334
- const deploymentId = exactString(record.deploymentId, "$.deploymentId")
335
- for (const entry of [...coordinators, ...members]) {
336
- if (entry.registrationReceipt.address.deploymentId !== deploymentId) {
337
- invalid("$.deploymentId", "All actor registration receipts must belong to this deployment")
338
- }
339
- }
340
- return Object.freeze({
341
- schemaVersion: exactLiteral(
342
- record.schemaVersion,
343
- HOLON_DEPLOYMENT_RUNTIME_SCHEMA_VERSION,
344
- "$.schemaVersion",
345
- ),
346
- deploymentId,
347
- definitionSemanticFingerprint: digest(
348
- record.definitionSemanticFingerprint,
349
- "$.definitionSemanticFingerprint",
350
- ),
351
- revision: record.revision as number,
352
- coordinators: Object.freeze(coordinators),
353
- members: Object.freeze(members),
354
- subscriptions: Object.freeze(subscriptions),
355
- })
356
- }
357
-
358
- function sameBytes(left: Uint8Array, right: Uint8Array): boolean {
359
- if (left.byteLength !== right.byteLength) return false
360
- for (let index = 0; index < left.byteLength; index += 1) {
361
- if (left[index] !== right[index]) return false
362
- }
363
- return true
364
- }
365
-
366
- export function canonicalHolonDeploymentRuntimeSnapshotBytes(value: unknown): Uint8Array {
367
- return new TextEncoder().encode(JSON.stringify(normalizeHolonDeploymentRuntimeSnapshot(value)))
368
- }
369
-
370
- export function parseHolonDeploymentRuntimeSnapshotBytes(bytes: Uint8Array): HolonDeploymentRuntimeSnapshot {
371
- let decoded: string
372
- try {
373
- decoded = new TextDecoder("utf-8", { fatal: true }).decode(bytes)
374
- } catch {
375
- return invalid("$bytes", "Runtime bytes are not valid UTF-8")
376
- }
377
- let value: unknown
378
- try {
379
- value = JSON.parse(decoded)
380
- } catch {
381
- return invalid("$bytes", "Runtime bytes are not valid JSON")
382
- }
383
- const snapshot = normalizeHolonDeploymentRuntimeSnapshot(value)
384
- if (!sameBytes(bytes, canonicalHolonDeploymentRuntimeSnapshotBytes(snapshot))) {
385
- return invalid("$bytes", "Runtime bytes are not canonical")
386
- }
387
- return snapshot
388
- }