@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,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createAgent - Factory function to create an AgentEngine
|
|
3
|
+
*
|
|
4
|
+
* Creates an AgentEngine connected to EventBus:
|
|
5
|
+
* - receive() emits user_message to EventBus
|
|
6
|
+
* - Source subscribes to StreamEvent from EventBus
|
|
7
|
+
* - Presenter emits AgentOutput to EventBus
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* EventBus
|
|
11
|
+
* ↗ ↘
|
|
12
|
+
* emit │ │ emit
|
|
13
|
+
* user_message │ │ AgentOutput
|
|
14
|
+
* ↑ │ │ ↑
|
|
15
|
+
* ┌─────────────────────────────────────────────────────────────┐
|
|
16
|
+
* │ AgentEngine │
|
|
17
|
+
* │ │
|
|
18
|
+
* │ receive() ──► Source ──► MealyMachine ──► Presenter │
|
|
19
|
+
* │ (sub) (pub) │
|
|
20
|
+
* └─────────────────────────────────────────────────────────────┘
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import type {
|
|
25
|
+
AgentEngine,
|
|
26
|
+
AgentState,
|
|
27
|
+
AgentOutputCallback,
|
|
28
|
+
UserMessage,
|
|
29
|
+
MessageQueue,
|
|
30
|
+
StateChangeHandler,
|
|
31
|
+
EventHandlerMap,
|
|
32
|
+
ReactHandlerMap,
|
|
33
|
+
AgentOutput,
|
|
34
|
+
CreateAgentOptions,
|
|
35
|
+
AgentSource,
|
|
36
|
+
AgentPresenter,
|
|
37
|
+
AgentEventBus,
|
|
38
|
+
StreamEvent,
|
|
39
|
+
Unsubscribe,
|
|
40
|
+
AgentMiddleware,
|
|
41
|
+
AgentInterceptor,
|
|
42
|
+
} from "./types";
|
|
43
|
+
import { MealyMachine } from "./engine/MealyMachine";
|
|
44
|
+
import { AgentStateMachine } from "./AgentStateMachine";
|
|
45
|
+
import { createLogger } from "commonxjs/logger";
|
|
46
|
+
import { isDriveableEvent } from "../event";
|
|
47
|
+
|
|
48
|
+
const logger = createLogger("agent/AgentEngine");
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Generate unique agent ID
|
|
52
|
+
*/
|
|
53
|
+
function generateAgentId(): string {
|
|
54
|
+
return `agent_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* StreamEvent types that Source should subscribe to
|
|
59
|
+
*/
|
|
60
|
+
const STREAM_EVENT_TYPES = [
|
|
61
|
+
"message_start",
|
|
62
|
+
"message_delta",
|
|
63
|
+
"message_stop",
|
|
64
|
+
"text_delta",
|
|
65
|
+
"tool_use_start",
|
|
66
|
+
"input_json_delta",
|
|
67
|
+
"tool_use_stop",
|
|
68
|
+
"tool_result",
|
|
69
|
+
"error_received",
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Default Source implementation
|
|
74
|
+
* Subscribes to StreamEvent from EventBus
|
|
75
|
+
*/
|
|
76
|
+
class DefaultSource implements AgentSource {
|
|
77
|
+
readonly name = "DefaultSource";
|
|
78
|
+
private unsubscribes: Unsubscribe[] = [];
|
|
79
|
+
|
|
80
|
+
constructor(
|
|
81
|
+
private readonly bus: AgentEventBus,
|
|
82
|
+
private readonly agentId: string
|
|
83
|
+
) {}
|
|
84
|
+
|
|
85
|
+
connect(onEvent: (event: StreamEvent) => void): void {
|
|
86
|
+
// Subscribe to each StreamEvent type
|
|
87
|
+
for (const type of STREAM_EVENT_TYPES) {
|
|
88
|
+
const unsub = this.bus.on(type, (event: unknown) => {
|
|
89
|
+
// Only process DriveableEvents (source: "driver", category: "stream")
|
|
90
|
+
// This prevents circular processing of AgentOutput events
|
|
91
|
+
if (!isDriveableEvent(event as { source?: string; category?: string })) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Filter by agentId if present in context
|
|
96
|
+
const e = event as { context?: { agentId?: string } };
|
|
97
|
+
if (e.context?.agentId && e.context.agentId !== this.agentId) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
onEvent(event as StreamEvent);
|
|
101
|
+
});
|
|
102
|
+
this.unsubscribes.push(unsub);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
logger.debug("DefaultSource connected", { agentId: this.agentId });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
disconnect(): void {
|
|
109
|
+
for (const unsub of this.unsubscribes) {
|
|
110
|
+
unsub();
|
|
111
|
+
}
|
|
112
|
+
this.unsubscribes = [];
|
|
113
|
+
logger.debug("DefaultSource disconnected", { agentId: this.agentId });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Default Presenter implementation
|
|
119
|
+
* Emits AgentOutput to EventBus
|
|
120
|
+
*/
|
|
121
|
+
class DefaultPresenter implements AgentPresenter {
|
|
122
|
+
readonly name = "DefaultPresenter";
|
|
123
|
+
|
|
124
|
+
constructor(private readonly bus: AgentEventBus) {}
|
|
125
|
+
|
|
126
|
+
present(agentId: string, output: AgentOutput): void {
|
|
127
|
+
// Emit to EventBus with agent context
|
|
128
|
+
this.bus.emit({
|
|
129
|
+
...output,
|
|
130
|
+
source: "agent",
|
|
131
|
+
context: { agentId },
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Simple MessageQueue implementation
|
|
138
|
+
*/
|
|
139
|
+
class SimpleMessageQueue implements MessageQueue {
|
|
140
|
+
private queue: UserMessage[] = [];
|
|
141
|
+
|
|
142
|
+
get length(): number {
|
|
143
|
+
return this.queue.length;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get isEmpty(): boolean {
|
|
147
|
+
return this.queue.length === 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
enqueue(message: UserMessage): void {
|
|
151
|
+
this.queue.push(message);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
dequeue(): UserMessage | undefined {
|
|
155
|
+
return this.queue.shift();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
clear(): void {
|
|
159
|
+
this.queue = [];
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* AgentEngineImpl - EventBus-based AgentEngine implementation
|
|
165
|
+
*/
|
|
166
|
+
class AgentEngineImpl implements AgentEngine {
|
|
167
|
+
readonly agentId: string;
|
|
168
|
+
readonly createdAt: number;
|
|
169
|
+
readonly messageQueue: MessageQueue;
|
|
170
|
+
|
|
171
|
+
private readonly _messageQueue = new SimpleMessageQueue();
|
|
172
|
+
private readonly bus: AgentEventBus;
|
|
173
|
+
private readonly source: AgentSource;
|
|
174
|
+
private readonly presenter: AgentPresenter;
|
|
175
|
+
private readonly machine: MealyMachine;
|
|
176
|
+
private readonly stateMachine: AgentStateMachine;
|
|
177
|
+
|
|
178
|
+
private readonly handlers: Set<AgentOutputCallback> = new Set();
|
|
179
|
+
private readonly typeHandlers: Map<string, Set<AgentOutputCallback>> = new Map();
|
|
180
|
+
private readonly readyHandlers: Set<() => void> = new Set();
|
|
181
|
+
private readonly destroyHandlers: Set<() => void> = new Set();
|
|
182
|
+
private readonly middlewares: AgentMiddleware[] = [];
|
|
183
|
+
private readonly interceptors: AgentInterceptor[] = [];
|
|
184
|
+
|
|
185
|
+
private isDestroyed = false;
|
|
186
|
+
|
|
187
|
+
constructor(options: CreateAgentOptions) {
|
|
188
|
+
this.agentId = options.agentId ?? generateAgentId();
|
|
189
|
+
this.createdAt = Date.now();
|
|
190
|
+
this.messageQueue = this._messageQueue;
|
|
191
|
+
this.bus = options.bus;
|
|
192
|
+
this.machine = new MealyMachine();
|
|
193
|
+
this.stateMachine = new AgentStateMachine();
|
|
194
|
+
|
|
195
|
+
// Use provided Source/Presenter or create defaults
|
|
196
|
+
this.source = options.source ?? new DefaultSource(this.bus, this.agentId);
|
|
197
|
+
this.presenter = options.presenter ?? new DefaultPresenter(this.bus);
|
|
198
|
+
|
|
199
|
+
// Connect Source to receive StreamEvents
|
|
200
|
+
this.source.connect((event) => this.handleStreamEvent(event));
|
|
201
|
+
|
|
202
|
+
logger.debug("AgentEngine created", { agentId: this.agentId });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
get state(): AgentState {
|
|
206
|
+
return this.stateMachine.state;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async receive(message: string | UserMessage): Promise<void> {
|
|
210
|
+
if (this.isDestroyed) {
|
|
211
|
+
throw new Error("Cannot receive message on destroyed agent");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const userMessage: UserMessage =
|
|
215
|
+
typeof message === "string"
|
|
216
|
+
? {
|
|
217
|
+
id: `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
218
|
+
role: "user",
|
|
219
|
+
subtype: "user",
|
|
220
|
+
content: message,
|
|
221
|
+
timestamp: Date.now(),
|
|
222
|
+
}
|
|
223
|
+
: message;
|
|
224
|
+
|
|
225
|
+
logger.debug("Receiving message", { messageId: userMessage.id });
|
|
226
|
+
|
|
227
|
+
// Run through middleware chain
|
|
228
|
+
let processedMessage = userMessage;
|
|
229
|
+
for (const middleware of this.middlewares) {
|
|
230
|
+
let nextCalled = false;
|
|
231
|
+
await middleware(processedMessage, async (msg) => {
|
|
232
|
+
nextCalled = true;
|
|
233
|
+
processedMessage = msg;
|
|
234
|
+
});
|
|
235
|
+
if (!nextCalled) {
|
|
236
|
+
logger.debug("Middleware blocked message", { messageId: userMessage.id });
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Emit user_message to EventBus
|
|
242
|
+
// This triggers Driver to send to LLM
|
|
243
|
+
this.bus.emit({
|
|
244
|
+
type: "user_message",
|
|
245
|
+
timestamp: Date.now(),
|
|
246
|
+
source: "agent",
|
|
247
|
+
data: processedMessage,
|
|
248
|
+
context: { agentId: this.agentId },
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
logger.debug("user_message emitted to EventBus", { messageId: userMessage.id });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Handle a stream event (called by Source)
|
|
256
|
+
*/
|
|
257
|
+
handleStreamEvent(event: StreamEvent): void {
|
|
258
|
+
if (this.isDestroyed) return;
|
|
259
|
+
|
|
260
|
+
logger.debug("handleStreamEvent", { type: event.type });
|
|
261
|
+
|
|
262
|
+
// Process through MealyMachine
|
|
263
|
+
const outputs = this.machine.process(this.agentId, event);
|
|
264
|
+
|
|
265
|
+
logger.debug("MealyMachine outputs", {
|
|
266
|
+
count: outputs.length,
|
|
267
|
+
types: outputs.map((o) => o.type),
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Emit all outputs
|
|
271
|
+
for (const output of outputs) {
|
|
272
|
+
this.stateMachine.process(output);
|
|
273
|
+
this.emitOutput(output);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private emitOutput(output: AgentOutput): void {
|
|
278
|
+
// Run through interceptor chain
|
|
279
|
+
let currentOutput: AgentOutput | null = output;
|
|
280
|
+
|
|
281
|
+
const runInterceptor = (index: number, out: AgentOutput): void => {
|
|
282
|
+
if (index >= this.interceptors.length) {
|
|
283
|
+
currentOutput = out;
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
this.interceptors[index](out, (nextOut) => {
|
|
287
|
+
runInterceptor(index + 1, nextOut);
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
runInterceptor(0, output);
|
|
292
|
+
if (!currentOutput) return;
|
|
293
|
+
|
|
294
|
+
// Send to presenter (emits to EventBus)
|
|
295
|
+
this.presenter.present(this.agentId, currentOutput);
|
|
296
|
+
|
|
297
|
+
// Notify local handlers
|
|
298
|
+
for (const handler of this.handlers) {
|
|
299
|
+
try {
|
|
300
|
+
handler(currentOutput);
|
|
301
|
+
} catch (e) {
|
|
302
|
+
logger.error("Event handler error", { error: e });
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Notify type-specific handlers
|
|
307
|
+
const typeSet = this.typeHandlers.get(currentOutput.type);
|
|
308
|
+
if (typeSet) {
|
|
309
|
+
for (const handler of typeSet) {
|
|
310
|
+
try {
|
|
311
|
+
handler(currentOutput);
|
|
312
|
+
} catch (e) {
|
|
313
|
+
logger.error("Event handler error", { error: e });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
on(handler: AgentOutputCallback): Unsubscribe;
|
|
320
|
+
on(handlers: EventHandlerMap): Unsubscribe;
|
|
321
|
+
on(type: string, handler: AgentOutputCallback): Unsubscribe;
|
|
322
|
+
on(types: string[], handler: AgentOutputCallback): Unsubscribe;
|
|
323
|
+
on(
|
|
324
|
+
typeOrHandler: string | string[] | AgentOutputCallback | EventHandlerMap,
|
|
325
|
+
handler?: AgentOutputCallback
|
|
326
|
+
): Unsubscribe {
|
|
327
|
+
if (typeof typeOrHandler === "function") {
|
|
328
|
+
this.handlers.add(typeOrHandler);
|
|
329
|
+
return () => this.handlers.delete(typeOrHandler);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (typeof typeOrHandler === "object" && !Array.isArray(typeOrHandler)) {
|
|
333
|
+
const unsubscribes: Unsubscribe[] = [];
|
|
334
|
+
for (const [type, h] of Object.entries(typeOrHandler)) {
|
|
335
|
+
if (h) {
|
|
336
|
+
unsubscribes.push(this.on(type, h));
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return () => unsubscribes.forEach((u) => u());
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const types = Array.isArray(typeOrHandler) ? typeOrHandler : [typeOrHandler];
|
|
343
|
+
const h = handler!;
|
|
344
|
+
|
|
345
|
+
for (const type of types) {
|
|
346
|
+
if (!this.typeHandlers.has(type)) {
|
|
347
|
+
this.typeHandlers.set(type, new Set());
|
|
348
|
+
}
|
|
349
|
+
this.typeHandlers.get(type)!.add(h);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return () => {
|
|
353
|
+
for (const type of types) {
|
|
354
|
+
this.typeHandlers.get(type)?.delete(h);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
onStateChange(handler: StateChangeHandler): Unsubscribe {
|
|
360
|
+
return this.stateMachine.onStateChange(handler);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
react(handlers: ReactHandlerMap): Unsubscribe {
|
|
364
|
+
const eventHandlerMap: EventHandlerMap = {};
|
|
365
|
+
for (const [key, handler] of Object.entries(handlers)) {
|
|
366
|
+
if (handler && key.startsWith("on")) {
|
|
367
|
+
const eventType = key
|
|
368
|
+
.slice(2)
|
|
369
|
+
.replace(/([A-Z])/g, "_$1")
|
|
370
|
+
.toLowerCase()
|
|
371
|
+
.slice(1);
|
|
372
|
+
eventHandlerMap[eventType] = handler;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return this.on(eventHandlerMap);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
onReady(handler: () => void): Unsubscribe {
|
|
379
|
+
try {
|
|
380
|
+
handler();
|
|
381
|
+
} catch (e) {
|
|
382
|
+
logger.error("onReady handler error", { error: e });
|
|
383
|
+
}
|
|
384
|
+
this.readyHandlers.add(handler);
|
|
385
|
+
return () => this.readyHandlers.delete(handler);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
onDestroy(handler: () => void): Unsubscribe {
|
|
389
|
+
this.destroyHandlers.add(handler);
|
|
390
|
+
return () => this.destroyHandlers.delete(handler);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
use(middleware: AgentMiddleware): Unsubscribe {
|
|
394
|
+
this.middlewares.push(middleware);
|
|
395
|
+
return () => {
|
|
396
|
+
const index = this.middlewares.indexOf(middleware);
|
|
397
|
+
if (index >= 0) {
|
|
398
|
+
this.middlewares.splice(index, 1);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
intercept(interceptor: AgentInterceptor): Unsubscribe {
|
|
404
|
+
this.interceptors.push(interceptor);
|
|
405
|
+
return () => {
|
|
406
|
+
const index = this.interceptors.indexOf(interceptor);
|
|
407
|
+
if (index >= 0) {
|
|
408
|
+
this.interceptors.splice(index, 1);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
interrupt(): void {
|
|
414
|
+
if (this.state === "idle" || this.isDestroyed) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Emit interrupt event to EventBus
|
|
419
|
+
this.bus.emit({
|
|
420
|
+
type: "interrupt_request",
|
|
421
|
+
timestamp: Date.now(),
|
|
422
|
+
source: "agent",
|
|
423
|
+
data: {},
|
|
424
|
+
context: { agentId: this.agentId },
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
logger.debug("Interrupt requested", { agentId: this.agentId });
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
async destroy(): Promise<void> {
|
|
431
|
+
if (this.isDestroyed) return;
|
|
432
|
+
this.isDestroyed = true;
|
|
433
|
+
|
|
434
|
+
// Disconnect Source
|
|
435
|
+
this.source.disconnect();
|
|
436
|
+
|
|
437
|
+
// Notify destroy handlers
|
|
438
|
+
for (const handler of this.destroyHandlers) {
|
|
439
|
+
try {
|
|
440
|
+
handler();
|
|
441
|
+
} catch (e) {
|
|
442
|
+
logger.error("onDestroy handler error", { error: e });
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Clear state
|
|
447
|
+
this.machine.clearState(this.agentId);
|
|
448
|
+
this.stateMachine.reset();
|
|
449
|
+
|
|
450
|
+
this._messageQueue.clear();
|
|
451
|
+
this.handlers.clear();
|
|
452
|
+
this.typeHandlers.clear();
|
|
453
|
+
this.readyHandlers.clear();
|
|
454
|
+
this.destroyHandlers.clear();
|
|
455
|
+
this.middlewares.length = 0;
|
|
456
|
+
this.interceptors.length = 0;
|
|
457
|
+
|
|
458
|
+
logger.debug("AgentEngine destroyed", { agentId: this.agentId });
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Create an AgentEngine instance connected to EventBus
|
|
464
|
+
*/
|
|
465
|
+
export function createAgent(options: CreateAgentOptions): AgentEngine {
|
|
466
|
+
return new AgentEngineImpl(options);
|
|
467
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentProcessor
|
|
3
|
+
*
|
|
4
|
+
* Combined Mealy processor for the full AgentX engine.
|
|
5
|
+
* Composes MessageAssembler, StateMachine, and TurnTracker processors.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { combineProcessors, combineInitialStates, type Processor } from "./mealy";
|
|
9
|
+
// Note: StreamEventType and MessageEventType are part of AgentOutput (from Presenter)
|
|
10
|
+
// They flow through the system but AgentProcessor doesn't need to import them directly
|
|
11
|
+
import {
|
|
12
|
+
messageAssemblerProcessor,
|
|
13
|
+
stateEventProcessor,
|
|
14
|
+
turnTrackerProcessor,
|
|
15
|
+
createInitialMessageAssemblerState,
|
|
16
|
+
createInitialStateEventProcessorContext,
|
|
17
|
+
createInitialTurnTrackerState,
|
|
18
|
+
type MessageAssemblerState,
|
|
19
|
+
type StateEventProcessorContext,
|
|
20
|
+
type TurnTrackerState,
|
|
21
|
+
type MessageAssemblerOutput,
|
|
22
|
+
type StateEventProcessorOutput,
|
|
23
|
+
type TurnTrackerOutput,
|
|
24
|
+
} from "./internal";
|
|
25
|
+
import type { AgentOutput } from "../types";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Combined state type for the full agent engine
|
|
29
|
+
*/
|
|
30
|
+
export type AgentEngineState = {
|
|
31
|
+
messageAssembler: MessageAssemblerState;
|
|
32
|
+
stateEventProcessor: StateEventProcessorContext;
|
|
33
|
+
turnTracker: TurnTrackerState;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Input event type for AgentProcessor
|
|
38
|
+
*
|
|
39
|
+
* Accepts:
|
|
40
|
+
* - StreamEventType: Raw stream events from Driver
|
|
41
|
+
* - MessageEventType: Re-injected message events (for TurnTracker)
|
|
42
|
+
*
|
|
43
|
+
* Note: AgentOutput is used because re-injected events can be any output type
|
|
44
|
+
*/
|
|
45
|
+
export type AgentProcessorInput = AgentOutput;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Output event type from AgentProcessor
|
|
49
|
+
*
|
|
50
|
+
* Produces:
|
|
51
|
+
* - MessageAssemblerOutput: Assembled message events
|
|
52
|
+
* - StateEventProcessorOutput: State transition events
|
|
53
|
+
* - TurnTrackerOutput: Turn analytics events
|
|
54
|
+
*
|
|
55
|
+
* Note: StreamEventType is NOT in output - it's passed through by AgentEngine
|
|
56
|
+
*/
|
|
57
|
+
export type AgentProcessorOutput =
|
|
58
|
+
| MessageAssemblerOutput
|
|
59
|
+
| StateEventProcessorOutput
|
|
60
|
+
| TurnTrackerOutput;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Combined processor for the full agent engine
|
|
64
|
+
*
|
|
65
|
+
* This combines:
|
|
66
|
+
* - MessageAssembler: Stream → Message events
|
|
67
|
+
* - StateEventProcessor: Stream → State events
|
|
68
|
+
* - TurnTracker: Message → Turn events
|
|
69
|
+
*
|
|
70
|
+
* Pattern: (state, input) => [newState, outputs]
|
|
71
|
+
* Key insight: State is means, outputs are the goal (Mealy Machine)
|
|
72
|
+
*
|
|
73
|
+
* Note: Raw StreamEvents are NOT output by this processor.
|
|
74
|
+
* The AgentEngine handles pass-through of original events.
|
|
75
|
+
*/
|
|
76
|
+
export const agentProcessor: Processor<
|
|
77
|
+
AgentEngineState,
|
|
78
|
+
AgentProcessorInput,
|
|
79
|
+
AgentProcessorOutput
|
|
80
|
+
> = combineProcessors<AgentEngineState, AgentProcessorInput, AgentProcessorOutput>({
|
|
81
|
+
messageAssembler: messageAssemblerProcessor as unknown as Processor<
|
|
82
|
+
AgentEngineState["messageAssembler"],
|
|
83
|
+
AgentProcessorInput,
|
|
84
|
+
AgentProcessorOutput
|
|
85
|
+
>,
|
|
86
|
+
stateEventProcessor: stateEventProcessor as unknown as Processor<
|
|
87
|
+
AgentEngineState["stateEventProcessor"],
|
|
88
|
+
AgentProcessorInput,
|
|
89
|
+
AgentProcessorOutput
|
|
90
|
+
>,
|
|
91
|
+
turnTracker: turnTrackerProcessor as unknown as Processor<
|
|
92
|
+
AgentEngineState["turnTracker"],
|
|
93
|
+
AgentProcessorInput,
|
|
94
|
+
AgentProcessorOutput
|
|
95
|
+
>,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Initial state factory for the full agent engine
|
|
100
|
+
*/
|
|
101
|
+
export const createInitialAgentEngineState: () => AgentEngineState =
|
|
102
|
+
combineInitialStates<AgentEngineState>({
|
|
103
|
+
messageAssembler: createInitialMessageAssemblerState,
|
|
104
|
+
stateEventProcessor: createInitialStateEventProcessorContext,
|
|
105
|
+
turnTracker: createInitialTurnTrackerState,
|
|
106
|
+
});
|