depa-actor 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.
@@ -0,0 +1,132 @@
1
+ /**
2
+ * depa-actor — ActorPipeline
3
+ *
4
+ * Adapts the DOP 6-step pipeline (from depa-processor) to actor context.
5
+ *
6
+ * Mapping:
7
+ * OuterRuntime = ActorSelf
8
+ * OuterInput = envelope payload
9
+ * OuterConfig = actor state
10
+ *
11
+ * createPipelineHandler() wraps a pipeline definition into an ActorHandler.
12
+ */
13
+
14
+ import type {
15
+ MailboxSchema,
16
+ ActorSelf,
17
+ ActorHandler,
18
+ } from '../core/types';
19
+
20
+ // ─── Pipeline Adapter Types ──────────────────────────────────────────
21
+
22
+ export type PipelineDerivedAdapter<
23
+ TRuntime, TSchema extends MailboxSchema, TState, TDerived,
24
+ > = (
25
+ self: ActorSelf<TRuntime, TSchema, TState>,
26
+ payload: TSchema[keyof TSchema & string],
27
+ state: TState,
28
+ ) => TDerived;
29
+
30
+ export type PipelineInnerRuntimeAdapter<
31
+ TRuntime, TSchema extends MailboxSchema, TState, TDerived, TInnerRuntime,
32
+ > = (
33
+ self: ActorSelf<TRuntime, TSchema, TState>,
34
+ payload: TSchema[keyof TSchema & string],
35
+ state: TState,
36
+ derived: TDerived,
37
+ ) => TInnerRuntime;
38
+
39
+ export type PipelineInnerInputAdapter<
40
+ TRuntime, TSchema extends MailboxSchema, TState, TDerived, TInnerInput,
41
+ > = (
42
+ self: ActorSelf<TRuntime, TSchema, TState>,
43
+ payload: TSchema[keyof TSchema & string],
44
+ state: TState,
45
+ derived: TDerived,
46
+ ) => TInnerInput;
47
+
48
+ export type PipelineInnerConfigAdapter<
49
+ TRuntime, TSchema extends MailboxSchema, TState, TDerived, TInnerConfig,
50
+ > = (
51
+ self: ActorSelf<TRuntime, TSchema, TState>,
52
+ payload: TSchema[keyof TSchema & string],
53
+ state: TState,
54
+ derived: TDerived,
55
+ ) => TInnerConfig;
56
+
57
+ export type PipelineCoreLogic<TInnerRuntime, TInnerInput, TInnerConfig, TInnerOutput> = (
58
+ runtime: TInnerRuntime,
59
+ input: TInnerInput,
60
+ config: TInnerConfig,
61
+ ) => TInnerOutput | Promise<TInnerOutput>;
62
+
63
+ export type PipelineOutputAdapter<
64
+ TRuntime, TSchema extends MailboxSchema, TState, TDerived, TInnerOutput,
65
+ > = (
66
+ self: ActorSelf<TRuntime, TSchema, TState>,
67
+ payload: TSchema[keyof TSchema & string],
68
+ state: TState,
69
+ derived: TDerived,
70
+ innerOutput: TInnerOutput,
71
+ ) => void | Promise<void>;
72
+
73
+ // ─── Pipeline Definition ─────────────────────────────────────────────
74
+
75
+ export interface ActorPipelineDef<
76
+ TRuntime,
77
+ TSchema extends MailboxSchema,
78
+ TState,
79
+ TDerived,
80
+ TInnerRuntime,
81
+ TInnerInput,
82
+ TInnerConfig,
83
+ TInnerOutput,
84
+ > {
85
+ computeDerived: PipelineDerivedAdapter<TRuntime, TSchema, TState, TDerived>;
86
+ innerRuntime: PipelineInnerRuntimeAdapter<TRuntime, TSchema, TState, TDerived, TInnerRuntime>;
87
+ innerInput: PipelineInnerInputAdapter<TRuntime, TSchema, TState, TDerived, TInnerInput>;
88
+ innerConfig: PipelineInnerConfigAdapter<TRuntime, TSchema, TState, TDerived, TInnerConfig>;
89
+ coreLogic: PipelineCoreLogic<TInnerRuntime, TInnerInput, TInnerConfig, TInnerOutput>;
90
+ output: PipelineOutputAdapter<TRuntime, TSchema, TState, TDerived, TInnerOutput>;
91
+ }
92
+
93
+ // ─── createPipelineHandler ───────────────────────────────────────────
94
+
95
+ export function createPipelineHandler<
96
+ TRuntime,
97
+ TSchema extends MailboxSchema,
98
+ TState,
99
+ TDerived,
100
+ TInnerRuntime,
101
+ TInnerInput,
102
+ TInnerConfig,
103
+ TInnerOutput,
104
+ >(
105
+ pipeline: ActorPipelineDef<
106
+ TRuntime, TSchema, TState, TDerived,
107
+ TInnerRuntime, TInnerInput, TInnerConfig, TInnerOutput
108
+ >,
109
+ ): ActorHandler<TRuntime, TSchema, TState> {
110
+ return async (self, envelope) => {
111
+ const payload = envelope.payload;
112
+ const state = self.state;
113
+
114
+ // Step 1: Compute derived
115
+ const derived = pipeline.computeDerived(self, payload, state);
116
+
117
+ // Step 2: Transform runtime
118
+ const innerRuntime = pipeline.innerRuntime(self, payload, state, derived);
119
+
120
+ // Step 3: Transform input
121
+ const innerInput = pipeline.innerInput(self, payload, state, derived);
122
+
123
+ // Step 4: Transform config
124
+ const innerConfig = pipeline.innerConfig(self, payload, state, derived);
125
+
126
+ // Step 5: Core logic
127
+ const innerOutput = await pipeline.coreLogic(innerRuntime, innerInput, innerConfig);
128
+
129
+ // Step 6: Output (side effects on actor state / send messages)
130
+ await pipeline.output(self, payload, state, derived, innerOutput);
131
+ };
132
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * depa-actor — ActorRuntime
3
+ *
4
+ * Lifecycle and plugin layer over ActorSystem.
5
+ * ActorSystem = engine, ActorRuntime = managed environment.
6
+ *
7
+ * Future AiAgentVm will hold an ActorRuntime instance.
8
+ */
9
+
10
+ import type {
11
+ MailboxSchema,
12
+ ActorDef,
13
+ ActorRef,
14
+ ActorLogEntry,
15
+ } from '../core/types';
16
+ import { ActorSystem } from '../core/ActorSystem';
17
+
18
+ // ─── Plugin ──────────────────────────────────────────────────────────
19
+
20
+ export interface ActorPlugin<TRuntime, TSchema extends MailboxSchema> {
21
+ name: string;
22
+ onRegister?: (id: string, def: ActorDef<TRuntime, TSchema, unknown>) => void;
23
+ onUnregister?: (id: string) => void;
24
+ onLog?: (entry: ActorLogEntry<TSchema>) => void;
25
+ }
26
+
27
+ // ─── ActorRuntime ────────────────────────────────────────────────────
28
+
29
+ export class ActorRuntime<TRuntime, TSchema extends MailboxSchema> {
30
+ readonly system: ActorSystem<TRuntime, TSchema>;
31
+ private plugins: ActorPlugin<TRuntime, TSchema>[] = [];
32
+ private facets = new Map<string, unknown>();
33
+
34
+ constructor(
35
+ getRuntime: () => TRuntime,
36
+ plugins?: ActorPlugin<TRuntime, TSchema>[],
37
+ ) {
38
+ this.plugins = plugins ?? [];
39
+
40
+ this.system = new ActorSystem<TRuntime, TSchema>(
41
+ getRuntime,
42
+ (entry) => this.handleLog(entry),
43
+ );
44
+ }
45
+
46
+ // ── Plugin management ──
47
+
48
+ addPlugin(plugin: ActorPlugin<TRuntime, TSchema>): void {
49
+ this.plugins.push(plugin);
50
+ }
51
+
52
+ hasFacet(name: string): boolean {
53
+ return this.facets.has(name);
54
+ }
55
+
56
+ getFacet<TFacet>(name: string): TFacet | undefined {
57
+ return this.facets.get(name) as TFacet | undefined;
58
+ }
59
+
60
+ setFacet<TFacet>(name: string, facet: TFacet): TFacet {
61
+ this.facets.set(name, facet);
62
+ return facet;
63
+ }
64
+
65
+ ensureFacet<TFacet>(name: string, create: () => TFacet): TFacet {
66
+ const existing = this.facets.get(name) as TFacet | undefined;
67
+ if (existing !== undefined) {
68
+ return existing;
69
+ }
70
+ const created = create();
71
+ this.facets.set(name, created);
72
+ return created;
73
+ }
74
+
75
+ // ── Delegated API (convenience) ──
76
+
77
+ register<TState = void>(id: string, def: ActorDef<TRuntime, TSchema, TState>): void {
78
+ this.system.register(id, def);
79
+ for (const p of this.plugins) {
80
+ p.onRegister?.(id, def as ActorDef<TRuntime, TSchema, unknown>);
81
+ }
82
+ }
83
+
84
+ unregister(id: string): void {
85
+ this.system.unregister(id);
86
+ for (const p of this.plugins) {
87
+ p.onUnregister?.(id);
88
+ }
89
+ }
90
+
91
+ sendFrom<TTag extends keyof TSchema & string>(
92
+ from: string,
93
+ to: string,
94
+ tag: TTag,
95
+ payload: TSchema[TTag],
96
+ ): void {
97
+ this.system.sendFrom(from, to, tag, payload);
98
+ }
99
+
100
+ refFrom(from: string, to: string): ActorRef<TSchema> | undefined {
101
+ return this.system.refFrom(from, to);
102
+ }
103
+
104
+ ids(): string[] {
105
+ return this.system.ids();
106
+ }
107
+
108
+ has(id: string): boolean {
109
+ return this.system.has(id);
110
+ }
111
+
112
+ // ── Internal ──
113
+
114
+ private handleLog(entry: ActorLogEntry<TSchema>): void {
115
+ for (const p of this.plugins) {
116
+ p.onLog?.(entry);
117
+ }
118
+ }
119
+ }
@@ -0,0 +1,86 @@
1
+ export type CompletionWaiter<TResult> = (result: TResult) => void;
2
+
3
+ export class CompletionSignalRegistry<TKey extends string, TResult> {
4
+ private readonly waiters = new Map<TKey, Set<CompletionWaiter<TResult>>>();
5
+
6
+ subscribe(key: TKey, waiter: CompletionWaiter<TResult>): () => void {
7
+ const current = this.waiters.get(key) ?? new Set<CompletionWaiter<TResult>>();
8
+ current.add(waiter);
9
+ this.waiters.set(key, current);
10
+ return () => {
11
+ const next = this.waiters.get(key);
12
+ if (!next) {
13
+ return;
14
+ }
15
+ next.delete(waiter);
16
+ if (next.size === 0) {
17
+ this.waiters.delete(key);
18
+ }
19
+ };
20
+ }
21
+
22
+ resolve(key: TKey, result: TResult): void {
23
+ const waiters = this.waiters.get(key);
24
+ if (!waiters || waiters.size === 0) {
25
+ return;
26
+ }
27
+ this.waiters.delete(key);
28
+ for (const waiter of Array.from(waiters)) {
29
+ waiter(result);
30
+ }
31
+ }
32
+
33
+ has(key: TKey): boolean {
34
+ return (this.waiters.get(key)?.size ?? 0) > 0;
35
+ }
36
+
37
+ count(key: TKey): number {
38
+ return this.waiters.get(key)?.size ?? 0;
39
+ }
40
+
41
+ clear(key?: TKey): void {
42
+ if (key !== undefined) {
43
+ this.waiters.delete(key);
44
+ return;
45
+ }
46
+ this.waiters.clear();
47
+ }
48
+ }
49
+
50
+ export function createCompletionSignalRegistry<TKey extends string, TResult>(): CompletionSignalRegistry<TKey, TResult> {
51
+ return new CompletionSignalRegistry<TKey, TResult>();
52
+ }
53
+
54
+ export class CompletionBindingRegistry<TKey extends string, TBinding> {
55
+ private readonly bindings: Record<TKey, TBinding>;
56
+
57
+ constructor(initial?: Record<TKey, TBinding>) {
58
+ this.bindings = Object.assign(Object.create(null) as Record<TKey, TBinding>, initial ?? {});
59
+ }
60
+
61
+ get(key: TKey): TBinding | undefined {
62
+ return this.bindings[key];
63
+ }
64
+
65
+ set(key: TKey, binding: TBinding): void {
66
+ this.bindings[key] = binding;
67
+ }
68
+
69
+ delete(key: TKey): void {
70
+ delete this.bindings[key];
71
+ }
72
+
73
+ has(key: TKey): boolean {
74
+ return key in this.bindings;
75
+ }
76
+
77
+ snapshot(): Record<TKey, TBinding> {
78
+ return { ...this.bindings };
79
+ }
80
+ }
81
+
82
+ export function createCompletionBindingRegistry<TKey extends string, TBinding>(
83
+ initial?: Record<TKey, TBinding>,
84
+ ): CompletionBindingRegistry<TKey, TBinding> {
85
+ return new CompletionBindingRegistry<TKey, TBinding>(initial);
86
+ }
@@ -0,0 +1,39 @@
1
+ export class RuntimeIndexHook<TKey extends string, TValue> {
2
+ private readonly entries = new Map<TKey, TValue>();
3
+
4
+ constructor(initial?: Record<TKey, TValue>) {
5
+ for (const [key, value] of Object.entries(initial ?? {}) as Array<[TKey, TValue]>) {
6
+ this.entries.set(key, value);
7
+ }
8
+ }
9
+
10
+ get(key: TKey): TValue | undefined {
11
+ return this.entries.get(key);
12
+ }
13
+
14
+ set(key: TKey, value: TValue): void {
15
+ this.entries.set(key, value);
16
+ }
17
+
18
+ delete(key: TKey): void {
19
+ this.entries.delete(key);
20
+ }
21
+
22
+ has(key: TKey): boolean {
23
+ return this.entries.has(key);
24
+ }
25
+
26
+ values(): TValue[] {
27
+ return Array.from(this.entries.values());
28
+ }
29
+
30
+ snapshot(): Record<TKey, TValue> {
31
+ return Object.fromEntries(this.entries.entries()) as Record<TKey, TValue>;
32
+ }
33
+ }
34
+
35
+ export function createRuntimeIndexHook<TKey extends string, TValue>(
36
+ initial?: Record<TKey, TValue>,
37
+ ): RuntimeIndexHook<TKey, TValue> {
38
+ return new RuntimeIndexHook<TKey, TValue>(initial);
39
+ }
@@ -0,0 +1,91 @@
1
+ export type SnapshotRecoveryState = {
2
+ restoredFromSnapshot: boolean;
3
+ snapshotVersion?: number;
4
+ restoredAt?: number;
5
+ };
6
+
7
+ export type RuntimeSnapshotManifestBase = {
8
+ version: number;
9
+ createdAt: string;
10
+ updatedAt: string;
11
+ actorKeys: string[];
12
+ fiberIds: string[];
13
+ indexFiles: string[];
14
+ derivedIndexFiles?: string[];
15
+ savedAt?: number;
16
+ vmFile: string;
17
+ actorFiles: Record<string, string>;
18
+ fiberFiles: Record<string, string>;
19
+ };
20
+
21
+ export type RuntimeRootSnapshotBase = {
22
+ version: number;
23
+ controlActorKey: string;
24
+ actorKeys: string[];
25
+ updatedAt: string;
26
+ recovery?: SnapshotRecoveryState;
27
+ };
28
+
29
+ export type ActorSnapshotBase<TActorType extends string = string> = {
30
+ version: number;
31
+ key: string;
32
+ id: string;
33
+ type: TActorType;
34
+ parentKey?: string;
35
+ updatedAt?: string;
36
+ recovery?: SnapshotRecoveryState;
37
+ };
38
+
39
+ export type FiberSnapshotBase = {
40
+ version: number;
41
+ fiberId: string;
42
+ actorKey?: string;
43
+ actorId?: string;
44
+ parentFiberId?: string;
45
+ status?: string;
46
+ lane?: string;
47
+ workloadKind?: string;
48
+ kind?: string;
49
+ waitingReason?: string | null;
50
+ createdAt?: number;
51
+ lastRunAt?: number | null;
52
+ lastYieldAt?: number | null;
53
+ resumeMetadata?: Record<string, unknown> | null;
54
+ updatedAt?: string;
55
+ workload?: string;
56
+ metadata?: Record<string, unknown>;
57
+ };
58
+
59
+ export interface SnapshotCodec<TState, TSnapshot> {
60
+ serialize: (state: TState) => TSnapshot;
61
+ hydrate: (snapshot: TSnapshot) => TState;
62
+ }
63
+
64
+ export interface RecoveryHooks<TState, TSnapshot> {
65
+ beforeSerialize?: (state: TState) => TState;
66
+ beforeHydrate?: (snapshot: TSnapshot) => TSnapshot;
67
+ afterHydrate?: (state: TState) => TState;
68
+ }
69
+
70
+ export interface PersistenceEffectPort<TManifest, TSnapshotState> {
71
+ save: (params: { manifest: TManifest; state: TSnapshotState }) => Promise<void>;
72
+ load: () => Promise<{ manifest: TManifest; state: TSnapshotState } | null>;
73
+ }
74
+
75
+ export function createSnapshotCodec<TState, TSnapshot>(
76
+ codec: SnapshotCodec<TState, TSnapshot>,
77
+ ): SnapshotCodec<TState, TSnapshot> {
78
+ return codec;
79
+ }
80
+
81
+ export function createRecoveryHooks<TState, TSnapshot>(
82
+ hooks: RecoveryHooks<TState, TSnapshot>,
83
+ ): RecoveryHooks<TState, TSnapshot> {
84
+ return hooks;
85
+ }
86
+
87
+ export function createPersistenceEffectPort<TManifest, TSnapshotState>(
88
+ port: PersistenceEffectPort<TManifest, TSnapshotState>,
89
+ ): PersistenceEffectPort<TManifest, TSnapshotState> {
90
+ return port;
91
+ }