@agentxjs/agent 0.1.6

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/dist/index.js ADDED
@@ -0,0 +1,1075 @@
1
+ import { createLogger } from '@agentxjs/common';
2
+ import { isStateEvent } from '@agentxjs/types/agent';
3
+
4
+ // src/engine/mealy/Store.ts
5
+ var MemoryStore = class {
6
+ states = /* @__PURE__ */ new Map();
7
+ get(id) {
8
+ return this.states.get(id);
9
+ }
10
+ set(id, state) {
11
+ this.states.set(id, state);
12
+ }
13
+ delete(id) {
14
+ this.states.delete(id);
15
+ }
16
+ has(id) {
17
+ return this.states.has(id);
18
+ }
19
+ /**
20
+ * Clear all stored states
21
+ */
22
+ clear() {
23
+ this.states.clear();
24
+ }
25
+ /**
26
+ * Get the number of stored states
27
+ */
28
+ get size() {
29
+ return this.states.size;
30
+ }
31
+ /**
32
+ * Get all stored IDs
33
+ */
34
+ keys() {
35
+ return this.states.keys();
36
+ }
37
+ };
38
+ createLogger("engine/Mealy");
39
+
40
+ // src/engine/mealy/combinators.ts
41
+ function combineProcessors(processors) {
42
+ return (state, event) => {
43
+ const newState = {};
44
+ const allOutputs = [];
45
+ for (const key in processors) {
46
+ const processor = processors[key];
47
+ const subState = state[key];
48
+ const [newSubState, outputs] = processor(subState, event);
49
+ newState[key] = newSubState;
50
+ allOutputs.push(...outputs);
51
+ }
52
+ return [newState, allOutputs];
53
+ };
54
+ }
55
+ function combineInitialStates(initialStates) {
56
+ return () => {
57
+ const state = {};
58
+ for (const key in initialStates) {
59
+ state[key] = initialStates[key]();
60
+ }
61
+ return state;
62
+ };
63
+ }
64
+ function chainProcessors(...processors) {
65
+ return (state, event) => {
66
+ let currentState = state;
67
+ const finalOutputs = [];
68
+ for (const processor of processors) {
69
+ const [newState, outputs] = processor(currentState, event);
70
+ currentState = newState;
71
+ finalOutputs.push(...outputs);
72
+ }
73
+ return [currentState, finalOutputs];
74
+ };
75
+ }
76
+ function filterProcessor(predicate, processor) {
77
+ return (state, event) => {
78
+ if (predicate(event)) {
79
+ return processor(state, event);
80
+ }
81
+ return [state, []];
82
+ };
83
+ }
84
+ function mapOutput(processor, mapper) {
85
+ return (state, event) => {
86
+ const [newState, outputs] = processor(state, event);
87
+ return [newState, outputs.map(mapper)];
88
+ };
89
+ }
90
+ function withLogging(processor, name, logger6 = console) {
91
+ return (state, event) => {
92
+ logger6.debug(`[${name}] Input:`, { event, state });
93
+ const [newState, outputs] = processor(state, event);
94
+ logger6.debug(`[${name}] Output:`, { newState, outputs });
95
+ return [newState, outputs];
96
+ };
97
+ }
98
+ function identityProcessor() {
99
+ return (state, _event) => {
100
+ return [state, []];
101
+ };
102
+ }
103
+
104
+ // src/engine/internal/messageAssemblerProcessor.ts
105
+ function createInitialMessageAssemblerState() {
106
+ return {
107
+ currentMessageId: null,
108
+ messageStartTime: null,
109
+ pendingContents: {},
110
+ pendingToolCalls: {}
111
+ };
112
+ }
113
+ function generateId() {
114
+ return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
115
+ }
116
+ var messageAssemblerProcessor = (state, input) => {
117
+ switch (input.type) {
118
+ case "message_start":
119
+ return handleMessageStart(state, input);
120
+ case "text_delta":
121
+ return handleTextDelta(state, input);
122
+ case "tool_use_start":
123
+ return handleToolUseStart(state, input);
124
+ case "input_json_delta":
125
+ return handleInputJsonDelta(state, input);
126
+ case "tool_use_stop":
127
+ return handleToolUseStop(state);
128
+ case "tool_result":
129
+ return handleToolResult(state, input);
130
+ case "message_stop":
131
+ return handleMessageStop(state, input);
132
+ case "error_received":
133
+ return handleErrorReceived(state, input);
134
+ default:
135
+ return [state, []];
136
+ }
137
+ };
138
+ function handleMessageStart(state, event) {
139
+ const data = event.data;
140
+ return [
141
+ {
142
+ ...state,
143
+ currentMessageId: data.messageId,
144
+ messageStartTime: event.timestamp,
145
+ pendingContents: {}
146
+ },
147
+ []
148
+ ];
149
+ }
150
+ function handleTextDelta(state, event) {
151
+ const data = event.data;
152
+ const index = 0;
153
+ const existingContent = state.pendingContents[index];
154
+ const pendingContent = existingContent?.type === "text" ? {
155
+ ...existingContent,
156
+ textDeltas: [...existingContent.textDeltas || [], data.text]
157
+ } : {
158
+ type: "text",
159
+ index,
160
+ textDeltas: [data.text]
161
+ };
162
+ return [
163
+ {
164
+ ...state,
165
+ pendingContents: {
166
+ ...state.pendingContents,
167
+ [index]: pendingContent
168
+ }
169
+ },
170
+ []
171
+ ];
172
+ }
173
+ function handleToolUseStart(state, event) {
174
+ const data = event.data;
175
+ const index = 1;
176
+ const pendingContent = {
177
+ type: "tool_use",
178
+ index,
179
+ toolId: data.toolCallId,
180
+ toolName: data.toolName,
181
+ toolInputJson: ""
182
+ };
183
+ return [
184
+ {
185
+ ...state,
186
+ pendingContents: {
187
+ ...state.pendingContents,
188
+ [index]: pendingContent
189
+ }
190
+ },
191
+ []
192
+ ];
193
+ }
194
+ function handleInputJsonDelta(state, event) {
195
+ const data = event.data;
196
+ const index = 1;
197
+ const existingContent = state.pendingContents[index];
198
+ if (!existingContent || existingContent.type !== "tool_use") {
199
+ return [state, []];
200
+ }
201
+ const pendingContent = {
202
+ ...existingContent,
203
+ toolInputJson: (existingContent.toolInputJson || "") + data.partialJson
204
+ };
205
+ return [
206
+ {
207
+ ...state,
208
+ pendingContents: {
209
+ ...state.pendingContents,
210
+ [index]: pendingContent
211
+ }
212
+ },
213
+ []
214
+ ];
215
+ }
216
+ function handleToolUseStop(state, _event) {
217
+ const index = 1;
218
+ const pendingContent = state.pendingContents[index];
219
+ if (!pendingContent || pendingContent.type !== "tool_use") {
220
+ return [state, []];
221
+ }
222
+ const toolId = pendingContent.toolId || "";
223
+ const toolName = pendingContent.toolName || "";
224
+ let toolInput = {};
225
+ try {
226
+ toolInput = pendingContent.toolInputJson ? JSON.parse(pendingContent.toolInputJson) : {};
227
+ } catch {
228
+ toolInput = {};
229
+ }
230
+ const toolCall = {
231
+ type: "tool-call",
232
+ id: toolId,
233
+ name: toolName,
234
+ input: toolInput
235
+ };
236
+ const messageId = generateId();
237
+ const timestamp = Date.now();
238
+ const toolCallMessage = {
239
+ id: messageId,
240
+ role: "assistant",
241
+ subtype: "tool-call",
242
+ toolCall,
243
+ timestamp,
244
+ parentId: state.currentMessageId || void 0
245
+ };
246
+ const toolCallMessageEvent = {
247
+ type: "tool_call_message",
248
+ timestamp,
249
+ data: toolCallMessage
250
+ };
251
+ const { [index]: _, ...remainingContents } = state.pendingContents;
252
+ return [
253
+ {
254
+ ...state,
255
+ pendingContents: remainingContents,
256
+ pendingToolCalls: {
257
+ ...state.pendingToolCalls,
258
+ [toolId]: { id: toolId, name: toolName }
259
+ }
260
+ },
261
+ [toolCallMessageEvent]
262
+ ];
263
+ }
264
+ function handleToolResult(state, event) {
265
+ const data = event.data;
266
+ const { toolCallId, result, isError } = data;
267
+ const pendingToolCall = state.pendingToolCalls[toolCallId];
268
+ const toolName = pendingToolCall?.name || "unknown";
269
+ const toolResult = {
270
+ type: "tool-result",
271
+ id: toolCallId,
272
+ name: toolName,
273
+ output: {
274
+ type: isError ? "error-text" : "text",
275
+ value: typeof result === "string" ? result : JSON.stringify(result)
276
+ }
277
+ };
278
+ const messageId = generateId();
279
+ const timestamp = Date.now();
280
+ const toolResultMessage = {
281
+ id: messageId,
282
+ role: "tool",
283
+ subtype: "tool-result",
284
+ toolCallId,
285
+ toolResult,
286
+ timestamp
287
+ };
288
+ const toolResultMessageEvent = {
289
+ type: "tool_result_message",
290
+ timestamp,
291
+ data: toolResultMessage
292
+ };
293
+ const { [toolCallId]: _, ...remainingToolCalls } = state.pendingToolCalls;
294
+ return [
295
+ {
296
+ ...state,
297
+ pendingToolCalls: remainingToolCalls
298
+ },
299
+ [toolResultMessageEvent]
300
+ ];
301
+ }
302
+ function handleMessageStop(state, event) {
303
+ const data = event.data;
304
+ if (!state.currentMessageId) {
305
+ return [state, []];
306
+ }
307
+ const textParts = [];
308
+ const sortedContents = Object.values(state.pendingContents).sort((a, b) => a.index - b.index);
309
+ for (const pending of sortedContents) {
310
+ if (pending.type === "text" && pending.textDeltas) {
311
+ textParts.push(pending.textDeltas.join(""));
312
+ }
313
+ }
314
+ const textContent = textParts.join("");
315
+ const stopReason = data.stopReason;
316
+ if (!textContent || textContent.trim().length === 0) {
317
+ const shouldPreserveToolCalls2 = stopReason === "tool_use";
318
+ return [
319
+ {
320
+ ...createInitialMessageAssemblerState(),
321
+ pendingToolCalls: shouldPreserveToolCalls2 ? state.pendingToolCalls : {}
322
+ },
323
+ []
324
+ ];
325
+ }
326
+ const contentParts = [
327
+ {
328
+ type: "text",
329
+ text: textContent
330
+ }
331
+ ];
332
+ const timestamp = state.messageStartTime || Date.now();
333
+ const assistantMessage = {
334
+ id: state.currentMessageId,
335
+ role: "assistant",
336
+ subtype: "assistant",
337
+ content: contentParts,
338
+ timestamp
339
+ };
340
+ const assistantEvent = {
341
+ type: "assistant_message",
342
+ timestamp,
343
+ data: assistantMessage
344
+ };
345
+ const shouldPreserveToolCalls = stopReason === "tool_use";
346
+ return [
347
+ {
348
+ ...createInitialMessageAssemblerState(),
349
+ pendingToolCalls: shouldPreserveToolCalls ? state.pendingToolCalls : {}
350
+ },
351
+ [assistantEvent]
352
+ ];
353
+ }
354
+ function handleErrorReceived(_state, event) {
355
+ const data = event.data;
356
+ const messageId = generateId();
357
+ const timestamp = Date.now();
358
+ const errorMessage = {
359
+ id: messageId,
360
+ role: "error",
361
+ subtype: "error",
362
+ content: data.message,
363
+ errorCode: data.errorCode,
364
+ timestamp
365
+ };
366
+ const errorMessageEvent = {
367
+ type: "error_message",
368
+ timestamp,
369
+ data: errorMessage
370
+ };
371
+ return [createInitialMessageAssemblerState(), [errorMessageEvent]];
372
+ }
373
+ var messageAssemblerProcessorDef = {
374
+ name: "MessageAssembler",
375
+ description: "Assembles complete messages from stream events",
376
+ initialState: createInitialMessageAssemblerState,
377
+ processor: messageAssemblerProcessor
378
+ };
379
+ var logger2 = createLogger("engine/stateEventProcessor");
380
+ function createInitialStateEventProcessorContext() {
381
+ return {};
382
+ }
383
+ var stateEventProcessor = (context, input) => {
384
+ logger2.debug(`[Stream Event] ${input.type}`, {
385
+ context,
386
+ eventData: "data" in input ? input.data : void 0
387
+ });
388
+ switch (input.type) {
389
+ case "message_start":
390
+ return handleMessageStart2(context, input);
391
+ case "message_delta":
392
+ return handleMessageDelta(context);
393
+ case "message_stop":
394
+ return handleMessageStop2(context, input);
395
+ case "text_delta":
396
+ return handleTextDelta2(context);
397
+ case "tool_use_start":
398
+ return handleToolUseStart2(context, input);
399
+ case "tool_use_stop":
400
+ return handleToolUseStop2(context);
401
+ case "error_received":
402
+ return handleErrorReceived2(context, input);
403
+ default:
404
+ logger2.debug(`[Stream Event] ${input.type} (unhandled)`);
405
+ return [context, []];
406
+ }
407
+ };
408
+ function handleMessageStart2(context, event) {
409
+ const data = event.data;
410
+ const conversationStartEvent = {
411
+ type: "conversation_start",
412
+ timestamp: Date.now(),
413
+ data: {
414
+ messageId: data.messageId
415
+ }
416
+ };
417
+ return [context, [conversationStartEvent]];
418
+ }
419
+ function handleMessageDelta(context) {
420
+ return [context, []];
421
+ }
422
+ function handleMessageStop2(context, event) {
423
+ const data = event.data;
424
+ const stopReason = data.stopReason;
425
+ logger2.debug("message_stop received", { stopReason });
426
+ if (stopReason === "tool_use") {
427
+ logger2.debug("Skipping conversation_end (tool_use in progress)");
428
+ return [context, []];
429
+ }
430
+ const conversationEndEvent = {
431
+ type: "conversation_end",
432
+ timestamp: Date.now(),
433
+ data: {
434
+ reason: "completed"
435
+ }
436
+ };
437
+ return [context, [conversationEndEvent]];
438
+ }
439
+ function handleTextDelta2(context) {
440
+ const respondingEvent = {
441
+ type: "conversation_responding",
442
+ timestamp: Date.now(),
443
+ data: {}
444
+ };
445
+ return [context, [respondingEvent]];
446
+ }
447
+ function handleToolUseStart2(context, event) {
448
+ const data = event.data;
449
+ const outputs = [];
450
+ const toolPlannedEvent = {
451
+ type: "tool_planned",
452
+ timestamp: Date.now(),
453
+ data: {
454
+ toolId: data.toolCallId,
455
+ toolName: data.toolName
456
+ }
457
+ };
458
+ outputs.push(toolPlannedEvent);
459
+ const toolExecutingEvent = {
460
+ type: "tool_executing",
461
+ timestamp: Date.now(),
462
+ data: {
463
+ toolId: data.toolCallId,
464
+ toolName: data.toolName,
465
+ input: {}
466
+ }
467
+ };
468
+ outputs.push(toolExecutingEvent);
469
+ return [context, outputs];
470
+ }
471
+ function handleToolUseStop2(context) {
472
+ return [context, []];
473
+ }
474
+ function handleErrorReceived2(context, event) {
475
+ const data = event.data;
476
+ const errorOccurredEvent = {
477
+ type: "error_occurred",
478
+ timestamp: Date.now(),
479
+ data: {
480
+ code: data.errorCode || "unknown_error",
481
+ message: data.message,
482
+ recoverable: true
483
+ }
484
+ };
485
+ return [context, [errorOccurredEvent]];
486
+ }
487
+ var stateEventProcessorDef = {
488
+ name: "StateEventProcessor",
489
+ description: "Transform Stream Events into State Events",
490
+ initialState: createInitialStateEventProcessorContext,
491
+ processor: stateEventProcessor
492
+ };
493
+
494
+ // src/engine/internal/turnTrackerProcessor.ts
495
+ function createInitialTurnTrackerState() {
496
+ return {
497
+ pendingTurn: null,
498
+ costPerInputToken: 3e-6,
499
+ // $3 per 1M tokens
500
+ costPerOutputToken: 15e-6
501
+ // $15 per 1M tokens
502
+ };
503
+ }
504
+ function generateId2() {
505
+ return `turn_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
506
+ }
507
+ var turnTrackerProcessor = (state, input) => {
508
+ switch (input.type) {
509
+ case "user_message":
510
+ return handleUserMessage(state, input);
511
+ case "message_stop":
512
+ return handleMessageStop3(state, input);
513
+ case "assistant_message":
514
+ return [state, []];
515
+ default:
516
+ return [state, []];
517
+ }
518
+ };
519
+ function handleUserMessage(state, event) {
520
+ const data = event.data;
521
+ const turnId = generateId2();
522
+ const contentText = typeof data.content === "string" ? data.content : "";
523
+ const pendingTurn = {
524
+ turnId,
525
+ messageId: data.id,
526
+ content: contentText,
527
+ requestedAt: event.timestamp
528
+ };
529
+ const turnRequestEvent = {
530
+ type: "turn_request",
531
+ timestamp: Date.now(),
532
+ data: {
533
+ turnId,
534
+ messageId: data.id,
535
+ content: contentText,
536
+ timestamp: event.timestamp
537
+ }
538
+ };
539
+ return [
540
+ {
541
+ ...state,
542
+ pendingTurn
543
+ },
544
+ [turnRequestEvent]
545
+ ];
546
+ }
547
+ function handleMessageStop3(state, event) {
548
+ if (!state.pendingTurn) {
549
+ return [state, []];
550
+ }
551
+ const data = event.data;
552
+ const stopReason = data.stopReason;
553
+ if (stopReason === "end_turn" || stopReason === "max_tokens" || stopReason === "stop_sequence") {
554
+ return completeTurn(state, event.timestamp);
555
+ }
556
+ return [state, []];
557
+ }
558
+ function completeTurn(state, completedAt) {
559
+ if (!state.pendingTurn) {
560
+ return [state, []];
561
+ }
562
+ const { turnId, messageId, requestedAt } = state.pendingTurn;
563
+ const duration = completedAt - requestedAt;
564
+ const usage = { inputTokens: 0, outputTokens: 0 };
565
+ const turnResponseEvent = {
566
+ type: "turn_response",
567
+ timestamp: Date.now(),
568
+ data: {
569
+ turnId,
570
+ messageId,
571
+ duration,
572
+ usage,
573
+ timestamp: completedAt
574
+ }
575
+ };
576
+ return [
577
+ {
578
+ ...state,
579
+ pendingTurn: null
580
+ },
581
+ [turnResponseEvent]
582
+ ];
583
+ }
584
+ var turnTrackerProcessorDef = {
585
+ name: "TurnTracker",
586
+ description: "Tracks request-response turn pairs",
587
+ initialState: createInitialTurnTrackerState,
588
+ processor: turnTrackerProcessor
589
+ };
590
+
591
+ // src/engine/AgentProcessor.ts
592
+ var agentProcessor = combineProcessors({
593
+ messageAssembler: messageAssemblerProcessor,
594
+ stateEventProcessor,
595
+ turnTracker: turnTrackerProcessor
596
+ });
597
+ var createInitialAgentEngineState = combineInitialStates({
598
+ messageAssembler: createInitialMessageAssemblerState,
599
+ stateEventProcessor: createInitialStateEventProcessorContext,
600
+ turnTracker: createInitialTurnTrackerState
601
+ });
602
+ var logger3 = createLogger("engine/MealyMachine");
603
+ var MealyMachine = class {
604
+ store;
605
+ constructor() {
606
+ this.store = new MemoryStore();
607
+ logger3.debug("MealyMachine initialized");
608
+ }
609
+ /**
610
+ * Process a single driveable event and return output events
611
+ *
612
+ * This is the core Mealy Machine operation:
613
+ * process(agentId, event) → outputs[]
614
+ *
615
+ * @param agentId - The agent identifier (for state isolation)
616
+ * @param event - StreamEvent to process
617
+ * @returns Array of output events (state, message, turn events)
618
+ */
619
+ process(agentId, event) {
620
+ const eventType = event.type || "unknown";
621
+ logger3.debug("Processing event", { agentId, eventType });
622
+ const isNewState = !this.store.has(agentId);
623
+ let state = this.store.get(agentId) ?? createInitialAgentEngineState();
624
+ if (isNewState) {
625
+ logger3.debug("Created initial state for agent", { agentId });
626
+ }
627
+ const allOutputs = [];
628
+ allOutputs.push(event);
629
+ const [newState, outputs] = agentProcessor(state, event);
630
+ state = newState;
631
+ for (const output of outputs) {
632
+ allOutputs.push(output);
633
+ const [chainedState, chainedOutputs] = this.processChained(state, output);
634
+ state = chainedState;
635
+ allOutputs.push(...chainedOutputs);
636
+ }
637
+ this.store.set(agentId, state);
638
+ if (outputs.length > 0) {
639
+ logger3.debug("Produced outputs", {
640
+ agentId,
641
+ inputEvent: eventType,
642
+ outputCount: allOutputs.length,
643
+ processorOutputs: outputs.length
644
+ });
645
+ }
646
+ return allOutputs;
647
+ }
648
+ /**
649
+ * Process chained events recursively
650
+ *
651
+ * Some processors produce events that trigger other processors:
652
+ * - MessageAssembler produces MessageEvents
653
+ * - TurnTracker consumes MessageEvents to produce TurnEvents
654
+ */
655
+ processChained(state, event) {
656
+ const [newState, outputs] = agentProcessor(state, event);
657
+ if (outputs.length === 0) {
658
+ return [newState, []];
659
+ }
660
+ const allOutputs = [...outputs];
661
+ let currentState = newState;
662
+ for (const output of outputs) {
663
+ const [chainedState, chainedOutputs] = this.processChained(currentState, output);
664
+ currentState = chainedState;
665
+ allOutputs.push(...chainedOutputs);
666
+ }
667
+ return [currentState, allOutputs];
668
+ }
669
+ /**
670
+ * Clear state for an agent
671
+ *
672
+ * Call this when an agent is destroyed to free memory.
673
+ */
674
+ clearState(agentId) {
675
+ logger3.debug("Clearing state", { agentId });
676
+ this.store.delete(agentId);
677
+ }
678
+ /**
679
+ * Check if state exists for an agent
680
+ */
681
+ hasState(agentId) {
682
+ return this.store.has(agentId);
683
+ }
684
+ };
685
+ function createMealyMachine() {
686
+ return new MealyMachine();
687
+ }
688
+ var logger4 = createLogger("agent/AgentStateMachine");
689
+ var AgentStateMachine = class {
690
+ _state = "idle";
691
+ handlers = /* @__PURE__ */ new Set();
692
+ /**
693
+ * Current agent state
694
+ */
695
+ get state() {
696
+ return this._state;
697
+ }
698
+ /**
699
+ * Process an event and update internal state if it's a StateEvent
700
+ *
701
+ * @param event - Event from MealyMachine (could be any AgentOutput)
702
+ */
703
+ process(event) {
704
+ if (!isStateEvent(event)) {
705
+ return;
706
+ }
707
+ const prev = this._state;
708
+ const next = this.mapEventToState(event);
709
+ if (next !== null && prev !== next) {
710
+ this._state = next;
711
+ logger4.debug("State transition", {
712
+ eventType: event.type,
713
+ from: prev,
714
+ to: next
715
+ });
716
+ this.notifyHandlers({ prev, current: next });
717
+ }
718
+ }
719
+ /**
720
+ * Subscribe to state changes
721
+ *
722
+ * @param handler - Callback receiving { prev, current } state change
723
+ * @returns Unsubscribe function
724
+ */
725
+ onStateChange(handler) {
726
+ this.handlers.add(handler);
727
+ return () => {
728
+ this.handlers.delete(handler);
729
+ };
730
+ }
731
+ /**
732
+ * Reset state machine (used on destroy)
733
+ */
734
+ reset() {
735
+ const prev = this._state;
736
+ this._state = "idle";
737
+ if (prev !== "idle") {
738
+ this.notifyHandlers({ prev, current: "idle" });
739
+ }
740
+ this.handlers.clear();
741
+ }
742
+ /**
743
+ * Map StateEvent type to AgentState
744
+ *
745
+ * @param event - StateEvent from MealyMachine
746
+ * @returns New AgentState or null if no transition needed
747
+ */
748
+ mapEventToState(event) {
749
+ switch (event.type) {
750
+ // Conversation lifecycle
751
+ case "conversation_start":
752
+ return "thinking";
753
+ case "conversation_thinking":
754
+ return "thinking";
755
+ case "conversation_responding":
756
+ return "responding";
757
+ case "conversation_end":
758
+ return "idle";
759
+ case "conversation_interrupted":
760
+ return "idle";
761
+ // Tool lifecycle
762
+ case "tool_planned":
763
+ return "planning_tool";
764
+ case "tool_executing":
765
+ return "awaiting_tool_result";
766
+ case "tool_completed":
767
+ return "responding";
768
+ case "tool_failed":
769
+ return "responding";
770
+ // Error
771
+ case "error_occurred":
772
+ return "error";
773
+ default:
774
+ return null;
775
+ }
776
+ }
777
+ /**
778
+ * Notify all registered handlers of state change
779
+ */
780
+ notifyHandlers(change) {
781
+ for (const handler of this.handlers) {
782
+ try {
783
+ handler(change);
784
+ } catch (error) {
785
+ logger4.error("State change handler error", {
786
+ from: change.prev,
787
+ to: change.current,
788
+ error
789
+ });
790
+ }
791
+ }
792
+ }
793
+ };
794
+ var logger5 = createLogger("agent/SimpleAgent");
795
+ function generateAgentId() {
796
+ return `agent_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
797
+ }
798
+ var SimpleMessageQueue = class {
799
+ queue = [];
800
+ get length() {
801
+ return this.queue.length;
802
+ }
803
+ get isEmpty() {
804
+ return this.queue.length === 0;
805
+ }
806
+ enqueue(message) {
807
+ this.queue.push(message);
808
+ }
809
+ dequeue() {
810
+ return this.queue.shift();
811
+ }
812
+ clear() {
813
+ this.queue = [];
814
+ }
815
+ };
816
+ var SimpleAgent = class {
817
+ agentId;
818
+ createdAt;
819
+ messageQueue;
820
+ _messageQueue = new SimpleMessageQueue();
821
+ driver;
822
+ presenter;
823
+ machine;
824
+ stateMachine;
825
+ handlers = /* @__PURE__ */ new Set();
826
+ typeHandlers = /* @__PURE__ */ new Map();
827
+ readyHandlers = /* @__PURE__ */ new Set();
828
+ destroyHandlers = /* @__PURE__ */ new Set();
829
+ middlewares = [];
830
+ interceptors = [];
831
+ isProcessing = false;
832
+ constructor(options) {
833
+ this.agentId = generateAgentId();
834
+ this.createdAt = Date.now();
835
+ this.messageQueue = this._messageQueue;
836
+ this.driver = options.driver;
837
+ this.presenter = options.presenter;
838
+ this.machine = new MealyMachine();
839
+ this.stateMachine = new AgentStateMachine();
840
+ }
841
+ get state() {
842
+ return this.stateMachine.state;
843
+ }
844
+ async receive(message) {
845
+ console.log(
846
+ "[SimpleAgent.receive] CALLED with message:",
847
+ typeof message === "string" ? message : message.content
848
+ );
849
+ const userMessage = typeof message === "string" ? {
850
+ id: `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
851
+ role: "user",
852
+ subtype: "user",
853
+ content: message,
854
+ timestamp: Date.now()
855
+ } : message;
856
+ this._messageQueue.enqueue(userMessage);
857
+ console.log("[SimpleAgent.receive] Message queued, isProcessing:", this.isProcessing);
858
+ if (this.isProcessing) {
859
+ return new Promise((resolve, reject) => {
860
+ userMessage._resolve = resolve;
861
+ userMessage._reject = reject;
862
+ });
863
+ }
864
+ console.log("[SimpleAgent.receive] Starting processQueue");
865
+ await this.processQueue();
866
+ }
867
+ async processQueue() {
868
+ if (this.isProcessing) return;
869
+ this.isProcessing = true;
870
+ console.log("[SimpleAgent.processQueue] Starting, queue size:", this._messageQueue.length);
871
+ while (!this._messageQueue.isEmpty) {
872
+ const message = this._messageQueue.dequeue();
873
+ if (!message) break;
874
+ console.log("[SimpleAgent.processQueue] Processing message:", message.id);
875
+ try {
876
+ await this.processMessage(message);
877
+ if (message._resolve) {
878
+ message._resolve();
879
+ }
880
+ } catch (error) {
881
+ if (message._reject) {
882
+ message._reject(error);
883
+ }
884
+ throw error;
885
+ }
886
+ }
887
+ this.isProcessing = false;
888
+ console.log("[SimpleAgent.processQueue] Finished");
889
+ }
890
+ async processMessage(message) {
891
+ console.log("[SimpleAgent.processMessage] START, message:", message.id);
892
+ let processedMessage = message;
893
+ for (const middleware of this.middlewares) {
894
+ let nextCalled = false;
895
+ await middleware(processedMessage, async (msg) => {
896
+ nextCalled = true;
897
+ processedMessage = msg;
898
+ });
899
+ if (!nextCalled) {
900
+ console.log("[SimpleAgent.processMessage] Middleware blocked message");
901
+ return;
902
+ }
903
+ }
904
+ console.log("[SimpleAgent.processMessage] Getting driver stream...");
905
+ const driverStream = this.driver.receive(processedMessage);
906
+ console.log("[SimpleAgent.processMessage] Driver stream:", driverStream);
907
+ try {
908
+ console.log("[SimpleAgent.processMessage] Starting for-await loop...");
909
+ for await (const streamEvent of driverStream) {
910
+ this.handleStreamEvent(streamEvent);
911
+ }
912
+ console.log("[SimpleAgent.processMessage] For-await loop completed");
913
+ } catch (error) {
914
+ console.log("[SimpleAgent.processMessage] ERROR:", error);
915
+ throw error;
916
+ }
917
+ console.log("[SimpleAgent.processMessage] END");
918
+ }
919
+ /**
920
+ * Handle a stream event from the driver (push-based API)
921
+ *
922
+ * This method processes a single StreamEvent through the MealyMachine
923
+ * and emits all resulting outputs to presenter and handlers.
924
+ */
925
+ handleStreamEvent(event) {
926
+ logger5.info("handleStreamEvent", { type: event.type });
927
+ const outputs = this.machine.process(this.agentId, event);
928
+ logger5.info("MealyMachine outputs", {
929
+ count: outputs.length,
930
+ types: outputs.map((o) => o.type)
931
+ });
932
+ for (const output of outputs) {
933
+ this.stateMachine.process(output);
934
+ this.emitOutput(output);
935
+ }
936
+ }
937
+ emitOutput(output) {
938
+ let currentOutput = output;
939
+ const runInterceptor = (index, out) => {
940
+ if (index >= this.interceptors.length) {
941
+ currentOutput = out;
942
+ return;
943
+ }
944
+ this.interceptors[index](out, (nextOut) => {
945
+ runInterceptor(index + 1, nextOut);
946
+ });
947
+ };
948
+ runInterceptor(0, output);
949
+ if (!currentOutput) return;
950
+ this.presenter.present(this.agentId, currentOutput);
951
+ for (const handler of this.handlers) {
952
+ try {
953
+ handler(currentOutput);
954
+ } catch (e) {
955
+ console.error("Event handler error:", e);
956
+ }
957
+ }
958
+ const typeSet = this.typeHandlers.get(currentOutput.type);
959
+ if (typeSet) {
960
+ for (const handler of typeSet) {
961
+ try {
962
+ handler(currentOutput);
963
+ } catch (e) {
964
+ console.error("Event handler error:", e);
965
+ }
966
+ }
967
+ }
968
+ }
969
+ on(typeOrHandler, handler) {
970
+ if (typeof typeOrHandler === "function") {
971
+ this.handlers.add(typeOrHandler);
972
+ return () => this.handlers.delete(typeOrHandler);
973
+ }
974
+ if (typeof typeOrHandler === "object" && !Array.isArray(typeOrHandler)) {
975
+ const unsubscribes = [];
976
+ for (const [type, h2] of Object.entries(typeOrHandler)) {
977
+ if (h2) {
978
+ unsubscribes.push(this.on(type, h2));
979
+ }
980
+ }
981
+ return () => unsubscribes.forEach((u) => u());
982
+ }
983
+ const types = Array.isArray(typeOrHandler) ? typeOrHandler : [typeOrHandler];
984
+ const h = handler;
985
+ for (const type of types) {
986
+ if (!this.typeHandlers.has(type)) {
987
+ this.typeHandlers.set(type, /* @__PURE__ */ new Set());
988
+ }
989
+ this.typeHandlers.get(type).add(h);
990
+ }
991
+ return () => {
992
+ for (const type of types) {
993
+ this.typeHandlers.get(type)?.delete(h);
994
+ }
995
+ };
996
+ }
997
+ onStateChange(handler) {
998
+ return this.stateMachine.onStateChange(handler);
999
+ }
1000
+ react(handlers) {
1001
+ const eventHandlerMap = {};
1002
+ for (const [key, handler] of Object.entries(handlers)) {
1003
+ if (handler && key.startsWith("on")) {
1004
+ const eventType = key.slice(2).replace(/([A-Z])/g, "_$1").toLowerCase().slice(1);
1005
+ eventHandlerMap[eventType] = handler;
1006
+ }
1007
+ }
1008
+ return this.on(eventHandlerMap);
1009
+ }
1010
+ onReady(handler) {
1011
+ try {
1012
+ handler();
1013
+ } catch (e) {
1014
+ console.error("onReady handler error:", e);
1015
+ }
1016
+ this.readyHandlers.add(handler);
1017
+ return () => this.readyHandlers.delete(handler);
1018
+ }
1019
+ onDestroy(handler) {
1020
+ this.destroyHandlers.add(handler);
1021
+ return () => this.destroyHandlers.delete(handler);
1022
+ }
1023
+ use(middleware) {
1024
+ this.middlewares.push(middleware);
1025
+ return () => {
1026
+ const index = this.middlewares.indexOf(middleware);
1027
+ if (index >= 0) {
1028
+ this.middlewares.splice(index, 1);
1029
+ }
1030
+ };
1031
+ }
1032
+ intercept(interceptor) {
1033
+ this.interceptors.push(interceptor);
1034
+ return () => {
1035
+ const index = this.interceptors.indexOf(interceptor);
1036
+ if (index >= 0) {
1037
+ this.interceptors.splice(index, 1);
1038
+ }
1039
+ };
1040
+ }
1041
+ interrupt() {
1042
+ if (this.state === "idle") {
1043
+ return;
1044
+ }
1045
+ this.driver.interrupt();
1046
+ }
1047
+ async destroy() {
1048
+ if (this.state !== "idle") {
1049
+ this.interrupt();
1050
+ }
1051
+ for (const handler of this.destroyHandlers) {
1052
+ try {
1053
+ handler();
1054
+ } catch (e) {
1055
+ console.error("onDestroy handler error:", e);
1056
+ }
1057
+ }
1058
+ this.machine.clearState(this.agentId);
1059
+ this.stateMachine.reset();
1060
+ this._messageQueue.clear();
1061
+ this.handlers.clear();
1062
+ this.typeHandlers.clear();
1063
+ this.readyHandlers.clear();
1064
+ this.destroyHandlers.clear();
1065
+ this.middlewares.length = 0;
1066
+ this.interceptors.length = 0;
1067
+ }
1068
+ };
1069
+ function createAgent(options) {
1070
+ return new SimpleAgent(options);
1071
+ }
1072
+
1073
+ export { AgentStateMachine, MealyMachine, MemoryStore, agentProcessor, chainProcessors, combineInitialStates, combineProcessors, createAgent, createInitialAgentEngineState, createInitialMessageAssemblerState, createInitialStateEventProcessorContext, createInitialTurnTrackerState, createMealyMachine, filterProcessor, identityProcessor, mapOutput, messageAssemblerProcessor, messageAssemblerProcessorDef, stateEventProcessor, stateEventProcessorDef, turnTrackerProcessor, turnTrackerProcessorDef, withLogging };
1074
+ //# sourceMappingURL=index.js.map
1075
+ //# sourceMappingURL=index.js.map