@agentxjs/core 1.9.1-dev
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/package.json +31 -0
- package/src/agent/AgentStateMachine.ts +151 -0
- package/src/agent/README.md +296 -0
- package/src/agent/__tests__/AgentStateMachine.test.ts +346 -0
- package/src/agent/__tests__/createAgent.test.ts +728 -0
- package/src/agent/__tests__/engine/internal/messageAssemblerProcessor.test.ts +567 -0
- package/src/agent/__tests__/engine/internal/stateEventProcessor.test.ts +315 -0
- package/src/agent/__tests__/engine/internal/turnTrackerProcessor.test.ts +340 -0
- package/src/agent/__tests__/engine/mealy/Mealy.test.ts +370 -0
- package/src/agent/__tests__/engine/mealy/Store.test.ts +123 -0
- package/src/agent/__tests__/engine/mealy/combinators.test.ts +322 -0
- package/src/agent/createAgent.ts +467 -0
- package/src/agent/engine/AgentProcessor.ts +106 -0
- package/src/agent/engine/MealyMachine.ts +184 -0
- package/src/agent/engine/internal/index.ts +35 -0
- package/src/agent/engine/internal/messageAssemblerProcessor.ts +550 -0
- package/src/agent/engine/internal/stateEventProcessor.ts +313 -0
- package/src/agent/engine/internal/turnTrackerProcessor.ts +239 -0
- package/src/agent/engine/mealy/Mealy.ts +308 -0
- package/src/agent/engine/mealy/Processor.ts +70 -0
- package/src/agent/engine/mealy/Sink.ts +56 -0
- package/src/agent/engine/mealy/Source.ts +51 -0
- package/src/agent/engine/mealy/Store.ts +98 -0
- package/src/agent/engine/mealy/combinators.ts +176 -0
- package/src/agent/engine/mealy/index.ts +45 -0
- package/src/agent/index.ts +106 -0
- package/src/agent/types/engine.ts +395 -0
- package/src/agent/types/event.ts +478 -0
- package/src/agent/types/index.ts +197 -0
- package/src/agent/types/message.ts +387 -0
- package/src/common/index.ts +8 -0
- package/src/common/logger/ConsoleLogger.ts +137 -0
- package/src/common/logger/LoggerFactoryImpl.ts +123 -0
- package/src/common/logger/index.ts +26 -0
- package/src/common/logger/types.ts +98 -0
- package/src/container/Container.ts +185 -0
- package/src/container/index.ts +44 -0
- package/src/container/types.ts +71 -0
- package/src/driver/index.ts +42 -0
- package/src/driver/types.ts +363 -0
- package/src/event/EventBus.ts +260 -0
- package/src/event/README.md +237 -0
- package/src/event/__tests__/EventBus.test.ts +251 -0
- package/src/event/index.ts +46 -0
- package/src/event/types/agent.ts +512 -0
- package/src/event/types/base.ts +241 -0
- package/src/event/types/bus.ts +429 -0
- package/src/event/types/command.ts +749 -0
- package/src/event/types/container.ts +471 -0
- package/src/event/types/driver.ts +452 -0
- package/src/event/types/index.ts +26 -0
- package/src/event/types/session.ts +314 -0
- package/src/image/Image.ts +203 -0
- package/src/image/index.ts +36 -0
- package/src/image/types.ts +77 -0
- package/src/index.ts +20 -0
- package/src/mq/OffsetGenerator.ts +48 -0
- package/src/mq/README.md +166 -0
- package/src/mq/__tests__/OffsetGenerator.test.ts +121 -0
- package/src/mq/index.ts +18 -0
- package/src/mq/types.ts +172 -0
- package/src/network/RpcClient.ts +455 -0
- package/src/network/index.ts +76 -0
- package/src/network/jsonrpc.ts +336 -0
- package/src/network/protocol.ts +90 -0
- package/src/network/types.ts +284 -0
- package/src/persistence/index.ts +27 -0
- package/src/persistence/types.ts +226 -0
- package/src/runtime/AgentXRuntime.ts +501 -0
- package/src/runtime/index.ts +56 -0
- package/src/runtime/types.ts +236 -0
- package/src/session/Session.ts +71 -0
- package/src/session/index.ts +25 -0
- package/src/session/types.ts +77 -0
- package/src/workspace/index.ts +27 -0
- package/src/workspace/types.ts +131 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mealy - The Mealy Machine runtime
|
|
3
|
+
*
|
|
4
|
+
* A Mealy Machine is a finite-state machine where outputs depend on
|
|
5
|
+
* both the current state AND the input: (state, input) => (state, output)
|
|
6
|
+
*
|
|
7
|
+
* This runtime orchestrates the complete processing pipeline:
|
|
8
|
+
* 1. Sources receive external input (side effects)
|
|
9
|
+
* 2. Processors process inputs (pure Mealy transition functions)
|
|
10
|
+
* 3. Sinks produce output effects (side effects)
|
|
11
|
+
*
|
|
12
|
+
* Architecture:
|
|
13
|
+
* - Inputs enter through Sources (input adapters)
|
|
14
|
+
* - Processors transform inputs (pure functions, state is means)
|
|
15
|
+
* - Sinks produce actions (output adapters)
|
|
16
|
+
*
|
|
17
|
+
* @template TState - The state type (accumulator, means to an end)
|
|
18
|
+
* @template TInput - The input/output type for Processors
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const mealy = createMealy({
|
|
23
|
+
* processor: messageProcessor,
|
|
24
|
+
* store: new MemoryStore(),
|
|
25
|
+
* initialState: { text: '' },
|
|
26
|
+
* sinks: [sseSink, logSink],
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Process an input
|
|
30
|
+
* mealy.process('agent_123', input);
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type { Processor } from "./Processor";
|
|
35
|
+
import type { Store } from "./Store";
|
|
36
|
+
import type { Sink, SinkDefinition } from "./Sink";
|
|
37
|
+
import { createLogger } from "commonxjs/logger";
|
|
38
|
+
|
|
39
|
+
const logger = createLogger("engine/Mealy");
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* MealyConfig - Configuration for creating a Mealy instance
|
|
43
|
+
*/
|
|
44
|
+
export interface MealyConfig<TState, TInput> {
|
|
45
|
+
/**
|
|
46
|
+
* The processor function to execute (pure Mealy transition function)
|
|
47
|
+
*/
|
|
48
|
+
processor: Processor<TState, TInput, TInput>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The store for state persistence
|
|
52
|
+
*/
|
|
53
|
+
store: Store<TState>;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Initial state for new IDs
|
|
57
|
+
*/
|
|
58
|
+
initialState: TState;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sinks to receive outputs
|
|
62
|
+
* Can be simple Sink functions or SinkDefinitions with filter/name
|
|
63
|
+
*/
|
|
64
|
+
sinks?: (Sink<TInput> | SinkDefinition<TInput>)[];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Whether to recursively process outputs
|
|
68
|
+
* If true, outputs are fed back into the processor
|
|
69
|
+
*
|
|
70
|
+
* @default true
|
|
71
|
+
*/
|
|
72
|
+
recursive?: boolean;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Maximum recursion depth to prevent infinite loops
|
|
76
|
+
*
|
|
77
|
+
* @default 100
|
|
78
|
+
*/
|
|
79
|
+
maxDepth?: number;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* ProcessResult - Result of processing an input
|
|
84
|
+
*/
|
|
85
|
+
export interface ProcessResult<TState, TOutput> {
|
|
86
|
+
/**
|
|
87
|
+
* The new state after processing
|
|
88
|
+
*/
|
|
89
|
+
state: TState;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* All outputs produced (including from recursion)
|
|
93
|
+
*/
|
|
94
|
+
outputs: TOutput[];
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Number of processor invocations (including recursion)
|
|
98
|
+
*/
|
|
99
|
+
processCount: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Mealy - Mealy Machine runtime
|
|
104
|
+
*
|
|
105
|
+
* Implements the Mealy Machine pattern: (state, input) => (state, output)
|
|
106
|
+
* where output depends on both current state and input.
|
|
107
|
+
*/
|
|
108
|
+
export class Mealy<TState, TInput> {
|
|
109
|
+
private readonly processor: Processor<TState, TInput, TInput>;
|
|
110
|
+
private readonly store: Store<TState>;
|
|
111
|
+
private readonly initialState: TState;
|
|
112
|
+
private readonly sinks: (Sink<TInput> | SinkDefinition<TInput>)[];
|
|
113
|
+
private readonly recursive: boolean;
|
|
114
|
+
private readonly maxDepth: number;
|
|
115
|
+
|
|
116
|
+
constructor(config: MealyConfig<TState, TInput>) {
|
|
117
|
+
this.processor = config.processor;
|
|
118
|
+
this.store = config.store;
|
|
119
|
+
this.initialState = config.initialState;
|
|
120
|
+
this.sinks = config.sinks ?? [];
|
|
121
|
+
this.recursive = config.recursive ?? true;
|
|
122
|
+
this.maxDepth = config.maxDepth ?? 100;
|
|
123
|
+
|
|
124
|
+
logger.debug("Mealy instance created", {
|
|
125
|
+
sinkCount: this.sinks.length,
|
|
126
|
+
recursive: this.recursive,
|
|
127
|
+
maxDepth: this.maxDepth,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Process an input through the Mealy Machine
|
|
133
|
+
*
|
|
134
|
+
* @param id - Unique identifier (e.g., agentId)
|
|
135
|
+
* @param input - The input to process
|
|
136
|
+
* @returns Result containing new state and all outputs
|
|
137
|
+
*/
|
|
138
|
+
process(id: string, input: TInput): ProcessResult<TState, TInput> {
|
|
139
|
+
return this.processInternal(id, input, 0);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Internal process with depth tracking
|
|
144
|
+
*/
|
|
145
|
+
private processInternal(id: string, input: TInput, depth: number): ProcessResult<TState, TInput> {
|
|
146
|
+
// Guard against infinite recursion
|
|
147
|
+
if (depth >= this.maxDepth) {
|
|
148
|
+
logger.warn("Max recursion depth reached", {
|
|
149
|
+
id,
|
|
150
|
+
maxDepth: this.maxDepth,
|
|
151
|
+
depth,
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
state: this.store.get(id) ?? this.initialState,
|
|
155
|
+
outputs: [],
|
|
156
|
+
processCount: 0,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 1. Get current state (or initialize)
|
|
161
|
+
let state = this.store.get(id);
|
|
162
|
+
if (state === undefined) {
|
|
163
|
+
state = this.initialState;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 2. Execute pure processor function (Mealy transition)
|
|
167
|
+
const [newState, outputs] = this.processor(state, input);
|
|
168
|
+
|
|
169
|
+
// 3. Save new state to store
|
|
170
|
+
this.store.set(id, newState);
|
|
171
|
+
|
|
172
|
+
// 4. Collect all outputs
|
|
173
|
+
const allOutputs: TInput[] = [...outputs];
|
|
174
|
+
let processCount = 1;
|
|
175
|
+
|
|
176
|
+
// 5. Send outputs to sinks
|
|
177
|
+
if (outputs.length > 0) {
|
|
178
|
+
this.sendToSinks(id, outputs);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 6. Optionally recurse on outputs
|
|
182
|
+
if (this.recursive) {
|
|
183
|
+
for (const output of outputs) {
|
|
184
|
+
const result = this.processInternal(id, output, depth + 1);
|
|
185
|
+
allOutputs.push(...result.outputs);
|
|
186
|
+
processCount += result.processCount;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
state: newState,
|
|
192
|
+
outputs: allOutputs,
|
|
193
|
+
processCount,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Send outputs to all sinks
|
|
199
|
+
*/
|
|
200
|
+
private sendToSinks(id: string, outputs: TInput[]): void {
|
|
201
|
+
for (const sink of this.sinks) {
|
|
202
|
+
// Check if sink is a function or SinkDefinition
|
|
203
|
+
if (typeof sink === "function") {
|
|
204
|
+
// Simple Sink function: (id, outputs) => void
|
|
205
|
+
try {
|
|
206
|
+
const result = sink(id, outputs);
|
|
207
|
+
if (result instanceof Promise) {
|
|
208
|
+
result.catch((error) => {
|
|
209
|
+
logger.error("Sink error (async)", { id, error });
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
} catch (error) {
|
|
213
|
+
logger.error("Sink error (sync)", { id, error });
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
// SinkDefinition with filter/name
|
|
217
|
+
const filteredOutputs = sink.filter ? outputs.filter(sink.filter) : outputs;
|
|
218
|
+
|
|
219
|
+
if (filteredOutputs.length === 0) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
const result = sink.sink(id, filteredOutputs);
|
|
225
|
+
if (result instanceof Promise) {
|
|
226
|
+
result.catch((error) => {
|
|
227
|
+
logger.error("Named sink error (async)", {
|
|
228
|
+
id,
|
|
229
|
+
sinkName: sink.name,
|
|
230
|
+
error,
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
logger.error("Named sink error (sync)", {
|
|
236
|
+
id,
|
|
237
|
+
sinkName: sink.name,
|
|
238
|
+
error,
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get current state for an ID (without processing)
|
|
247
|
+
*/
|
|
248
|
+
getState(id: string): TState | undefined {
|
|
249
|
+
return this.store.get(id);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Check if state exists for an ID
|
|
254
|
+
*/
|
|
255
|
+
hasState(id: string): boolean {
|
|
256
|
+
return this.store.has(id);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Delete state for an ID (cleanup)
|
|
261
|
+
*/
|
|
262
|
+
cleanup(id: string): void {
|
|
263
|
+
logger.debug("Cleaning up state", { id });
|
|
264
|
+
this.store.delete(id);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Add a sink at runtime
|
|
269
|
+
*/
|
|
270
|
+
addSink(sink: Sink<TInput> | SinkDefinition<TInput>): void {
|
|
271
|
+
const sinkName = typeof sink === "function" ? "(anonymous)" : sink.name;
|
|
272
|
+
logger.debug("Adding sink", { sinkName });
|
|
273
|
+
this.sinks.push(sink);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Remove a sink by name (only works for SinkDefinitions)
|
|
278
|
+
*/
|
|
279
|
+
removeSink(name: string): boolean {
|
|
280
|
+
const index = this.sinks.findIndex((s) => typeof s !== "function" && s.name === name);
|
|
281
|
+
if (index !== -1) {
|
|
282
|
+
this.sinks.splice(index, 1);
|
|
283
|
+
logger.debug("Removed sink", { name });
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
logger.debug("Sink not found for removal", { name });
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* createMealy - Factory function for creating Mealy Machine instances
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const mealy = createMealy({
|
|
297
|
+
* processor: myProcessor,
|
|
298
|
+
* store: new MemoryStore(),
|
|
299
|
+
* initialState: { count: 0 },
|
|
300
|
+
* sinks: [logSink],
|
|
301
|
+
* });
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
export function createMealy<TState, TInput>(
|
|
305
|
+
config: MealyConfig<TState, TInput>
|
|
306
|
+
): Mealy<TState, TInput> {
|
|
307
|
+
return new Mealy(config);
|
|
308
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Processor - Core pure function type for stream processing
|
|
3
|
+
*
|
|
4
|
+
* A Processor is a pure function that takes a state and an input,
|
|
5
|
+
* and returns a new state along with outputs.
|
|
6
|
+
*
|
|
7
|
+
* Pattern: (state, input) => [newState, outputs]
|
|
8
|
+
*
|
|
9
|
+
* Key properties:
|
|
10
|
+
* - Pure function (no side effects)
|
|
11
|
+
* - Deterministic (same input → same output)
|
|
12
|
+
* - State is a means (accumulator), outputs are the goal
|
|
13
|
+
*
|
|
14
|
+
* @template TState - The state type (internal accumulator)
|
|
15
|
+
* @template TInput - The input type
|
|
16
|
+
* @template TOutput - The output type (emissions)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const messageProcessor: Processor<MsgState, StreamEvent, MsgEvent> =
|
|
21
|
+
* (state, input) => {
|
|
22
|
+
* switch (input.type) {
|
|
23
|
+
* case 'text_delta':
|
|
24
|
+
* return [{ ...state, buffer: state.buffer + input.data.text }, []];
|
|
25
|
+
* case 'message_stop':
|
|
26
|
+
* return [{ buffer: '' }, [{ type: 'assistant_message', content: state.buffer }]];
|
|
27
|
+
* default:
|
|
28
|
+
* return [state, []];
|
|
29
|
+
* }
|
|
30
|
+
* };
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export type Processor<TState, TInput, TOutput> = (
|
|
34
|
+
state: Readonly<TState>,
|
|
35
|
+
input: TInput
|
|
36
|
+
) => [TState, TOutput[]];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* ProcessorResult - The return type of a Processor
|
|
40
|
+
*
|
|
41
|
+
* A tuple containing:
|
|
42
|
+
* - [0] newState: The updated state after processing
|
|
43
|
+
* - [1] outputs: Array of outputs to emit
|
|
44
|
+
*/
|
|
45
|
+
export type ProcessorResult<TState, TOutput> = [TState, TOutput[]];
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ProcessorDefinition - Metadata for a Processor
|
|
49
|
+
*/
|
|
50
|
+
export interface ProcessorDefinition<TState, TInput, TOutput> {
|
|
51
|
+
/**
|
|
52
|
+
* Unique name for this processor
|
|
53
|
+
*/
|
|
54
|
+
name: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The pure processor function
|
|
58
|
+
*/
|
|
59
|
+
processor: Processor<TState, TInput, TOutput>;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Initial state factory
|
|
63
|
+
*/
|
|
64
|
+
initialState: () => TState;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Optional description
|
|
68
|
+
*/
|
|
69
|
+
description?: string;
|
|
70
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sink - Output adapter for Mealy Machine
|
|
3
|
+
*
|
|
4
|
+
* A Sink receives outputs from Processors and produces external effects.
|
|
5
|
+
* This is a pure function type - lifecycle management belongs to higher layers.
|
|
6
|
+
*
|
|
7
|
+
* Pattern: (id, outputs) => void | Promise<void>
|
|
8
|
+
*
|
|
9
|
+
* @template TOutput - The output type received from Processors
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Sync sink (logging)
|
|
14
|
+
* const logSink: Sink<AgentEvent> = (id, outputs) => {
|
|
15
|
+
* outputs.forEach(output => console.log(`[${id}]`, output));
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* // Async sink (network)
|
|
19
|
+
* const sseSink: Sink<AgentEvent> = async (id, outputs) => {
|
|
20
|
+
* for (const output of outputs) {
|
|
21
|
+
* await sseConnection.send(id, output);
|
|
22
|
+
* }
|
|
23
|
+
* };
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export type Sink<TOutput> = (id: string, outputs: TOutput[]) => void | Promise<void>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* SinkDefinition - Named Sink with metadata
|
|
30
|
+
*
|
|
31
|
+
* Use this when you need to identify sinks by name.
|
|
32
|
+
*/
|
|
33
|
+
export interface SinkDefinition<TOutput> {
|
|
34
|
+
/**
|
|
35
|
+
* Unique name for this sink
|
|
36
|
+
*/
|
|
37
|
+
name: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Optional description
|
|
41
|
+
*/
|
|
42
|
+
description?: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Optional filter to select which outputs to process
|
|
46
|
+
*
|
|
47
|
+
* If not provided, all outputs are processed.
|
|
48
|
+
* Return true to process the output, false to skip.
|
|
49
|
+
*/
|
|
50
|
+
filter?: (output: TOutput) => boolean;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The sink function
|
|
54
|
+
*/
|
|
55
|
+
sink: Sink<TOutput>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Source - Input adapter for Mealy Machine
|
|
3
|
+
*
|
|
4
|
+
* A Source transforms external requests into internal events.
|
|
5
|
+
* This is a pure function type - lifecycle management belongs to higher layers.
|
|
6
|
+
*
|
|
7
|
+
* Pattern: (request) => AsyncIterable<input>
|
|
8
|
+
*
|
|
9
|
+
* @template TInput - The event type produced for Processors
|
|
10
|
+
* @template TRequest - The request type received from external (default: void)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* // Simple source (no request)
|
|
15
|
+
* const timerSource: Source<TimerEvent> = async function* () {
|
|
16
|
+
* while (true) {
|
|
17
|
+
* yield { type: 'tick', timestamp: Date.now() };
|
|
18
|
+
* await sleep(1000);
|
|
19
|
+
* }
|
|
20
|
+
* };
|
|
21
|
+
*
|
|
22
|
+
* // Source with request
|
|
23
|
+
* const apiSource: Source<ApiEvent, ApiRequest> = async function* (request) {
|
|
24
|
+
* const response = await fetch(request.url);
|
|
25
|
+
* yield { type: 'response', data: await response.json() };
|
|
26
|
+
* };
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export type Source<TInput, TRequest = void> = (request: TRequest) => AsyncIterable<TInput>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* SourceDefinition - Named Source with metadata
|
|
33
|
+
*
|
|
34
|
+
* Use this when you need to identify sources by name.
|
|
35
|
+
*/
|
|
36
|
+
export interface SourceDefinition<TInput, TRequest = void> {
|
|
37
|
+
/**
|
|
38
|
+
* Unique name for this source
|
|
39
|
+
*/
|
|
40
|
+
name: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Optional description
|
|
44
|
+
*/
|
|
45
|
+
description?: string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The source function
|
|
49
|
+
*/
|
|
50
|
+
source: Source<TInput, TRequest>;
|
|
51
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store - State storage interface for stream processing
|
|
3
|
+
*
|
|
4
|
+
* A Store abstracts state persistence, allowing processors to be stateless
|
|
5
|
+
* while maintaining state externally.
|
|
6
|
+
*
|
|
7
|
+
* @template T - The state type to store
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const store = new MemoryStore<AgentState>();
|
|
12
|
+
* store.set('agent_123', { count: 0 });
|
|
13
|
+
* const state = store.get('agent_123');
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export interface Store<T> {
|
|
17
|
+
/**
|
|
18
|
+
* Get state by ID
|
|
19
|
+
* @param id - Unique identifier (e.g., agentId, sessionId)
|
|
20
|
+
* @returns The stored state or undefined if not found
|
|
21
|
+
*/
|
|
22
|
+
get(id: string): T | undefined;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Set state for an ID
|
|
26
|
+
* @param id - Unique identifier
|
|
27
|
+
* @param state - The state to store
|
|
28
|
+
*/
|
|
29
|
+
set(id: string, state: T): void;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Delete state for an ID
|
|
33
|
+
* @param id - Unique identifier
|
|
34
|
+
*/
|
|
35
|
+
delete(id: string): void;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Check if state exists for an ID
|
|
39
|
+
* @param id - Unique identifier
|
|
40
|
+
* @returns True if state exists
|
|
41
|
+
*/
|
|
42
|
+
has(id: string): boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* MemoryStore - In-memory implementation of Store
|
|
47
|
+
*
|
|
48
|
+
* Stores state in a Map. Suitable for development and single-process deployments.
|
|
49
|
+
* For production multi-process scenarios, use RedisStore or PostgresStore.
|
|
50
|
+
*
|
|
51
|
+
* @template T - The state type to store
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const store = new MemoryStore<MyState>();
|
|
56
|
+
* store.set('session_1', { count: 0 });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export class MemoryStore<T> implements Store<T> {
|
|
60
|
+
private states = new Map<string, T>();
|
|
61
|
+
|
|
62
|
+
get(id: string): T | undefined {
|
|
63
|
+
return this.states.get(id);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
set(id: string, state: T): void {
|
|
67
|
+
this.states.set(id, state);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
delete(id: string): void {
|
|
71
|
+
this.states.delete(id);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
has(id: string): boolean {
|
|
75
|
+
return this.states.has(id);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Clear all stored states
|
|
80
|
+
*/
|
|
81
|
+
clear(): void {
|
|
82
|
+
this.states.clear();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get the number of stored states
|
|
87
|
+
*/
|
|
88
|
+
get size(): number {
|
|
89
|
+
return this.states.size;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get all stored IDs
|
|
94
|
+
*/
|
|
95
|
+
keys(): IterableIterator<string> {
|
|
96
|
+
return this.states.keys();
|
|
97
|
+
}
|
|
98
|
+
}
|