agentxjs 0.0.3 → 0.0.4
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.cjs +1886 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1742 -30
- package/dist/index.js.map +1 -1
- package/dist/runtime/sse/index.cjs +167 -4
- package/dist/runtime/sse/index.cjs.map +1 -1
- package/dist/runtime/sse/index.js +164 -1
- package/dist/runtime/sse/index.js.map +1 -1
- package/dist/server/index.cjs +163 -3
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +162 -2
- package/dist/server/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var common = require('@agentxjs/common');
|
|
4
|
-
var ky = require('ky');
|
|
5
|
-
var agent = require('@agentxjs/agent');
|
|
6
|
-
var engine = require('@agentxjs/engine');
|
|
7
3
|
var types = require('@agentxjs/types');
|
|
4
|
+
var ky = require('ky');
|
|
5
|
+
var rxjs = require('rxjs');
|
|
6
|
+
var operators = require('rxjs/operators');
|
|
8
7
|
|
|
9
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
9
|
|
|
@@ -23,7 +22,171 @@ function defineAgent(input) {
|
|
|
23
22
|
systemPrompt
|
|
24
23
|
};
|
|
25
24
|
}
|
|
26
|
-
var
|
|
25
|
+
var __defProp2 = Object.defineProperty;
|
|
26
|
+
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
27
|
+
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
28
|
+
var _ConsoleLogger = class _ConsoleLogger2 {
|
|
29
|
+
constructor(name, options = {}) {
|
|
30
|
+
__publicField2(this, "name");
|
|
31
|
+
__publicField2(this, "level");
|
|
32
|
+
__publicField2(this, "colors");
|
|
33
|
+
__publicField2(this, "timestamps");
|
|
34
|
+
this.name = name;
|
|
35
|
+
this.level = options.level ?? types.LogLevel.INFO;
|
|
36
|
+
this.colors = options.colors ?? this.isNodeEnvironment();
|
|
37
|
+
this.timestamps = options.timestamps ?? true;
|
|
38
|
+
}
|
|
39
|
+
debug(message, context) {
|
|
40
|
+
if (this.isDebugEnabled()) {
|
|
41
|
+
this.log("DEBUG", message, context);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
info(message, context) {
|
|
45
|
+
if (this.isInfoEnabled()) {
|
|
46
|
+
this.log("INFO", message, context);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
warn(message, context) {
|
|
50
|
+
if (this.isWarnEnabled()) {
|
|
51
|
+
this.log("WARN", message, context);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
error(message, context) {
|
|
55
|
+
if (this.isErrorEnabled()) {
|
|
56
|
+
if (message instanceof Error) {
|
|
57
|
+
this.log("ERROR", message.message, { ...context, stack: message.stack });
|
|
58
|
+
} else {
|
|
59
|
+
this.log("ERROR", message, context);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
isDebugEnabled() {
|
|
64
|
+
return this.level <= types.LogLevel.DEBUG;
|
|
65
|
+
}
|
|
66
|
+
isInfoEnabled() {
|
|
67
|
+
return this.level <= types.LogLevel.INFO;
|
|
68
|
+
}
|
|
69
|
+
isWarnEnabled() {
|
|
70
|
+
return this.level <= types.LogLevel.WARN;
|
|
71
|
+
}
|
|
72
|
+
isErrorEnabled() {
|
|
73
|
+
return this.level <= types.LogLevel.ERROR;
|
|
74
|
+
}
|
|
75
|
+
log(level, message, context) {
|
|
76
|
+
const parts = [];
|
|
77
|
+
if (this.timestamps) {
|
|
78
|
+
parts.push((/* @__PURE__ */ new Date()).toISOString());
|
|
79
|
+
}
|
|
80
|
+
if (this.colors) {
|
|
81
|
+
const color = _ConsoleLogger2.COLORS[level];
|
|
82
|
+
parts.push(`${color}${level.padEnd(5)}${_ConsoleLogger2.COLORS.RESET}`);
|
|
83
|
+
} else {
|
|
84
|
+
parts.push(level.padEnd(5));
|
|
85
|
+
}
|
|
86
|
+
parts.push(`[${this.name}]`);
|
|
87
|
+
parts.push(message);
|
|
88
|
+
const logLine = parts.join(" ");
|
|
89
|
+
const consoleMethod = this.getConsoleMethod(level);
|
|
90
|
+
if (context && Object.keys(context).length > 0) {
|
|
91
|
+
consoleMethod(logLine, context);
|
|
92
|
+
} else {
|
|
93
|
+
consoleMethod(logLine);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
getConsoleMethod(level) {
|
|
97
|
+
switch (level) {
|
|
98
|
+
case "DEBUG":
|
|
99
|
+
return console.debug.bind(console);
|
|
100
|
+
case "INFO":
|
|
101
|
+
return console.info.bind(console);
|
|
102
|
+
case "WARN":
|
|
103
|
+
return console.warn.bind(console);
|
|
104
|
+
case "ERROR":
|
|
105
|
+
return console.error.bind(console);
|
|
106
|
+
default:
|
|
107
|
+
return console.log.bind(console);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
isNodeEnvironment() {
|
|
111
|
+
return typeof process !== "undefined" && process.versions?.node !== void 0;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
__publicField2(_ConsoleLogger, "COLORS", {
|
|
115
|
+
DEBUG: "\x1B[36m",
|
|
116
|
+
INFO: "\x1B[32m",
|
|
117
|
+
WARN: "\x1B[33m",
|
|
118
|
+
ERROR: "\x1B[31m",
|
|
119
|
+
RESET: "\x1B[0m"
|
|
120
|
+
});
|
|
121
|
+
var ConsoleLogger = _ConsoleLogger;
|
|
122
|
+
var externalFactory = null;
|
|
123
|
+
var LoggerFactoryImpl = class {
|
|
124
|
+
static getLogger(nameOrClass) {
|
|
125
|
+
const name = typeof nameOrClass === "string" ? nameOrClass : nameOrClass.name;
|
|
126
|
+
if (this.loggers.has(name)) {
|
|
127
|
+
return this.loggers.get(name);
|
|
128
|
+
}
|
|
129
|
+
const lazyLogger = this.createLazyLogger(name);
|
|
130
|
+
this.loggers.set(name, lazyLogger);
|
|
131
|
+
return lazyLogger;
|
|
132
|
+
}
|
|
133
|
+
static configure(config) {
|
|
134
|
+
this.config = { ...this.config, ...config };
|
|
135
|
+
}
|
|
136
|
+
static reset() {
|
|
137
|
+
this.loggers.clear();
|
|
138
|
+
this.config = { defaultLevel: types.LogLevel.INFO };
|
|
139
|
+
externalFactory = null;
|
|
140
|
+
}
|
|
141
|
+
static createLazyLogger(name) {
|
|
142
|
+
let realLogger = null;
|
|
143
|
+
const getRealLogger = () => {
|
|
144
|
+
if (!realLogger) {
|
|
145
|
+
realLogger = this.createLogger(name);
|
|
146
|
+
}
|
|
147
|
+
return realLogger;
|
|
148
|
+
};
|
|
149
|
+
return {
|
|
150
|
+
name,
|
|
151
|
+
level: this.config.defaultLevel || types.LogLevel.INFO,
|
|
152
|
+
debug: (message, context) => getRealLogger().debug(message, context),
|
|
153
|
+
info: (message, context) => getRealLogger().info(message, context),
|
|
154
|
+
warn: (message, context) => getRealLogger().warn(message, context),
|
|
155
|
+
error: (message, context) => getRealLogger().error(message, context),
|
|
156
|
+
isDebugEnabled: () => getRealLogger().isDebugEnabled(),
|
|
157
|
+
isInfoEnabled: () => getRealLogger().isInfoEnabled(),
|
|
158
|
+
isWarnEnabled: () => getRealLogger().isWarnEnabled(),
|
|
159
|
+
isErrorEnabled: () => getRealLogger().isErrorEnabled()
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
static createLogger(name) {
|
|
163
|
+
if (externalFactory) {
|
|
164
|
+
return externalFactory.getLogger(name);
|
|
165
|
+
}
|
|
166
|
+
if (this.config.defaultImplementation) {
|
|
167
|
+
return this.config.defaultImplementation(name);
|
|
168
|
+
}
|
|
169
|
+
return new ConsoleLogger(name, {
|
|
170
|
+
level: this.config.defaultLevel,
|
|
171
|
+
...this.config.consoleOptions
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
__publicField2(LoggerFactoryImpl, "loggers", /* @__PURE__ */ new Map());
|
|
176
|
+
__publicField2(LoggerFactoryImpl, "config", {
|
|
177
|
+
defaultLevel: types.LogLevel.INFO
|
|
178
|
+
});
|
|
179
|
+
function setLoggerFactory(factory) {
|
|
180
|
+
externalFactory = factory;
|
|
181
|
+
LoggerFactoryImpl.reset();
|
|
182
|
+
externalFactory = factory;
|
|
183
|
+
}
|
|
184
|
+
function createLogger(name) {
|
|
185
|
+
return LoggerFactoryImpl.getLogger(name);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/managers/definition/DefinitionManagerImpl.ts
|
|
189
|
+
var logger = createLogger("agentx/DefinitionManager");
|
|
27
190
|
function generateMetaImageId(definitionName) {
|
|
28
191
|
return `meta_${definitionName}`;
|
|
29
192
|
}
|
|
@@ -99,7 +262,9 @@ var DefinitionManagerImpl = class {
|
|
|
99
262
|
return true;
|
|
100
263
|
}
|
|
101
264
|
};
|
|
102
|
-
|
|
265
|
+
|
|
266
|
+
// src/managers/image/ImageManagerImpl.ts
|
|
267
|
+
var logger2 = createLogger("agentx/ImageManager");
|
|
103
268
|
function generateMetaImageId2(definitionName) {
|
|
104
269
|
return `meta_${definitionName}`;
|
|
105
270
|
}
|
|
@@ -194,7 +359,9 @@ var ImageManagerImpl = class {
|
|
|
194
359
|
return this.containerManager.run(image, containerId);
|
|
195
360
|
}
|
|
196
361
|
};
|
|
197
|
-
|
|
362
|
+
|
|
363
|
+
// src/managers/agent/AgentManager.ts
|
|
364
|
+
var logger3 = createLogger("agentx/AgentManager");
|
|
198
365
|
var AgentManager = class {
|
|
199
366
|
constructor(containerManager) {
|
|
200
367
|
this.containerManager = containerManager;
|
|
@@ -235,7 +402,9 @@ var AgentManager = class {
|
|
|
235
402
|
logger3.info("All agents destroyed", { count: agents.length });
|
|
236
403
|
}
|
|
237
404
|
};
|
|
238
|
-
|
|
405
|
+
|
|
406
|
+
// src/managers/session/SessionManagerImpl.ts
|
|
407
|
+
var logger4 = createLogger("agentx/SessionManager");
|
|
239
408
|
function generateSessionId() {
|
|
240
409
|
const timestamp = Date.now().toString(36);
|
|
241
410
|
const random = Math.random().toString(36).substring(2, 8);
|
|
@@ -367,170 +536,1709 @@ var SessionImpl = class _SessionImpl {
|
|
|
367
536
|
this.defaultContainerId
|
|
368
537
|
);
|
|
369
538
|
}
|
|
370
|
-
async setTitle(title) {
|
|
371
|
-
logger4.debug("Setting session title", { sessionId: this.sessionId, title });
|
|
372
|
-
const now = /* @__PURE__ */ new Date();
|
|
373
|
-
await this.repository.saveSession({
|
|
374
|
-
sessionId: this.sessionId,
|
|
375
|
-
userId: this.userId,
|
|
376
|
-
imageId: this.imageId,
|
|
377
|
-
title,
|
|
378
|
-
createdAt: new Date(this.createdAt),
|
|
379
|
-
updatedAt: now
|
|
380
|
-
});
|
|
381
|
-
this._title = title;
|
|
382
|
-
this._updatedAt = now.getTime();
|
|
383
|
-
logger4.info("Session title updated", { sessionId: this.sessionId, title });
|
|
539
|
+
async setTitle(title) {
|
|
540
|
+
logger4.debug("Setting session title", { sessionId: this.sessionId, title });
|
|
541
|
+
const now = /* @__PURE__ */ new Date();
|
|
542
|
+
await this.repository.saveSession({
|
|
543
|
+
sessionId: this.sessionId,
|
|
544
|
+
userId: this.userId,
|
|
545
|
+
imageId: this.imageId,
|
|
546
|
+
title,
|
|
547
|
+
createdAt: new Date(this.createdAt),
|
|
548
|
+
updatedAt: now
|
|
549
|
+
});
|
|
550
|
+
this._title = title;
|
|
551
|
+
this._updatedAt = now.getTime();
|
|
552
|
+
logger4.info("Session title updated", { sessionId: this.sessionId, title });
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
var SessionManagerImpl = class {
|
|
556
|
+
constructor(repository, containerManager, defaultContainerId) {
|
|
557
|
+
__publicField(this, "repository");
|
|
558
|
+
__publicField(this, "containerManager");
|
|
559
|
+
__publicField(this, "defaultContainerId");
|
|
560
|
+
this.repository = repository;
|
|
561
|
+
this.containerManager = containerManager;
|
|
562
|
+
this.defaultContainerId = defaultContainerId;
|
|
563
|
+
}
|
|
564
|
+
async create(imageId, userId) {
|
|
565
|
+
const sessionId = generateSessionId();
|
|
566
|
+
const now = /* @__PURE__ */ new Date();
|
|
567
|
+
const record = {
|
|
568
|
+
sessionId,
|
|
569
|
+
userId,
|
|
570
|
+
imageId,
|
|
571
|
+
title: null,
|
|
572
|
+
createdAt: now,
|
|
573
|
+
updatedAt: now
|
|
574
|
+
};
|
|
575
|
+
await this.repository.saveSession(record);
|
|
576
|
+
logger4.info("Session created", { sessionId, imageId, userId });
|
|
577
|
+
return new SessionImpl(record, this.repository, this.containerManager, this.defaultContainerId);
|
|
578
|
+
}
|
|
579
|
+
async get(sessionId) {
|
|
580
|
+
const record = await this.repository.findSessionById(sessionId);
|
|
581
|
+
if (!record) return void 0;
|
|
582
|
+
return new SessionImpl(record, this.repository, this.containerManager, this.defaultContainerId);
|
|
583
|
+
}
|
|
584
|
+
async has(sessionId) {
|
|
585
|
+
return this.repository.sessionExists(sessionId);
|
|
586
|
+
}
|
|
587
|
+
async list() {
|
|
588
|
+
const records = await this.repository.findAllSessions();
|
|
589
|
+
return records.map(
|
|
590
|
+
(r) => new SessionImpl(r, this.repository, this.containerManager, this.defaultContainerId)
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
async listByImage(imageId) {
|
|
594
|
+
const records = await this.repository.findSessionsByImageId(imageId);
|
|
595
|
+
return records.map(
|
|
596
|
+
(r) => new SessionImpl(r, this.repository, this.containerManager, this.defaultContainerId)
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
async listByUser(userId) {
|
|
600
|
+
const records = await this.repository.findSessionsByUserId(userId);
|
|
601
|
+
return records.map(
|
|
602
|
+
(r) => new SessionImpl(r, this.repository, this.containerManager, this.defaultContainerId)
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
async destroy(sessionId) {
|
|
606
|
+
await this.repository.deleteSession(sessionId);
|
|
607
|
+
logger4.info("Session destroyed", { sessionId });
|
|
608
|
+
}
|
|
609
|
+
async destroyByImage(imageId) {
|
|
610
|
+
await this.repository.deleteSessionsByImageId(imageId);
|
|
611
|
+
logger4.info("Sessions destroyed by image", { imageId });
|
|
612
|
+
}
|
|
613
|
+
async destroyAll() {
|
|
614
|
+
const sessions = await this.repository.findAllSessions();
|
|
615
|
+
for (const session of sessions) {
|
|
616
|
+
await this.repository.deleteSession(session.sessionId);
|
|
617
|
+
}
|
|
618
|
+
logger4.info("All sessions destroyed");
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
// src/managers/error/ErrorManager.ts
|
|
623
|
+
var logger5 = createLogger("agentx/ErrorManager");
|
|
624
|
+
var ErrorManager = class {
|
|
625
|
+
constructor() {
|
|
626
|
+
__publicField(this, "handlers", /* @__PURE__ */ new Set());
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Handle an error from any agent
|
|
630
|
+
*
|
|
631
|
+
* Called internally when an agent emits an error event.
|
|
632
|
+
* 1. Default logging (always)
|
|
633
|
+
* 2. Custom handlers (user-registered)
|
|
634
|
+
*/
|
|
635
|
+
handle(agentId, error, event) {
|
|
636
|
+
this.logError(agentId, error);
|
|
637
|
+
for (const handler of this.handlers) {
|
|
638
|
+
try {
|
|
639
|
+
handler.handle(agentId, error, event);
|
|
640
|
+
} catch (e) {
|
|
641
|
+
logger5.error("ErrorHandler failed", { error: e });
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Add a custom error handler
|
|
647
|
+
*/
|
|
648
|
+
addHandler(handler) {
|
|
649
|
+
this.handlers.add(handler);
|
|
650
|
+
return () => {
|
|
651
|
+
this.handlers.delete(handler);
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Remove an error handler
|
|
656
|
+
*/
|
|
657
|
+
removeHandler(handler) {
|
|
658
|
+
this.handlers.delete(handler);
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Default error logging
|
|
662
|
+
*/
|
|
663
|
+
logError(agentId, error) {
|
|
664
|
+
const prefix = `[${agentId}] ${error.category}/${error.code}`;
|
|
665
|
+
if (error.severity === "fatal") {
|
|
666
|
+
logger5.error(`${prefix}: ${error.message}`, { error });
|
|
667
|
+
} else if (error.severity === "error") {
|
|
668
|
+
logger5.error(`${prefix}: ${error.message}`);
|
|
669
|
+
} else {
|
|
670
|
+
logger5.warn(`${prefix}: ${error.message}`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
var ApiError = class extends Error {
|
|
675
|
+
constructor(code, message, details) {
|
|
676
|
+
super(message);
|
|
677
|
+
this.code = code;
|
|
678
|
+
this.details = details;
|
|
679
|
+
this.name = "ApiError";
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
function createHttpClient(options) {
|
|
683
|
+
return ky__default.default.create({
|
|
684
|
+
prefixUrl: options.baseUrl.replace(/\/+$/, ""),
|
|
685
|
+
headers: options.headers,
|
|
686
|
+
timeout: options.timeout || 3e4,
|
|
687
|
+
hooks: {
|
|
688
|
+
afterResponse: [
|
|
689
|
+
async (_request, _options, response) => {
|
|
690
|
+
if (!response.ok) {
|
|
691
|
+
const data = await response.json().catch(() => ({}));
|
|
692
|
+
throw new ApiError(
|
|
693
|
+
data.error?.code || "UNKNOWN_ERROR",
|
|
694
|
+
data.error?.message || `Request failed: ${response.status}`,
|
|
695
|
+
data.error?.details
|
|
696
|
+
);
|
|
697
|
+
}
|
|
698
|
+
return response;
|
|
699
|
+
}
|
|
700
|
+
]
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
var logger6 = createLogger("core/AgentStateMachine");
|
|
705
|
+
var AgentStateMachine = class {
|
|
706
|
+
constructor() {
|
|
707
|
+
__publicField(this, "_state", "idle");
|
|
708
|
+
__publicField(this, "handlers", /* @__PURE__ */ new Set());
|
|
709
|
+
}
|
|
710
|
+
/**
|
|
711
|
+
* Current agent state
|
|
712
|
+
*/
|
|
713
|
+
get state() {
|
|
714
|
+
return this._state;
|
|
715
|
+
}
|
|
716
|
+
/**
|
|
717
|
+
* Process a StateEvent and update internal state
|
|
718
|
+
*
|
|
719
|
+
* @param event - StateEvent from Engine layer
|
|
720
|
+
*/
|
|
721
|
+
process(event) {
|
|
722
|
+
const prev = this._state;
|
|
723
|
+
const next = this.mapEventToState(event);
|
|
724
|
+
if (next !== null && prev !== next) {
|
|
725
|
+
this._state = next;
|
|
726
|
+
logger6.debug("State transition", {
|
|
727
|
+
eventType: event.type,
|
|
728
|
+
from: prev,
|
|
729
|
+
to: next
|
|
730
|
+
});
|
|
731
|
+
this.notifyHandlers({ prev, current: next });
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Subscribe to state changes
|
|
736
|
+
*
|
|
737
|
+
* @param handler - Callback receiving { prev, current } state change
|
|
738
|
+
* @returns Unsubscribe function
|
|
739
|
+
*/
|
|
740
|
+
onStateChange(handler) {
|
|
741
|
+
this.handlers.add(handler);
|
|
742
|
+
return () => {
|
|
743
|
+
this.handlers.delete(handler);
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Reset state machine (used on destroy)
|
|
748
|
+
*/
|
|
749
|
+
reset() {
|
|
750
|
+
this._state;
|
|
751
|
+
this._state = "idle";
|
|
752
|
+
this.handlers.clear();
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* Map StateEvent type to AgentState
|
|
756
|
+
*
|
|
757
|
+
* @param event - StateEvent from Engine
|
|
758
|
+
* @returns New AgentState or null if no transition needed
|
|
759
|
+
*/
|
|
760
|
+
mapEventToState(event) {
|
|
761
|
+
switch (event.type) {
|
|
762
|
+
// Agent lifecycle
|
|
763
|
+
case "agent_initializing":
|
|
764
|
+
return "initializing";
|
|
765
|
+
case "agent_ready":
|
|
766
|
+
return "idle";
|
|
767
|
+
case "agent_destroyed":
|
|
768
|
+
return "idle";
|
|
769
|
+
// Conversation lifecycle
|
|
770
|
+
case "conversation_queued":
|
|
771
|
+
return "queued";
|
|
772
|
+
case "conversation_start":
|
|
773
|
+
return "conversation_active";
|
|
774
|
+
case "conversation_thinking":
|
|
775
|
+
return "thinking";
|
|
776
|
+
case "conversation_responding":
|
|
777
|
+
return "responding";
|
|
778
|
+
case "conversation_end":
|
|
779
|
+
return "idle";
|
|
780
|
+
case "conversation_interrupted":
|
|
781
|
+
return "idle";
|
|
782
|
+
// Return to idle on interrupt
|
|
783
|
+
// Tool lifecycle
|
|
784
|
+
case "tool_planned":
|
|
785
|
+
return "planning_tool";
|
|
786
|
+
case "tool_executing":
|
|
787
|
+
return "awaiting_tool_result";
|
|
788
|
+
case "tool_completed":
|
|
789
|
+
return "responding";
|
|
790
|
+
// Back to responding after tool completes
|
|
791
|
+
case "tool_failed":
|
|
792
|
+
return "responding";
|
|
793
|
+
// Continue responding after tool failure
|
|
794
|
+
// Error
|
|
795
|
+
case "error_occurred":
|
|
796
|
+
return "idle";
|
|
797
|
+
// Reset to idle on error
|
|
798
|
+
default:
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Notify all registered handlers of state change
|
|
804
|
+
*/
|
|
805
|
+
notifyHandlers(change) {
|
|
806
|
+
for (const handler of this.handlers) {
|
|
807
|
+
try {
|
|
808
|
+
handler(change);
|
|
809
|
+
} catch (error) {
|
|
810
|
+
logger6.error("State change handler error", {
|
|
811
|
+
from: change.prev,
|
|
812
|
+
to: change.current,
|
|
813
|
+
error
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
var logger22 = createLogger("core/AgentEventBus");
|
|
820
|
+
var AgentEventBus = class {
|
|
821
|
+
constructor() {
|
|
822
|
+
__publicField(this, "subject", new rxjs.Subject());
|
|
823
|
+
__publicField(this, "typeSubscriptions", /* @__PURE__ */ new Map());
|
|
824
|
+
__publicField(this, "globalSubscriptions", []);
|
|
825
|
+
__publicField(this, "nextId", 0);
|
|
826
|
+
__publicField(this, "isDestroyed", false);
|
|
827
|
+
// Cached views
|
|
828
|
+
__publicField(this, "producerView", null);
|
|
829
|
+
__publicField(this, "consumerView", null);
|
|
830
|
+
}
|
|
831
|
+
// ===== Producer Methods =====
|
|
832
|
+
emit(event) {
|
|
833
|
+
if (this.isDestroyed) {
|
|
834
|
+
logger22.warn("Emit called on destroyed EventBus", { eventType: event.type });
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
this.subject.next(event);
|
|
838
|
+
}
|
|
839
|
+
emitBatch(events) {
|
|
840
|
+
for (const event of events) {
|
|
841
|
+
this.emit(event);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
on(typeOrTypes, handler, options = {}) {
|
|
845
|
+
if (this.isDestroyed) {
|
|
846
|
+
logger22.warn("Subscribe called on destroyed EventBus");
|
|
847
|
+
return () => {
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes];
|
|
851
|
+
const unsubscribes = [];
|
|
852
|
+
for (const type of types) {
|
|
853
|
+
const unsub = this.subscribeToType(type, handler, options);
|
|
854
|
+
unsubscribes.push(unsub);
|
|
855
|
+
}
|
|
856
|
+
return () => unsubscribes.forEach((u) => u());
|
|
857
|
+
}
|
|
858
|
+
onAny(handler, options = {}) {
|
|
859
|
+
if (this.isDestroyed) {
|
|
860
|
+
logger22.warn("Subscribe called on destroyed EventBus");
|
|
861
|
+
return () => {
|
|
862
|
+
};
|
|
863
|
+
}
|
|
864
|
+
return this.subscribeGlobal(handler, options);
|
|
865
|
+
}
|
|
866
|
+
once(type, handler) {
|
|
867
|
+
return this.on(type, handler, { once: true });
|
|
868
|
+
}
|
|
869
|
+
// ===== View Methods =====
|
|
870
|
+
asConsumer() {
|
|
871
|
+
if (!this.consumerView) {
|
|
872
|
+
this.consumerView = {
|
|
873
|
+
on: this.on.bind(this),
|
|
874
|
+
onAny: this.onAny.bind(this),
|
|
875
|
+
once: this.once.bind(this)
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
return this.consumerView;
|
|
879
|
+
}
|
|
880
|
+
asProducer() {
|
|
881
|
+
if (!this.producerView) {
|
|
882
|
+
this.producerView = {
|
|
883
|
+
emit: this.emit.bind(this),
|
|
884
|
+
emitBatch: this.emitBatch.bind(this)
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
return this.producerView;
|
|
888
|
+
}
|
|
889
|
+
// ===== Lifecycle =====
|
|
890
|
+
destroy() {
|
|
891
|
+
if (this.isDestroyed) return;
|
|
892
|
+
this.isDestroyed = true;
|
|
893
|
+
for (const records of this.typeSubscriptions.values()) {
|
|
894
|
+
for (const record of records) {
|
|
895
|
+
record.unsubscribe();
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
this.typeSubscriptions.clear();
|
|
899
|
+
for (const record of this.globalSubscriptions) {
|
|
900
|
+
record.unsubscribe();
|
|
901
|
+
}
|
|
902
|
+
this.globalSubscriptions.length = 0;
|
|
903
|
+
this.subject.complete();
|
|
904
|
+
logger22.debug("EventBus destroyed");
|
|
905
|
+
}
|
|
906
|
+
// ===== Private Methods =====
|
|
907
|
+
subscribeToType(type, handler, options) {
|
|
908
|
+
const { filter: filter$1, priority = 0, once = false } = options;
|
|
909
|
+
const id = this.nextId++;
|
|
910
|
+
let observable = this.subject.pipe(operators.filter((e) => e.type === type));
|
|
911
|
+
if (filter$1) {
|
|
912
|
+
observable = observable.pipe(operators.filter(filter$1));
|
|
913
|
+
}
|
|
914
|
+
if (once) {
|
|
915
|
+
observable = observable.pipe(operators.take(1));
|
|
916
|
+
}
|
|
917
|
+
const subscription = observable.subscribe({
|
|
918
|
+
next: (event) => {
|
|
919
|
+
this.executeWithPriority(type, event, handler, id);
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
const unsubscribe = () => {
|
|
923
|
+
subscription.unsubscribe();
|
|
924
|
+
const records2 = this.typeSubscriptions.get(type);
|
|
925
|
+
if (records2) {
|
|
926
|
+
const idx = records2.findIndex((r) => r.id === id);
|
|
927
|
+
if (idx !== -1) records2.splice(idx, 1);
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
if (!this.typeSubscriptions.has(type)) {
|
|
931
|
+
this.typeSubscriptions.set(type, []);
|
|
932
|
+
}
|
|
933
|
+
const record = { id, priority, handler, unsubscribe };
|
|
934
|
+
const records = this.typeSubscriptions.get(type);
|
|
935
|
+
records.push(record);
|
|
936
|
+
records.sort((a, b) => b.priority - a.priority);
|
|
937
|
+
return unsubscribe;
|
|
938
|
+
}
|
|
939
|
+
subscribeGlobal(handler, options) {
|
|
940
|
+
const { filter: filter$1, priority = 0, once = false } = options;
|
|
941
|
+
const id = this.nextId++;
|
|
942
|
+
let observable = this.subject.asObservable();
|
|
943
|
+
if (filter$1) {
|
|
944
|
+
observable = observable.pipe(operators.filter(filter$1));
|
|
945
|
+
}
|
|
946
|
+
if (once) {
|
|
947
|
+
observable = observable.pipe(operators.take(1));
|
|
948
|
+
}
|
|
949
|
+
const subscription = observable.subscribe({
|
|
950
|
+
next: (event) => {
|
|
951
|
+
this.executeGlobalWithPriority(event, handler, id);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
const unsubscribe = () => {
|
|
955
|
+
subscription.unsubscribe();
|
|
956
|
+
const idx = this.globalSubscriptions.findIndex((r) => r.id === id);
|
|
957
|
+
if (idx !== -1) this.globalSubscriptions.splice(idx, 1);
|
|
958
|
+
};
|
|
959
|
+
const record = { id, priority, handler, unsubscribe };
|
|
960
|
+
this.globalSubscriptions.push(record);
|
|
961
|
+
this.globalSubscriptions.sort((a, b) => b.priority - a.priority);
|
|
962
|
+
return unsubscribe;
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Execute handler respecting priority order for typed subscriptions
|
|
966
|
+
*/
|
|
967
|
+
executeWithPriority(type, event, handler, handlerId) {
|
|
968
|
+
const records = this.typeSubscriptions.get(type) || [];
|
|
969
|
+
const record = records.find((r) => r.id === handlerId);
|
|
970
|
+
if (record) {
|
|
971
|
+
try {
|
|
972
|
+
handler(event);
|
|
973
|
+
} catch (error) {
|
|
974
|
+
logger22.error("Event handler error", { eventType: type, error });
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Execute handler respecting priority order for global subscriptions
|
|
980
|
+
*/
|
|
981
|
+
executeGlobalWithPriority(event, handler, handlerId) {
|
|
982
|
+
const record = this.globalSubscriptions.find((r) => r.id === handlerId);
|
|
983
|
+
if (record) {
|
|
984
|
+
try {
|
|
985
|
+
handler(event);
|
|
986
|
+
} catch (error) {
|
|
987
|
+
logger22.error("Global event handler error", { eventType: event.type, error });
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
var AgentErrorClassifier = class {
|
|
993
|
+
constructor(agentId) {
|
|
994
|
+
this.agentId = agentId;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Classify an unknown error into an AgentError
|
|
998
|
+
*/
|
|
999
|
+
classify(error) {
|
|
1000
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1001
|
+
const message = err.message;
|
|
1002
|
+
if (message.includes("rate limit") || message.includes("429")) {
|
|
1003
|
+
return this.create("llm", "RATE_LIMITED", message, true, err);
|
|
1004
|
+
}
|
|
1005
|
+
if (message.includes("api key") || message.includes("401") || message.includes("unauthorized")) {
|
|
1006
|
+
return this.create("llm", "INVALID_API_KEY", message, false, err);
|
|
1007
|
+
}
|
|
1008
|
+
if (message.includes("context") && message.includes("long")) {
|
|
1009
|
+
return this.create("llm", "CONTEXT_TOO_LONG", message, true, err);
|
|
1010
|
+
}
|
|
1011
|
+
if (message.includes("overloaded") || message.includes("503")) {
|
|
1012
|
+
return this.create("llm", "OVERLOADED", message, true, err);
|
|
1013
|
+
}
|
|
1014
|
+
if (message.includes("timeout") || message.includes("ETIMEDOUT")) {
|
|
1015
|
+
return this.create("network", "TIMEOUT", message, true, err);
|
|
1016
|
+
}
|
|
1017
|
+
if (message.includes("ECONNREFUSED") || message.includes("connection")) {
|
|
1018
|
+
return this.create("network", "CONNECTION_FAILED", message, true, err);
|
|
1019
|
+
}
|
|
1020
|
+
if (message.includes("network") || message.includes("fetch")) {
|
|
1021
|
+
return this.create("network", "CONNECTION_FAILED", message, true, err);
|
|
1022
|
+
}
|
|
1023
|
+
if (message.includes("driver")) {
|
|
1024
|
+
return this.create("driver", "RECEIVE_FAILED", message, true, err);
|
|
1025
|
+
}
|
|
1026
|
+
return this.create("system", "UNKNOWN", message, true, err);
|
|
1027
|
+
}
|
|
1028
|
+
/**
|
|
1029
|
+
* Create an AgentError with the specified category and code
|
|
1030
|
+
*/
|
|
1031
|
+
create(category, code, message, recoverable, cause) {
|
|
1032
|
+
return {
|
|
1033
|
+
category,
|
|
1034
|
+
code,
|
|
1035
|
+
message,
|
|
1036
|
+
severity: recoverable ? "error" : "fatal",
|
|
1037
|
+
recoverable,
|
|
1038
|
+
cause
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Create an ErrorEvent from an AgentError
|
|
1043
|
+
*
|
|
1044
|
+
* ErrorEvent is independent from Message layer and transportable via SSE.
|
|
1045
|
+
*/
|
|
1046
|
+
createEvent(error) {
|
|
1047
|
+
return {
|
|
1048
|
+
type: "error",
|
|
1049
|
+
uuid: `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
1050
|
+
agentId: this.agentId,
|
|
1051
|
+
timestamp: Date.now(),
|
|
1052
|
+
data: {
|
|
1053
|
+
error
|
|
1054
|
+
}
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
};
|
|
1058
|
+
var MiddlewareChain = class {
|
|
1059
|
+
constructor() {
|
|
1060
|
+
__publicField(this, "middlewares", []);
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Add middleware to the chain
|
|
1064
|
+
*
|
|
1065
|
+
* @param middleware - Middleware function
|
|
1066
|
+
* @returns Unsubscribe function to remove the middleware
|
|
1067
|
+
*/
|
|
1068
|
+
use(middleware) {
|
|
1069
|
+
this.middlewares.push(middleware);
|
|
1070
|
+
return () => {
|
|
1071
|
+
const index = this.middlewares.indexOf(middleware);
|
|
1072
|
+
if (index !== -1) {
|
|
1073
|
+
this.middlewares.splice(index, 1);
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Execute the middleware chain
|
|
1079
|
+
*
|
|
1080
|
+
* @param message - User message to process
|
|
1081
|
+
* @param finalHandler - Handler called at the end of the chain
|
|
1082
|
+
*/
|
|
1083
|
+
async execute(message, finalHandler) {
|
|
1084
|
+
let index = 0;
|
|
1085
|
+
const next = async (msg) => {
|
|
1086
|
+
if (index < this.middlewares.length) {
|
|
1087
|
+
const middleware = this.middlewares[index++];
|
|
1088
|
+
await middleware(msg, next);
|
|
1089
|
+
} else {
|
|
1090
|
+
await finalHandler(msg);
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
await next(message);
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Clear all middlewares
|
|
1097
|
+
*/
|
|
1098
|
+
clear() {
|
|
1099
|
+
this.middlewares.length = 0;
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Get the number of middlewares
|
|
1103
|
+
*/
|
|
1104
|
+
get size() {
|
|
1105
|
+
return this.middlewares.length;
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
var logger32 = createLogger("core/InterceptorChain");
|
|
1109
|
+
var InterceptorChain = class {
|
|
1110
|
+
constructor(agentId) {
|
|
1111
|
+
__publicField(this, "interceptors", []);
|
|
1112
|
+
__publicField(this, "agentId");
|
|
1113
|
+
this.agentId = agentId;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Add interceptor to the chain
|
|
1117
|
+
*
|
|
1118
|
+
* @param interceptor - Interceptor function
|
|
1119
|
+
* @returns Unsubscribe function to remove the interceptor
|
|
1120
|
+
*/
|
|
1121
|
+
intercept(interceptor) {
|
|
1122
|
+
this.interceptors.push(interceptor);
|
|
1123
|
+
return () => {
|
|
1124
|
+
const index = this.interceptors.indexOf(interceptor);
|
|
1125
|
+
if (index !== -1) {
|
|
1126
|
+
this.interceptors.splice(index, 1);
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Execute the interceptor chain
|
|
1132
|
+
*
|
|
1133
|
+
* @param event - Event to process
|
|
1134
|
+
* @param finalHandler - Handler called at the end of the chain
|
|
1135
|
+
*/
|
|
1136
|
+
execute(event, finalHandler) {
|
|
1137
|
+
let index = 0;
|
|
1138
|
+
const next = (e) => {
|
|
1139
|
+
if (index < this.interceptors.length) {
|
|
1140
|
+
const interceptor = this.interceptors[index++];
|
|
1141
|
+
try {
|
|
1142
|
+
interceptor(e, next);
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
logger32.error("Interceptor error", {
|
|
1145
|
+
agentId: this.agentId,
|
|
1146
|
+
eventType: e.type,
|
|
1147
|
+
interceptorIndex: index - 1,
|
|
1148
|
+
error
|
|
1149
|
+
});
|
|
1150
|
+
next(e);
|
|
1151
|
+
}
|
|
1152
|
+
} else {
|
|
1153
|
+
finalHandler(e);
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
next(event);
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Clear all interceptors
|
|
1160
|
+
*/
|
|
1161
|
+
clear() {
|
|
1162
|
+
this.interceptors.length = 0;
|
|
1163
|
+
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Get the number of interceptors
|
|
1166
|
+
*/
|
|
1167
|
+
get size() {
|
|
1168
|
+
return this.interceptors.length;
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
var REACT_TO_EVENT_MAP = {
|
|
1172
|
+
// Stream Layer Events
|
|
1173
|
+
onMessageStart: "message_start",
|
|
1174
|
+
onMessageDelta: "message_delta",
|
|
1175
|
+
onMessageStop: "message_stop",
|
|
1176
|
+
onTextContentBlockStart: "text_content_block_start",
|
|
1177
|
+
onTextDelta: "text_delta",
|
|
1178
|
+
onTextContentBlockStop: "text_content_block_stop",
|
|
1179
|
+
onToolUseContentBlockStart: "tool_use_content_block_start",
|
|
1180
|
+
onInputJsonDelta: "input_json_delta",
|
|
1181
|
+
onToolUseContentBlockStop: "tool_use_content_block_stop",
|
|
1182
|
+
onToolCall: "tool_call",
|
|
1183
|
+
onToolResult: "tool_result",
|
|
1184
|
+
// Message Layer Events
|
|
1185
|
+
onUserMessage: "user_message",
|
|
1186
|
+
onAssistantMessage: "assistant_message",
|
|
1187
|
+
onToolCallMessage: "tool_call_message",
|
|
1188
|
+
onToolResultMessage: "tool_result_message",
|
|
1189
|
+
// Error Layer Events (independent, transportable via SSE)
|
|
1190
|
+
onError: "error",
|
|
1191
|
+
// Turn Layer Events
|
|
1192
|
+
onTurnRequest: "turn_request",
|
|
1193
|
+
onTurnResponse: "turn_response"
|
|
1194
|
+
};
|
|
1195
|
+
function mapReactHandlers(reactHandlers) {
|
|
1196
|
+
const eventHandlerMap = {};
|
|
1197
|
+
for (const [reactKey, eventKey] of Object.entries(REACT_TO_EVENT_MAP)) {
|
|
1198
|
+
const handler = reactHandlers[reactKey];
|
|
1199
|
+
if (handler) {
|
|
1200
|
+
eventHandlerMap[eventKey] = handler;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
return eventHandlerMap;
|
|
1204
|
+
}
|
|
1205
|
+
var logger42 = createLogger("core/AgentInstance");
|
|
1206
|
+
var AgentInstance = class {
|
|
1207
|
+
constructor(definition, context, engine, driver, sandbox) {
|
|
1208
|
+
__publicField(this, "agentId");
|
|
1209
|
+
__publicField(this, "definition");
|
|
1210
|
+
__publicField(this, "context");
|
|
1211
|
+
__publicField(this, "createdAt");
|
|
1212
|
+
__publicField(this, "sandbox");
|
|
1213
|
+
__publicField(this, "_lifecycle", "running");
|
|
1214
|
+
__publicField(this, "engine");
|
|
1215
|
+
/**
|
|
1216
|
+
* Driver instance - created from definition.driver class
|
|
1217
|
+
*/
|
|
1218
|
+
__publicField(this, "driver");
|
|
1219
|
+
/**
|
|
1220
|
+
* State machine - manages state transitions driven by StateEvents
|
|
1221
|
+
*/
|
|
1222
|
+
__publicField(this, "stateMachine", new AgentStateMachine());
|
|
1223
|
+
/**
|
|
1224
|
+
* Event bus - centralized event pub/sub
|
|
1225
|
+
*/
|
|
1226
|
+
__publicField(this, "eventBus", new AgentEventBus());
|
|
1227
|
+
/**
|
|
1228
|
+
* Error classifier - classifies and creates error events
|
|
1229
|
+
*/
|
|
1230
|
+
__publicField(this, "errorClassifier");
|
|
1231
|
+
/**
|
|
1232
|
+
* Middleware chain for receive() interception
|
|
1233
|
+
*/
|
|
1234
|
+
__publicField(this, "middlewareChain", new MiddlewareChain());
|
|
1235
|
+
/**
|
|
1236
|
+
* Interceptor chain for event dispatch interception
|
|
1237
|
+
*/
|
|
1238
|
+
__publicField(this, "interceptorChain");
|
|
1239
|
+
/**
|
|
1240
|
+
* Lifecycle handlers for onReady
|
|
1241
|
+
*/
|
|
1242
|
+
__publicField(this, "readyHandlers", /* @__PURE__ */ new Set());
|
|
1243
|
+
/**
|
|
1244
|
+
* Lifecycle handlers for onDestroy
|
|
1245
|
+
*/
|
|
1246
|
+
__publicField(this, "destroyHandlers", /* @__PURE__ */ new Set());
|
|
1247
|
+
this.agentId = context.agentId;
|
|
1248
|
+
this.definition = definition;
|
|
1249
|
+
this.context = context;
|
|
1250
|
+
this.engine = engine;
|
|
1251
|
+
this.createdAt = context.createdAt;
|
|
1252
|
+
this.sandbox = sandbox;
|
|
1253
|
+
this.driver = driver;
|
|
1254
|
+
this.errorClassifier = new AgentErrorClassifier(this.agentId);
|
|
1255
|
+
this.interceptorChain = new InterceptorChain(this.agentId);
|
|
1256
|
+
logger42.debug("AgentInstance created", {
|
|
1257
|
+
agentId: this.agentId,
|
|
1258
|
+
definitionName: definition.name,
|
|
1259
|
+
driverName: this.driver.name
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Current lifecycle state
|
|
1264
|
+
*/
|
|
1265
|
+
get lifecycle() {
|
|
1266
|
+
return this._lifecycle;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Current conversation state (delegated to StateMachine)
|
|
1270
|
+
*/
|
|
1271
|
+
get state() {
|
|
1272
|
+
return this.stateMachine.state;
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Receive a message from user
|
|
1276
|
+
*
|
|
1277
|
+
* Runs through middleware chain before actual processing.
|
|
1278
|
+
*
|
|
1279
|
+
* Error Handling:
|
|
1280
|
+
* - Errors are caught and converted to ErrorMessageEvent
|
|
1281
|
+
* - Handlers receive the error event before re-throwing
|
|
1282
|
+
* - This ensures UI can display errors
|
|
1283
|
+
*/
|
|
1284
|
+
async receive(message) {
|
|
1285
|
+
if (this._lifecycle === "destroyed") {
|
|
1286
|
+
logger42.warn("Receive called on destroyed agent", { agentId: this.agentId });
|
|
1287
|
+
const error = this.errorClassifier.create(
|
|
1288
|
+
"system",
|
|
1289
|
+
"AGENT_DESTROYED",
|
|
1290
|
+
"Agent has been destroyed",
|
|
1291
|
+
false
|
|
1292
|
+
);
|
|
1293
|
+
const errorEvent = this.errorClassifier.createEvent(error);
|
|
1294
|
+
this.notifyHandlers(errorEvent);
|
|
1295
|
+
throw new Error("[Agent] Agent has been destroyed");
|
|
1296
|
+
}
|
|
1297
|
+
if (this.state !== "idle") {
|
|
1298
|
+
logger42.warn("Receive called while agent is busy", {
|
|
1299
|
+
agentId: this.agentId,
|
|
1300
|
+
currentState: this.state
|
|
1301
|
+
});
|
|
1302
|
+
const error = this.errorClassifier.create(
|
|
1303
|
+
"system",
|
|
1304
|
+
"AGENT_BUSY",
|
|
1305
|
+
`Agent is busy (state: ${this.state}), please wait for current operation to complete`,
|
|
1306
|
+
false
|
|
1307
|
+
);
|
|
1308
|
+
const errorEvent = this.errorClassifier.createEvent(error);
|
|
1309
|
+
this.notifyHandlers(errorEvent);
|
|
1310
|
+
throw new Error(`[Agent] Agent is busy (state: ${this.state})`);
|
|
1311
|
+
}
|
|
1312
|
+
const userMessage = typeof message === "string" ? {
|
|
1313
|
+
id: `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
1314
|
+
role: "user",
|
|
1315
|
+
subtype: "user",
|
|
1316
|
+
content: message,
|
|
1317
|
+
timestamp: Date.now()
|
|
1318
|
+
} : message;
|
|
1319
|
+
logger42.debug("Receiving message", {
|
|
1320
|
+
agentId: this.agentId,
|
|
1321
|
+
messageId: userMessage.id
|
|
1322
|
+
});
|
|
1323
|
+
const userMessageEvent = {
|
|
1324
|
+
uuid: `evt_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
1325
|
+
type: "user_message",
|
|
1326
|
+
agentId: this.agentId,
|
|
1327
|
+
timestamp: Date.now(),
|
|
1328
|
+
data: userMessage
|
|
1329
|
+
};
|
|
1330
|
+
this.presentOutput(userMessageEvent);
|
|
1331
|
+
this.notifyHandlers(userMessageEvent);
|
|
1332
|
+
await this.executeMiddlewareChain(userMessage);
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Execute middleware chain and then process the message
|
|
1336
|
+
*/
|
|
1337
|
+
async executeMiddlewareChain(message) {
|
|
1338
|
+
await this.middlewareChain.execute(message, (msg) => this.doReceive(msg));
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Process a single stream event through the engine
|
|
1342
|
+
*
|
|
1343
|
+
* Used by:
|
|
1344
|
+
* - doReceive() - normal message flow
|
|
1345
|
+
* - AgentInterrupter - interrupt event injection
|
|
1346
|
+
*
|
|
1347
|
+
* @param streamEvent - Stream event to process
|
|
1348
|
+
*/
|
|
1349
|
+
processStreamEvent(streamEvent) {
|
|
1350
|
+
const outputs = this.engine.process(this.agentId, streamEvent);
|
|
1351
|
+
for (const output of outputs) {
|
|
1352
|
+
this.presentOutput(output);
|
|
1353
|
+
}
|
|
1354
|
+
for (const output of outputs) {
|
|
1355
|
+
this.notifyHandlers(output);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Actual message processing logic
|
|
1360
|
+
*
|
|
1361
|
+
* Coordinates the flow:
|
|
1362
|
+
* 1. Driver receives message → produces StreamEvents
|
|
1363
|
+
* 2. Engine processes events → produces outputs
|
|
1364
|
+
* 3. Presenters handle outputs
|
|
1365
|
+
* 4. Handlers receive outputs
|
|
1366
|
+
*/
|
|
1367
|
+
async doReceive(userMessage) {
|
|
1368
|
+
try {
|
|
1369
|
+
logger42.debug("Processing message through driver", {
|
|
1370
|
+
agentId: this.agentId,
|
|
1371
|
+
messageId: userMessage.id
|
|
1372
|
+
});
|
|
1373
|
+
const queuedEvent = {
|
|
1374
|
+
type: "conversation_queued",
|
|
1375
|
+
uuid: `${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
|
|
1376
|
+
agentId: this.agentId,
|
|
1377
|
+
timestamp: Date.now(),
|
|
1378
|
+
data: {
|
|
1379
|
+
userMessage
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
this.notifyHandlers(queuedEvent);
|
|
1383
|
+
const streamEvents = this.driver.receive(userMessage);
|
|
1384
|
+
for await (const streamEvent of streamEvents) {
|
|
1385
|
+
this.processStreamEvent(streamEvent);
|
|
1386
|
+
}
|
|
1387
|
+
logger42.debug("Message processing completed", {
|
|
1388
|
+
agentId: this.agentId,
|
|
1389
|
+
messageId: userMessage.id
|
|
1390
|
+
});
|
|
1391
|
+
} catch (error) {
|
|
1392
|
+
const agentError = this.errorClassifier.classify(error);
|
|
1393
|
+
const errorEvent = this.errorClassifier.createEvent(agentError);
|
|
1394
|
+
logger42.error("Message processing failed", {
|
|
1395
|
+
agentId: this.agentId,
|
|
1396
|
+
messageId: userMessage.id,
|
|
1397
|
+
errorCategory: agentError.category,
|
|
1398
|
+
errorCode: agentError.code,
|
|
1399
|
+
error
|
|
1400
|
+
});
|
|
1401
|
+
this.notifyHandlers(errorEvent);
|
|
1402
|
+
throw error;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Send output to all presenters
|
|
1407
|
+
*
|
|
1408
|
+
* Note: Presenters are no longer part of AgentDefinition.
|
|
1409
|
+
* This is a placeholder for future presenter injection via Runtime or middleware.
|
|
1410
|
+
*/
|
|
1411
|
+
presentOutput(_output) {
|
|
1412
|
+
}
|
|
1413
|
+
on(typeOrHandlerOrMap, handler) {
|
|
1414
|
+
if (typeof typeOrHandlerOrMap === "function") {
|
|
1415
|
+
return this.eventBus.onAny(typeOrHandlerOrMap);
|
|
1416
|
+
}
|
|
1417
|
+
if (this.isEventHandlerMap(typeOrHandlerOrMap)) {
|
|
1418
|
+
const unsubscribes = [];
|
|
1419
|
+
for (const [eventType, eventHandler] of Object.entries(typeOrHandlerOrMap)) {
|
|
1420
|
+
if (eventHandler) {
|
|
1421
|
+
unsubscribes.push(this.eventBus.on(eventType, eventHandler));
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
return () => {
|
|
1425
|
+
for (const unsub of unsubscribes) {
|
|
1426
|
+
unsub();
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
const types = Array.isArray(typeOrHandlerOrMap) ? typeOrHandlerOrMap : [typeOrHandlerOrMap];
|
|
1431
|
+
const h = handler;
|
|
1432
|
+
return this.eventBus.on(types, h);
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Check if the argument is an EventHandlerMap (object with event type keys)
|
|
1436
|
+
*/
|
|
1437
|
+
isEventHandlerMap(arg) {
|
|
1438
|
+
if (typeof arg !== "object" || arg === null || Array.isArray(arg)) {
|
|
1439
|
+
return false;
|
|
1440
|
+
}
|
|
1441
|
+
const keys = Object.keys(arg);
|
|
1442
|
+
if (keys.length === 0) {
|
|
1443
|
+
return false;
|
|
1444
|
+
}
|
|
1445
|
+
return keys.every((key) => {
|
|
1446
|
+
const value = arg[key];
|
|
1447
|
+
return value === void 0 || typeof value === "function";
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Subscribe to state changes (delegated to StateMachine)
|
|
1452
|
+
*
|
|
1453
|
+
* @param handler - Callback receiving { prev, current } state change
|
|
1454
|
+
* @returns Unsubscribe function
|
|
1455
|
+
*/
|
|
1456
|
+
onStateChange(handler) {
|
|
1457
|
+
return this.stateMachine.onStateChange(handler);
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* React-style fluent event subscription
|
|
1461
|
+
*
|
|
1462
|
+
* Converts onXxx handlers to event type keys and delegates to on(handlers)
|
|
1463
|
+
*/
|
|
1464
|
+
react(handlers) {
|
|
1465
|
+
const eventHandlerMap = mapReactHandlers(handlers);
|
|
1466
|
+
return this.on(eventHandlerMap);
|
|
1467
|
+
}
|
|
1468
|
+
/**
|
|
1469
|
+
* Subscribe to agent ready event
|
|
1470
|
+
*
|
|
1471
|
+
* If already running, handler is called immediately.
|
|
1472
|
+
*/
|
|
1473
|
+
onReady(handler) {
|
|
1474
|
+
if (this._lifecycle === "running") {
|
|
1475
|
+
try {
|
|
1476
|
+
handler();
|
|
1477
|
+
} catch (error) {
|
|
1478
|
+
logger42.error("onReady handler error", {
|
|
1479
|
+
agentId: this.agentId,
|
|
1480
|
+
error
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
this.readyHandlers.add(handler);
|
|
1485
|
+
return () => {
|
|
1486
|
+
this.readyHandlers.delete(handler);
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Subscribe to agent destroy event
|
|
1491
|
+
*/
|
|
1492
|
+
onDestroy(handler) {
|
|
1493
|
+
this.destroyHandlers.add(handler);
|
|
1494
|
+
return () => {
|
|
1495
|
+
this.destroyHandlers.delete(handler);
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Add middleware to intercept incoming messages
|
|
1500
|
+
*/
|
|
1501
|
+
use(middleware) {
|
|
1502
|
+
return this.middlewareChain.use(middleware);
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Add interceptor to intercept outgoing events
|
|
1506
|
+
*/
|
|
1507
|
+
intercept(interceptor) {
|
|
1508
|
+
return this.interceptorChain.intercept(interceptor);
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Interrupt - User-initiated stop
|
|
1512
|
+
*
|
|
1513
|
+
* Stops the current operation gracefully.
|
|
1514
|
+
* Flow:
|
|
1515
|
+
* 1. Call driver.interrupt() to abort active requests
|
|
1516
|
+
* 2. Driver yields InterruptedStreamEvent
|
|
1517
|
+
* 3. Event flows through engine pipeline
|
|
1518
|
+
* 4. StateEventProcessor generates conversation_interrupted
|
|
1519
|
+
* 5. StateMachine transitions to idle state
|
|
1520
|
+
* 6. UI receives state change notification
|
|
1521
|
+
*/
|
|
1522
|
+
interrupt() {
|
|
1523
|
+
logger42.debug("User interrupt requested", { agentId: this.agentId, currentState: this.state });
|
|
1524
|
+
this.driver.interrupt();
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Destroy - Clean up resources
|
|
1528
|
+
*/
|
|
1529
|
+
async destroy() {
|
|
1530
|
+
logger42.debug("Destroying agent", { agentId: this.agentId });
|
|
1531
|
+
for (const handler of this.destroyHandlers) {
|
|
1532
|
+
try {
|
|
1533
|
+
handler();
|
|
1534
|
+
} catch (error) {
|
|
1535
|
+
logger42.error("onDestroy handler error", {
|
|
1536
|
+
agentId: this.agentId,
|
|
1537
|
+
error
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
this._lifecycle = "destroyed";
|
|
1542
|
+
this.stateMachine.reset();
|
|
1543
|
+
this.eventBus.destroy();
|
|
1544
|
+
this.readyHandlers.clear();
|
|
1545
|
+
this.destroyHandlers.clear();
|
|
1546
|
+
this.middlewareChain.clear();
|
|
1547
|
+
this.interceptorChain.clear();
|
|
1548
|
+
this.engine.clearState(this.agentId);
|
|
1549
|
+
logger42.info("Agent destroyed", { agentId: this.agentId });
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Notify all registered handlers
|
|
1553
|
+
*
|
|
1554
|
+
* Flow:
|
|
1555
|
+
* 1. StateMachine processes StateEvents (for state transitions)
|
|
1556
|
+
* 2. Interceptor chain can modify/filter events
|
|
1557
|
+
* 3. EventBus emits to all subscribers
|
|
1558
|
+
*/
|
|
1559
|
+
notifyHandlers(event) {
|
|
1560
|
+
if (types.isStateEvent(event)) {
|
|
1561
|
+
this.stateMachine.process(event);
|
|
1562
|
+
}
|
|
1563
|
+
this.executeInterceptorChain(event);
|
|
1564
|
+
}
|
|
1565
|
+
/**
|
|
1566
|
+
* Execute interceptor chain and then emit to EventBus
|
|
1567
|
+
*/
|
|
1568
|
+
executeInterceptorChain(event) {
|
|
1569
|
+
this.interceptorChain.execute(event, (e) => this.eventBus.emit(e));
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Get the event consumer for external subscriptions
|
|
1573
|
+
*
|
|
1574
|
+
* Use this to expose event subscription without emit capability.
|
|
1575
|
+
*/
|
|
1576
|
+
getEventConsumer() {
|
|
1577
|
+
return this.eventBus.asConsumer();
|
|
384
1578
|
}
|
|
385
1579
|
};
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
__publicField(this, "
|
|
391
|
-
this.repository = repository;
|
|
392
|
-
this.containerManager = containerManager;
|
|
393
|
-
this.defaultContainerId = defaultContainerId;
|
|
1580
|
+
|
|
1581
|
+
// ../engine/dist/index.js
|
|
1582
|
+
var MemoryStore = class {
|
|
1583
|
+
constructor() {
|
|
1584
|
+
__publicField(this, "states", /* @__PURE__ */ new Map());
|
|
394
1585
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
const now = /* @__PURE__ */ new Date();
|
|
398
|
-
const record = {
|
|
399
|
-
sessionId,
|
|
400
|
-
userId,
|
|
401
|
-
imageId,
|
|
402
|
-
title: null,
|
|
403
|
-
createdAt: now,
|
|
404
|
-
updatedAt: now
|
|
405
|
-
};
|
|
406
|
-
await this.repository.saveSession(record);
|
|
407
|
-
logger4.info("Session created", { sessionId, imageId, userId });
|
|
408
|
-
return new SessionImpl(record, this.repository, this.containerManager, this.defaultContainerId);
|
|
1586
|
+
get(id) {
|
|
1587
|
+
return this.states.get(id);
|
|
409
1588
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
if (!record) return void 0;
|
|
413
|
-
return new SessionImpl(record, this.repository, this.containerManager, this.defaultContainerId);
|
|
1589
|
+
set(id, state) {
|
|
1590
|
+
this.states.set(id, state);
|
|
414
1591
|
}
|
|
415
|
-
|
|
416
|
-
|
|
1592
|
+
delete(id) {
|
|
1593
|
+
this.states.delete(id);
|
|
417
1594
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
return records.map(
|
|
421
|
-
(r) => new SessionImpl(r, this.repository, this.containerManager, this.defaultContainerId)
|
|
422
|
-
);
|
|
1595
|
+
has(id) {
|
|
1596
|
+
return this.states.has(id);
|
|
423
1597
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
);
|
|
1598
|
+
/**
|
|
1599
|
+
* Clear all stored states
|
|
1600
|
+
*/
|
|
1601
|
+
clear() {
|
|
1602
|
+
this.states.clear();
|
|
429
1603
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
1604
|
+
/**
|
|
1605
|
+
* Get the number of stored states
|
|
1606
|
+
*/
|
|
1607
|
+
get size() {
|
|
1608
|
+
return this.states.size;
|
|
435
1609
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
1610
|
+
/**
|
|
1611
|
+
* Get all stored IDs
|
|
1612
|
+
*/
|
|
1613
|
+
keys() {
|
|
1614
|
+
return this.states.keys();
|
|
439
1615
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
1616
|
+
};
|
|
1617
|
+
createLogger("engine/Mealy");
|
|
1618
|
+
function combineProcessors(processors) {
|
|
1619
|
+
return (state, event) => {
|
|
1620
|
+
const newState = {};
|
|
1621
|
+
const allOutputs = [];
|
|
1622
|
+
for (const key in processors) {
|
|
1623
|
+
const processor = processors[key];
|
|
1624
|
+
const subState = state[key];
|
|
1625
|
+
const [newSubState, outputs] = processor(subState, event);
|
|
1626
|
+
newState[key] = newSubState;
|
|
1627
|
+
allOutputs.push(...outputs);
|
|
1628
|
+
}
|
|
1629
|
+
return [newState, allOutputs];
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
function combineInitialStates(initialStates) {
|
|
1633
|
+
return () => {
|
|
1634
|
+
const state = {};
|
|
1635
|
+
for (const key in initialStates) {
|
|
1636
|
+
state[key] = initialStates[key]();
|
|
1637
|
+
}
|
|
1638
|
+
return state;
|
|
1639
|
+
};
|
|
1640
|
+
}
|
|
1641
|
+
function createInitialMessageAssemblerState() {
|
|
1642
|
+
return {
|
|
1643
|
+
currentMessageId: null,
|
|
1644
|
+
messageStartTime: null,
|
|
1645
|
+
pendingContents: {},
|
|
1646
|
+
pendingToolCalls: {}
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
function generateId() {
|
|
1650
|
+
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
1651
|
+
}
|
|
1652
|
+
var messageAssemblerProcessor = (state, input) => {
|
|
1653
|
+
switch (input.type) {
|
|
1654
|
+
case "message_start":
|
|
1655
|
+
return handleMessageStart(state, input);
|
|
1656
|
+
case "text_delta":
|
|
1657
|
+
return handleTextDelta(state, input);
|
|
1658
|
+
case "tool_use_content_block_start":
|
|
1659
|
+
return handleToolUseContentBlockStart(state, input);
|
|
1660
|
+
case "input_json_delta":
|
|
1661
|
+
return handleInputJsonDelta(state, input);
|
|
1662
|
+
case "tool_use_content_block_stop":
|
|
1663
|
+
return handleToolUseContentBlockStop(state, input);
|
|
1664
|
+
case "tool_result":
|
|
1665
|
+
return handleToolResult(state, input);
|
|
1666
|
+
case "message_stop":
|
|
1667
|
+
return handleMessageStop(state, input);
|
|
1668
|
+
default:
|
|
1669
|
+
return [state, []];
|
|
443
1670
|
}
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
1671
|
+
};
|
|
1672
|
+
function handleMessageStart(state, event) {
|
|
1673
|
+
return [
|
|
1674
|
+
{
|
|
1675
|
+
...state,
|
|
1676
|
+
currentMessageId: generateId(),
|
|
1677
|
+
messageStartTime: event.timestamp,
|
|
1678
|
+
pendingContents: {}
|
|
1679
|
+
},
|
|
1680
|
+
[]
|
|
1681
|
+
];
|
|
1682
|
+
}
|
|
1683
|
+
function handleTextDelta(state, event) {
|
|
1684
|
+
const index = 0;
|
|
1685
|
+
const existingContent = state.pendingContents[index];
|
|
1686
|
+
const pendingContent = existingContent?.type === "text" ? {
|
|
1687
|
+
...existingContent,
|
|
1688
|
+
textDeltas: [...existingContent.textDeltas || [], event.data.text]
|
|
1689
|
+
} : {
|
|
1690
|
+
type: "text",
|
|
1691
|
+
index,
|
|
1692
|
+
textDeltas: [event.data.text]
|
|
1693
|
+
};
|
|
1694
|
+
return [
|
|
1695
|
+
{
|
|
1696
|
+
...state,
|
|
1697
|
+
pendingContents: {
|
|
1698
|
+
...state.pendingContents,
|
|
1699
|
+
[index]: pendingContent
|
|
1700
|
+
}
|
|
1701
|
+
},
|
|
1702
|
+
[]
|
|
1703
|
+
];
|
|
1704
|
+
}
|
|
1705
|
+
function handleToolUseContentBlockStart(state, event) {
|
|
1706
|
+
const index = 1;
|
|
1707
|
+
const pendingContent = {
|
|
1708
|
+
type: "tool_use",
|
|
1709
|
+
index,
|
|
1710
|
+
toolId: event.data.id,
|
|
1711
|
+
toolName: event.data.name,
|
|
1712
|
+
toolInputJson: ""
|
|
1713
|
+
};
|
|
1714
|
+
return [
|
|
1715
|
+
{
|
|
1716
|
+
...state,
|
|
1717
|
+
pendingContents: {
|
|
1718
|
+
...state.pendingContents,
|
|
1719
|
+
[index]: pendingContent
|
|
1720
|
+
}
|
|
1721
|
+
},
|
|
1722
|
+
[]
|
|
1723
|
+
];
|
|
1724
|
+
}
|
|
1725
|
+
function handleInputJsonDelta(state, event) {
|
|
1726
|
+
const index = 1;
|
|
1727
|
+
const existingContent = state.pendingContents[index];
|
|
1728
|
+
if (!existingContent || existingContent.type !== "tool_use") {
|
|
1729
|
+
return [state, []];
|
|
1730
|
+
}
|
|
1731
|
+
const pendingContent = {
|
|
1732
|
+
...existingContent,
|
|
1733
|
+
toolInputJson: (existingContent.toolInputJson || "") + event.data.partialJson
|
|
1734
|
+
};
|
|
1735
|
+
return [
|
|
1736
|
+
{
|
|
1737
|
+
...state,
|
|
1738
|
+
pendingContents: {
|
|
1739
|
+
...state.pendingContents,
|
|
1740
|
+
[index]: pendingContent
|
|
1741
|
+
}
|
|
1742
|
+
},
|
|
1743
|
+
[]
|
|
1744
|
+
];
|
|
1745
|
+
}
|
|
1746
|
+
function handleToolUseContentBlockStop(state, event) {
|
|
1747
|
+
const index = 1;
|
|
1748
|
+
const pendingContent = state.pendingContents[index];
|
|
1749
|
+
if (!pendingContent || pendingContent.type !== "tool_use") {
|
|
1750
|
+
return [state, []];
|
|
1751
|
+
}
|
|
1752
|
+
let toolInput = {};
|
|
1753
|
+
try {
|
|
1754
|
+
toolInput = pendingContent.toolInputJson ? JSON.parse(pendingContent.toolInputJson) : {};
|
|
1755
|
+
} catch {
|
|
1756
|
+
toolInput = {};
|
|
1757
|
+
}
|
|
1758
|
+
const outputs = [];
|
|
1759
|
+
const toolId = pendingContent.toolId;
|
|
1760
|
+
const toolName = pendingContent.toolName;
|
|
1761
|
+
const toolCallEvent = {
|
|
1762
|
+
type: "tool_call",
|
|
1763
|
+
uuid: generateId(),
|
|
1764
|
+
agentId: event.agentId,
|
|
1765
|
+
timestamp: Date.now(),
|
|
1766
|
+
data: {
|
|
1767
|
+
id: toolId,
|
|
1768
|
+
name: toolName,
|
|
1769
|
+
input: toolInput
|
|
448
1770
|
}
|
|
449
|
-
|
|
1771
|
+
};
|
|
1772
|
+
outputs.push(toolCallEvent);
|
|
1773
|
+
const toolCall = {
|
|
1774
|
+
type: "tool-call",
|
|
1775
|
+
id: toolId,
|
|
1776
|
+
name: toolName,
|
|
1777
|
+
input: toolInput
|
|
1778
|
+
};
|
|
1779
|
+
const toolCallMessage = {
|
|
1780
|
+
id: generateId(),
|
|
1781
|
+
role: "assistant",
|
|
1782
|
+
subtype: "tool-call",
|
|
1783
|
+
toolCall,
|
|
1784
|
+
timestamp: Date.now()
|
|
1785
|
+
};
|
|
1786
|
+
const toolCallMessageEvent = {
|
|
1787
|
+
type: "tool_call_message",
|
|
1788
|
+
uuid: generateId(),
|
|
1789
|
+
agentId: event.agentId,
|
|
1790
|
+
timestamp: Date.now(),
|
|
1791
|
+
data: toolCallMessage
|
|
1792
|
+
};
|
|
1793
|
+
outputs.push(toolCallMessageEvent);
|
|
1794
|
+
const { [index]: _, ...remainingContents } = state.pendingContents;
|
|
1795
|
+
return [
|
|
1796
|
+
{
|
|
1797
|
+
...state,
|
|
1798
|
+
pendingContents: remainingContents,
|
|
1799
|
+
pendingToolCalls: {
|
|
1800
|
+
...state.pendingToolCalls,
|
|
1801
|
+
[toolId]: { id: toolId, name: toolName }
|
|
1802
|
+
}
|
|
1803
|
+
},
|
|
1804
|
+
outputs
|
|
1805
|
+
];
|
|
1806
|
+
}
|
|
1807
|
+
function handleToolResult(state, event) {
|
|
1808
|
+
const { toolId, content, isError } = event.data;
|
|
1809
|
+
const pendingToolCall = state.pendingToolCalls[toolId];
|
|
1810
|
+
const toolName = pendingToolCall?.name || "unknown";
|
|
1811
|
+
const toolResult = {
|
|
1812
|
+
type: "tool-result",
|
|
1813
|
+
id: toolId,
|
|
1814
|
+
name: toolName,
|
|
1815
|
+
output: {
|
|
1816
|
+
type: isError ? "error-text" : "text",
|
|
1817
|
+
value: typeof content === "string" ? content : JSON.stringify(content)
|
|
1818
|
+
}
|
|
1819
|
+
};
|
|
1820
|
+
const toolResultMessage = {
|
|
1821
|
+
id: generateId(),
|
|
1822
|
+
role: "tool",
|
|
1823
|
+
subtype: "tool-result",
|
|
1824
|
+
toolResult,
|
|
1825
|
+
toolCallId: toolId,
|
|
1826
|
+
timestamp: Date.now()
|
|
1827
|
+
};
|
|
1828
|
+
const toolResultMessageEvent = {
|
|
1829
|
+
type: "tool_result_message",
|
|
1830
|
+
uuid: generateId(),
|
|
1831
|
+
agentId: event.agentId,
|
|
1832
|
+
timestamp: Date.now(),
|
|
1833
|
+
data: toolResultMessage
|
|
1834
|
+
};
|
|
1835
|
+
const { [toolId]: _, ...remainingToolCalls } = state.pendingToolCalls;
|
|
1836
|
+
return [
|
|
1837
|
+
{
|
|
1838
|
+
...state,
|
|
1839
|
+
pendingToolCalls: remainingToolCalls
|
|
1840
|
+
},
|
|
1841
|
+
[toolResultMessageEvent]
|
|
1842
|
+
];
|
|
1843
|
+
}
|
|
1844
|
+
function handleMessageStop(state, event) {
|
|
1845
|
+
if (!state.currentMessageId) {
|
|
1846
|
+
return [state, []];
|
|
1847
|
+
}
|
|
1848
|
+
const textParts = [];
|
|
1849
|
+
const sortedContents = Object.values(state.pendingContents).sort((a, b) => a.index - b.index);
|
|
1850
|
+
for (const pending of sortedContents) {
|
|
1851
|
+
if (pending.type === "text" && pending.textDeltas) {
|
|
1852
|
+
textParts.push(pending.textDeltas.join(""));
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
const content = textParts.join("");
|
|
1856
|
+
const stopReason = event.data.stopReason;
|
|
1857
|
+
if (!content || content.trim().length === 0) {
|
|
1858
|
+
const shouldPreserveToolCalls2 = stopReason === "tool_use";
|
|
1859
|
+
return [
|
|
1860
|
+
{
|
|
1861
|
+
...createInitialMessageAssemblerState(),
|
|
1862
|
+
pendingToolCalls: shouldPreserveToolCalls2 ? state.pendingToolCalls : {}
|
|
1863
|
+
},
|
|
1864
|
+
[]
|
|
1865
|
+
];
|
|
1866
|
+
}
|
|
1867
|
+
const assistantMessage = {
|
|
1868
|
+
id: state.currentMessageId,
|
|
1869
|
+
role: "assistant",
|
|
1870
|
+
subtype: "assistant",
|
|
1871
|
+
content,
|
|
1872
|
+
timestamp: state.messageStartTime || Date.now(),
|
|
1873
|
+
// Usage data is not available in message_stop event
|
|
1874
|
+
// It would need to be tracked separately if needed
|
|
1875
|
+
usage: void 0
|
|
1876
|
+
};
|
|
1877
|
+
const assistantEvent = {
|
|
1878
|
+
type: "assistant_message",
|
|
1879
|
+
uuid: generateId(),
|
|
1880
|
+
agentId: event.agentId,
|
|
1881
|
+
timestamp: Date.now(),
|
|
1882
|
+
data: assistantMessage
|
|
1883
|
+
};
|
|
1884
|
+
const shouldPreserveToolCalls = stopReason === "tool_use";
|
|
1885
|
+
return [
|
|
1886
|
+
{
|
|
1887
|
+
...createInitialMessageAssemblerState(),
|
|
1888
|
+
pendingToolCalls: shouldPreserveToolCalls ? state.pendingToolCalls : {}
|
|
1889
|
+
},
|
|
1890
|
+
[assistantEvent]
|
|
1891
|
+
];
|
|
1892
|
+
}
|
|
1893
|
+
var logger23 = createLogger("engine/stateEventProcessor");
|
|
1894
|
+
function createInitialStateEventProcessorContext() {
|
|
1895
|
+
return {};
|
|
1896
|
+
}
|
|
1897
|
+
function generateId2() {
|
|
1898
|
+
return `state_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
1899
|
+
}
|
|
1900
|
+
var stateEventProcessor = (context, input) => {
|
|
1901
|
+
logger23.debug(`[Stream Event] ${input.type}`, {
|
|
1902
|
+
context,
|
|
1903
|
+
eventData: "data" in input ? input.data : void 0
|
|
1904
|
+
});
|
|
1905
|
+
switch (input.type) {
|
|
1906
|
+
case "message_start":
|
|
1907
|
+
return handleMessageStart2(context, input);
|
|
1908
|
+
case "message_delta":
|
|
1909
|
+
return handleMessageDelta(context);
|
|
1910
|
+
case "message_stop":
|
|
1911
|
+
return handleMessageStop2(context, input);
|
|
1912
|
+
case "text_content_block_start":
|
|
1913
|
+
return handleTextContentBlockStart(context, input);
|
|
1914
|
+
case "tool_use_content_block_start":
|
|
1915
|
+
return handleToolUseContentBlockStart2(context, input);
|
|
1916
|
+
case "tool_use_content_block_stop":
|
|
1917
|
+
return handleToolUseContentBlockStop2(context);
|
|
1918
|
+
case "tool_call":
|
|
1919
|
+
return handleToolCall(context);
|
|
1920
|
+
case "interrupted":
|
|
1921
|
+
return handleInterrupted(context, input);
|
|
1922
|
+
default:
|
|
1923
|
+
logger23.debug(`[Stream Event] ${input.type} (unhandled)`);
|
|
1924
|
+
return [context, []];
|
|
450
1925
|
}
|
|
451
1926
|
};
|
|
452
|
-
|
|
453
|
-
|
|
1927
|
+
function handleMessageStart2(context, event) {
|
|
1928
|
+
const conversationStartEvent = {
|
|
1929
|
+
type: "conversation_start",
|
|
1930
|
+
uuid: generateId2(),
|
|
1931
|
+
agentId: event.agentId,
|
|
1932
|
+
timestamp: event.timestamp,
|
|
1933
|
+
transition: {
|
|
1934
|
+
reason: "conversation_started",
|
|
1935
|
+
trigger: "message_start"
|
|
1936
|
+
},
|
|
1937
|
+
data: {
|
|
1938
|
+
userMessage: {}
|
|
1939
|
+
// Will be populated by higher-level component
|
|
1940
|
+
}
|
|
1941
|
+
};
|
|
1942
|
+
return [context, [conversationStartEvent]];
|
|
1943
|
+
}
|
|
1944
|
+
function handleMessageDelta(context, _event) {
|
|
1945
|
+
return [context, []];
|
|
1946
|
+
}
|
|
1947
|
+
function handleMessageStop2(context, event) {
|
|
1948
|
+
const stopReason = event.data.stopReason;
|
|
1949
|
+
logger23.debug("message_stop received", { stopReason });
|
|
1950
|
+
if (stopReason === "tool_use") {
|
|
1951
|
+
logger23.debug("Skipping conversation_end (tool_use in progress)");
|
|
1952
|
+
return [context, []];
|
|
1953
|
+
}
|
|
1954
|
+
const conversationEndEvent = {
|
|
1955
|
+
type: "conversation_end",
|
|
1956
|
+
uuid: generateId2(),
|
|
1957
|
+
agentId: event.agentId,
|
|
1958
|
+
timestamp: event.timestamp,
|
|
1959
|
+
transition: {
|
|
1960
|
+
reason: "conversation_completed",
|
|
1961
|
+
trigger: "message_stop"
|
|
1962
|
+
},
|
|
1963
|
+
data: {
|
|
1964
|
+
assistantMessage: {},
|
|
1965
|
+
// Will be populated by higher-level component
|
|
1966
|
+
durationMs: 0,
|
|
1967
|
+
// Will be calculated by StateMachine or TurnTracker
|
|
1968
|
+
durationApiMs: 0,
|
|
1969
|
+
numTurns: 0,
|
|
1970
|
+
result: "completed",
|
|
1971
|
+
totalCostUsd: 0,
|
|
1972
|
+
usage: {
|
|
1973
|
+
input: 0,
|
|
1974
|
+
output: 0
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
};
|
|
1978
|
+
return [context, [conversationEndEvent]];
|
|
1979
|
+
}
|
|
1980
|
+
function handleTextContentBlockStart(context, event) {
|
|
1981
|
+
const respondingEvent = {
|
|
1982
|
+
type: "conversation_responding",
|
|
1983
|
+
uuid: generateId2(),
|
|
1984
|
+
agentId: event.agentId,
|
|
1985
|
+
timestamp: Date.now(),
|
|
1986
|
+
transition: {
|
|
1987
|
+
reason: "assistant_responding",
|
|
1988
|
+
trigger: "text_content_block_start"
|
|
1989
|
+
},
|
|
1990
|
+
data: {}
|
|
1991
|
+
};
|
|
1992
|
+
return [context, [respondingEvent]];
|
|
1993
|
+
}
|
|
1994
|
+
function handleToolUseContentBlockStart2(context, event) {
|
|
1995
|
+
const outputs = [];
|
|
1996
|
+
const toolPlannedEvent = {
|
|
1997
|
+
type: "tool_planned",
|
|
1998
|
+
uuid: generateId2(),
|
|
1999
|
+
agentId: event.agentId,
|
|
2000
|
+
timestamp: event.timestamp,
|
|
2001
|
+
data: {
|
|
2002
|
+
id: event.data.id,
|
|
2003
|
+
name: event.data.name,
|
|
2004
|
+
input: {}
|
|
2005
|
+
}
|
|
2006
|
+
};
|
|
2007
|
+
outputs.push(toolPlannedEvent);
|
|
2008
|
+
const toolExecutingEvent = {
|
|
2009
|
+
type: "tool_executing",
|
|
2010
|
+
uuid: generateId2(),
|
|
2011
|
+
agentId: event.agentId,
|
|
2012
|
+
timestamp: event.timestamp,
|
|
2013
|
+
transition: {
|
|
2014
|
+
reason: "tool_planning_started",
|
|
2015
|
+
trigger: "tool_use_content_block_start"
|
|
2016
|
+
},
|
|
2017
|
+
data: {}
|
|
2018
|
+
};
|
|
2019
|
+
outputs.push(toolExecutingEvent);
|
|
2020
|
+
return [context, outputs];
|
|
2021
|
+
}
|
|
2022
|
+
function handleToolUseContentBlockStop2(context, _event) {
|
|
2023
|
+
return [context, []];
|
|
2024
|
+
}
|
|
2025
|
+
function handleToolCall(context, _event) {
|
|
2026
|
+
return [context, []];
|
|
2027
|
+
}
|
|
2028
|
+
function handleInterrupted(context, event) {
|
|
2029
|
+
logger23.debug("interrupted event received", { reason: event.data.reason });
|
|
2030
|
+
const conversationInterruptedEvent = {
|
|
2031
|
+
type: "conversation_interrupted",
|
|
2032
|
+
uuid: generateId2(),
|
|
2033
|
+
agentId: event.agentId,
|
|
2034
|
+
timestamp: event.timestamp,
|
|
2035
|
+
transition: {
|
|
2036
|
+
reason: event.data.reason,
|
|
2037
|
+
trigger: "interrupted"
|
|
2038
|
+
},
|
|
2039
|
+
data: {
|
|
2040
|
+
reason: event.data.reason
|
|
2041
|
+
}
|
|
2042
|
+
};
|
|
2043
|
+
return [context, [conversationInterruptedEvent]];
|
|
2044
|
+
}
|
|
2045
|
+
function createInitialTurnTrackerState() {
|
|
2046
|
+
return {
|
|
2047
|
+
pendingTurn: null,
|
|
2048
|
+
costPerInputToken: 3e-6,
|
|
2049
|
+
// $3 per 1M tokens
|
|
2050
|
+
costPerOutputToken: 15e-6
|
|
2051
|
+
// $15 per 1M tokens
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2054
|
+
function generateId3() {
|
|
2055
|
+
return `turn_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
2056
|
+
}
|
|
2057
|
+
function calculateCost(usage, costPerInputToken, costPerOutputToken) {
|
|
2058
|
+
const inputCost = usage.input * costPerInputToken;
|
|
2059
|
+
const outputCost = usage.output * costPerOutputToken;
|
|
2060
|
+
return inputCost + outputCost;
|
|
2061
|
+
}
|
|
2062
|
+
var turnTrackerProcessor = (state, input) => {
|
|
2063
|
+
switch (input.type) {
|
|
2064
|
+
case "user_message":
|
|
2065
|
+
return handleUserMessage(state, input);
|
|
2066
|
+
case "message_stop":
|
|
2067
|
+
return handleMessageStop3(state, input);
|
|
2068
|
+
case "assistant_message":
|
|
2069
|
+
return [state, []];
|
|
2070
|
+
default:
|
|
2071
|
+
return [state, []];
|
|
2072
|
+
}
|
|
2073
|
+
};
|
|
2074
|
+
function handleUserMessage(state, event) {
|
|
2075
|
+
const turnId = generateId3();
|
|
2076
|
+
const pendingTurn = {
|
|
2077
|
+
turnId,
|
|
2078
|
+
userMessage: event.data,
|
|
2079
|
+
requestedAt: event.timestamp
|
|
2080
|
+
};
|
|
2081
|
+
const turnRequestEvent = {
|
|
2082
|
+
type: "turn_request",
|
|
2083
|
+
uuid: generateId3(),
|
|
2084
|
+
agentId: event.agentId,
|
|
2085
|
+
timestamp: Date.now(),
|
|
2086
|
+
turnId,
|
|
2087
|
+
data: {
|
|
2088
|
+
userMessage: event.data,
|
|
2089
|
+
requestedAt: event.timestamp
|
|
2090
|
+
}
|
|
2091
|
+
};
|
|
2092
|
+
return [
|
|
2093
|
+
{
|
|
2094
|
+
...state,
|
|
2095
|
+
pendingTurn
|
|
2096
|
+
},
|
|
2097
|
+
[turnRequestEvent]
|
|
2098
|
+
];
|
|
2099
|
+
}
|
|
2100
|
+
function handleMessageStop3(state, event) {
|
|
2101
|
+
if (!state.pendingTurn) {
|
|
2102
|
+
return [state, []];
|
|
2103
|
+
}
|
|
2104
|
+
const stopReason = event.data.stopReason;
|
|
2105
|
+
if (stopReason === "end_turn" || stopReason === "max_tokens" || stopReason === "stop_sequence") {
|
|
2106
|
+
return completeTurn(state, event.agentId, event.timestamp);
|
|
2107
|
+
}
|
|
2108
|
+
return [state, []];
|
|
2109
|
+
}
|
|
2110
|
+
function completeTurn(state, agentId, completedAt) {
|
|
2111
|
+
if (!state.pendingTurn) {
|
|
2112
|
+
return [state, []];
|
|
2113
|
+
}
|
|
2114
|
+
const { turnId, requestedAt } = state.pendingTurn;
|
|
2115
|
+
const duration = completedAt - requestedAt;
|
|
2116
|
+
const usage = { input: 0, output: 0 };
|
|
2117
|
+
const cost = calculateCost(usage, state.costPerInputToken, state.costPerOutputToken);
|
|
2118
|
+
const turnResponseEvent = {
|
|
2119
|
+
type: "turn_response",
|
|
2120
|
+
uuid: generateId3(),
|
|
2121
|
+
agentId,
|
|
2122
|
+
timestamp: Date.now(),
|
|
2123
|
+
turnId,
|
|
2124
|
+
data: {
|
|
2125
|
+
assistantMessage: {
|
|
2126
|
+
id: generateId3(),
|
|
2127
|
+
role: "assistant",
|
|
2128
|
+
subtype: "assistant",
|
|
2129
|
+
content: "",
|
|
2130
|
+
timestamp: completedAt
|
|
2131
|
+
},
|
|
2132
|
+
respondedAt: completedAt,
|
|
2133
|
+
durationMs: duration,
|
|
2134
|
+
usage,
|
|
2135
|
+
costUsd: cost
|
|
2136
|
+
}
|
|
2137
|
+
};
|
|
2138
|
+
return [
|
|
2139
|
+
{
|
|
2140
|
+
...state,
|
|
2141
|
+
pendingTurn: null
|
|
2142
|
+
},
|
|
2143
|
+
[turnResponseEvent]
|
|
2144
|
+
];
|
|
2145
|
+
}
|
|
2146
|
+
var agentProcessor = combineProcessors({
|
|
2147
|
+
messageAssembler: messageAssemblerProcessor,
|
|
2148
|
+
stateEventProcessor,
|
|
2149
|
+
turnTracker: turnTrackerProcessor
|
|
2150
|
+
});
|
|
2151
|
+
var createInitialAgentEngineState = combineInitialStates({
|
|
2152
|
+
messageAssembler: createInitialMessageAssemblerState,
|
|
2153
|
+
stateEventProcessor: createInitialStateEventProcessorContext,
|
|
2154
|
+
turnTracker: createInitialTurnTrackerState
|
|
2155
|
+
});
|
|
2156
|
+
var logger33 = createLogger("engine/AgentEngine");
|
|
2157
|
+
var AgentEngine = class {
|
|
454
2158
|
constructor() {
|
|
455
|
-
__publicField(this, "
|
|
2159
|
+
__publicField(this, "store");
|
|
2160
|
+
this.store = new MemoryStore();
|
|
2161
|
+
logger33.debug("AgentEngine initialized");
|
|
456
2162
|
}
|
|
457
2163
|
/**
|
|
458
|
-
*
|
|
2164
|
+
* Process a single stream event and return output events
|
|
459
2165
|
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
2166
|
+
* This is the core Mealy Machine operation:
|
|
2167
|
+
* process(agentId, event) → outputs[]
|
|
2168
|
+
*
|
|
2169
|
+
* @param agentId - The agent identifier (for state isolation)
|
|
2170
|
+
* @param event - Stream event to process
|
|
2171
|
+
* @returns Array of output events (state, message, turn events)
|
|
463
2172
|
*/
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
2173
|
+
process(agentId, event) {
|
|
2174
|
+
const eventType = event.type || "unknown";
|
|
2175
|
+
logger33.debug("Processing event", { agentId, eventType });
|
|
2176
|
+
const isNewState = !this.store.has(agentId);
|
|
2177
|
+
let state = this.store.get(agentId) ?? createInitialAgentEngineState();
|
|
2178
|
+
if (isNewState) {
|
|
2179
|
+
logger33.debug("Created initial state for agent", { agentId });
|
|
2180
|
+
}
|
|
2181
|
+
const allOutputs = [];
|
|
2182
|
+
allOutputs.push(event);
|
|
2183
|
+
const [newState, outputs] = agentProcessor(state, event);
|
|
2184
|
+
state = newState;
|
|
2185
|
+
for (const output of outputs) {
|
|
2186
|
+
allOutputs.push(output);
|
|
2187
|
+
const [chainedState, chainedOutputs] = this.processChained(state, output);
|
|
2188
|
+
state = chainedState;
|
|
2189
|
+
allOutputs.push(...chainedOutputs);
|
|
472
2190
|
}
|
|
2191
|
+
this.store.set(agentId, state);
|
|
2192
|
+
if (outputs.length > 0) {
|
|
2193
|
+
logger33.debug("Produced outputs", {
|
|
2194
|
+
agentId,
|
|
2195
|
+
inputEvent: eventType,
|
|
2196
|
+
outputCount: allOutputs.length,
|
|
2197
|
+
processorOutputs: outputs.length
|
|
2198
|
+
});
|
|
2199
|
+
}
|
|
2200
|
+
return allOutputs;
|
|
473
2201
|
}
|
|
474
2202
|
/**
|
|
475
|
-
*
|
|
2203
|
+
* Process chained events recursively
|
|
2204
|
+
*
|
|
2205
|
+
* Some processors produce events that trigger other processors:
|
|
2206
|
+
* - MessageAssembler produces MessageEvents
|
|
2207
|
+
* - TurnTracker consumes MessageEvents to produce TurnEvents
|
|
476
2208
|
*/
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
2209
|
+
processChained(state, event) {
|
|
2210
|
+
const [newState, outputs] = agentProcessor(state, event);
|
|
2211
|
+
if (outputs.length === 0) {
|
|
2212
|
+
return [newState, []];
|
|
2213
|
+
}
|
|
2214
|
+
const allOutputs = [...outputs];
|
|
2215
|
+
let currentState = newState;
|
|
2216
|
+
for (const output of outputs) {
|
|
2217
|
+
const [chainedState, chainedOutputs] = this.processChained(currentState, output);
|
|
2218
|
+
currentState = chainedState;
|
|
2219
|
+
allOutputs.push(...chainedOutputs);
|
|
2220
|
+
}
|
|
2221
|
+
return [currentState, allOutputs];
|
|
482
2222
|
}
|
|
483
2223
|
/**
|
|
484
|
-
*
|
|
2224
|
+
* Clear state for an agent
|
|
2225
|
+
*
|
|
2226
|
+
* Call this when an agent is destroyed to free memory.
|
|
485
2227
|
*/
|
|
486
|
-
|
|
487
|
-
|
|
2228
|
+
clearState(agentId) {
|
|
2229
|
+
logger33.debug("Clearing state", { agentId });
|
|
2230
|
+
this.store.delete(agentId);
|
|
488
2231
|
}
|
|
489
2232
|
/**
|
|
490
|
-
*
|
|
2233
|
+
* Check if state exists for an agent
|
|
491
2234
|
*/
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
if (error.severity === "fatal") {
|
|
495
|
-
logger5.error(`${prefix}: ${error.message}`, { error });
|
|
496
|
-
} else if (error.severity === "error") {
|
|
497
|
-
logger5.error(`${prefix}: ${error.message}`);
|
|
498
|
-
} else {
|
|
499
|
-
logger5.warn(`${prefix}: ${error.message}`);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
};
|
|
503
|
-
var ApiError = class extends Error {
|
|
504
|
-
constructor(code, message, details) {
|
|
505
|
-
super(message);
|
|
506
|
-
this.code = code;
|
|
507
|
-
this.details = details;
|
|
508
|
-
this.name = "ApiError";
|
|
2235
|
+
hasState(agentId) {
|
|
2236
|
+
return this.store.has(agentId);
|
|
509
2237
|
}
|
|
510
2238
|
};
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
headers: options.headers,
|
|
515
|
-
timeout: options.timeout || 3e4,
|
|
516
|
-
hooks: {
|
|
517
|
-
afterResponse: [
|
|
518
|
-
async (_request, _options, response) => {
|
|
519
|
-
if (!response.ok) {
|
|
520
|
-
const data = await response.json().catch(() => ({}));
|
|
521
|
-
throw new ApiError(
|
|
522
|
-
data.error?.code || "UNKNOWN_ERROR",
|
|
523
|
-
data.error?.message || `Request failed: ${response.status}`,
|
|
524
|
-
data.error?.details
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
return response;
|
|
528
|
-
}
|
|
529
|
-
]
|
|
530
|
-
}
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
var logger6 = common.createLogger("agentx/ContainerManager");
|
|
2239
|
+
|
|
2240
|
+
// src/container/ContainerManagerImpl.ts
|
|
2241
|
+
var logger7 = createLogger("agentx/ContainerManager");
|
|
534
2242
|
function generateContainerId() {
|
|
535
2243
|
const timestamp = Date.now().toString(36);
|
|
536
2244
|
const random = Math.random().toString(36).substring(2, 8);
|
|
@@ -549,7 +2257,7 @@ var ContainerManagerImpl = class {
|
|
|
549
2257
|
__publicField(this, "repository");
|
|
550
2258
|
this.runtime = runtime;
|
|
551
2259
|
this.repository = repository;
|
|
552
|
-
this.engine = new
|
|
2260
|
+
this.engine = new AgentEngine();
|
|
553
2261
|
}
|
|
554
2262
|
// ==================== Container Lifecycle ====================
|
|
555
2263
|
async create(config) {
|
|
@@ -562,7 +2270,7 @@ var ContainerManagerImpl = class {
|
|
|
562
2270
|
config
|
|
563
2271
|
};
|
|
564
2272
|
await this.repository.saveContainer(record);
|
|
565
|
-
|
|
2273
|
+
logger7.info("Container created", { containerId });
|
|
566
2274
|
return record;
|
|
567
2275
|
}
|
|
568
2276
|
async get(containerId) {
|
|
@@ -577,7 +2285,7 @@ var ContainerManagerImpl = class {
|
|
|
577
2285
|
return false;
|
|
578
2286
|
}
|
|
579
2287
|
await this.repository.deleteContainer(containerId);
|
|
580
|
-
|
|
2288
|
+
logger7.info("Container deleted", { containerId });
|
|
581
2289
|
return true;
|
|
582
2290
|
}
|
|
583
2291
|
async exists(containerId) {
|
|
@@ -585,7 +2293,7 @@ var ContainerManagerImpl = class {
|
|
|
585
2293
|
}
|
|
586
2294
|
// ==================== Agent Runtime ====================
|
|
587
2295
|
async run(image, containerId) {
|
|
588
|
-
|
|
2296
|
+
logger7.info("Running agent from image", {
|
|
589
2297
|
imageId: image.imageId,
|
|
590
2298
|
containerId
|
|
591
2299
|
});
|
|
@@ -605,18 +2313,18 @@ var ContainerManagerImpl = class {
|
|
|
605
2313
|
};
|
|
606
2314
|
const sandbox = this.runtime.createSandbox(containerId);
|
|
607
2315
|
const driver = this.runtime.createDriver(image.definition, context, sandbox);
|
|
608
|
-
const agent
|
|
609
|
-
this.agents.set(agentId, agent
|
|
610
|
-
|
|
2316
|
+
const agent = new AgentInstance(image.definition, context, this.engine, driver, sandbox);
|
|
2317
|
+
this.agents.set(agentId, agent);
|
|
2318
|
+
logger7.info("Agent started", {
|
|
611
2319
|
agentId,
|
|
612
2320
|
imageId: image.imageId,
|
|
613
2321
|
containerId,
|
|
614
2322
|
definitionName: image.definition.name
|
|
615
2323
|
});
|
|
616
|
-
return agent
|
|
2324
|
+
return agent;
|
|
617
2325
|
}
|
|
618
2326
|
async resume(session, containerId) {
|
|
619
|
-
|
|
2327
|
+
logger7.info("Resuming agent from session", {
|
|
620
2328
|
sessionId: session.sessionId,
|
|
621
2329
|
imageId: session.imageId,
|
|
622
2330
|
containerId
|
|
@@ -642,26 +2350,26 @@ var ContainerManagerImpl = class {
|
|
|
642
2350
|
const sandbox = this.runtime.createSandbox(containerId);
|
|
643
2351
|
const definition = imageRecord.definition;
|
|
644
2352
|
const driver = this.runtime.createDriver(definition, context, sandbox);
|
|
645
|
-
const agent
|
|
646
|
-
this.agents.set(agentId, agent
|
|
647
|
-
|
|
2353
|
+
const agent = new AgentInstance(definition, context, this.engine, driver, sandbox);
|
|
2354
|
+
this.agents.set(agentId, agent);
|
|
2355
|
+
logger7.info("Agent resumed", {
|
|
648
2356
|
agentId,
|
|
649
2357
|
sessionId: session.sessionId,
|
|
650
2358
|
imageId: session.imageId,
|
|
651
2359
|
containerId
|
|
652
2360
|
});
|
|
653
|
-
return agent
|
|
2361
|
+
return agent;
|
|
654
2362
|
}
|
|
655
2363
|
async destroyAgent(agentId) {
|
|
656
2364
|
const agent = this.agents.get(agentId);
|
|
657
2365
|
if (!agent) {
|
|
658
|
-
|
|
2366
|
+
logger7.warn("Agent not found for destroy", { agentId });
|
|
659
2367
|
return;
|
|
660
2368
|
}
|
|
661
|
-
|
|
2369
|
+
logger7.debug("Destroying agent", { agentId });
|
|
662
2370
|
await agent.destroy();
|
|
663
2371
|
this.agents.delete(agentId);
|
|
664
|
-
|
|
2372
|
+
logger7.info("Agent destroyed", { agentId });
|
|
665
2373
|
}
|
|
666
2374
|
getAgent(agentId) {
|
|
667
2375
|
return this.agents.get(agentId);
|
|
@@ -674,16 +2382,16 @@ var ContainerManagerImpl = class {
|
|
|
674
2382
|
}
|
|
675
2383
|
async destroyAllAgents() {
|
|
676
2384
|
const agentIds = Array.from(this.agents.keys());
|
|
677
|
-
|
|
2385
|
+
logger7.debug("Destroying all agents", { count: agentIds.length });
|
|
678
2386
|
await Promise.all(agentIds.map((id) => this.destroyAgent(id)));
|
|
679
|
-
|
|
2387
|
+
logger7.info("All agents destroyed", { count: agentIds.length });
|
|
680
2388
|
}
|
|
681
2389
|
};
|
|
682
2390
|
|
|
683
2391
|
// src/AgentX.ts
|
|
684
|
-
var
|
|
2392
|
+
var logger8 = createLogger("agentx/AgentX");
|
|
685
2393
|
function createAgentX(runtime, options) {
|
|
686
|
-
|
|
2394
|
+
logger8.info("Creating AgentX instance", { runtime: runtime.name });
|
|
687
2395
|
if (!runtime.repository) {
|
|
688
2396
|
throw new Error("Runtime must have a repository for persistence");
|
|
689
2397
|
}
|
|
@@ -694,7 +2402,7 @@ function createAgentX(runtime, options) {
|
|
|
694
2402
|
const agentManager = new AgentManager(containerManager);
|
|
695
2403
|
const imageManager = new ImageManagerImpl(repository, containerManager, options?.containerId);
|
|
696
2404
|
const sessionManager = new SessionManagerImpl(repository, containerManager, options?.containerId);
|
|
697
|
-
|
|
2405
|
+
logger8.debug("AgentX instance created", { runtime: runtime.name });
|
|
698
2406
|
return {
|
|
699
2407
|
mode: "local",
|
|
700
2408
|
containers: containerManager,
|
|
@@ -868,7 +2576,9 @@ function createSSEDriver(config) {
|
|
|
868
2576
|
}
|
|
869
2577
|
};
|
|
870
2578
|
}
|
|
871
|
-
|
|
2579
|
+
|
|
2580
|
+
// src/runtime/sse/repository/RemoteRepository.ts
|
|
2581
|
+
var logger9 = createLogger("agentx/RemoteRepository");
|
|
872
2582
|
var RemoteRepository = class {
|
|
873
2583
|
constructor(options) {
|
|
874
2584
|
__publicField(this, "client");
|
|
@@ -876,7 +2586,7 @@ var RemoteRepository = class {
|
|
|
876
2586
|
baseUrl: options.serverUrl,
|
|
877
2587
|
headers: options.headers
|
|
878
2588
|
});
|
|
879
|
-
|
|
2589
|
+
logger9.debug("RemoteRepository created", { serverUrl: options.serverUrl });
|
|
880
2590
|
}
|
|
881
2591
|
// ==================== Definition ====================
|
|
882
2592
|
async saveDefinition(record) {
|
|
@@ -981,7 +2691,7 @@ var RemoteRepository = class {
|
|
|
981
2691
|
* Browser-side calls this but it does nothing to avoid duplicate saves.
|
|
982
2692
|
*/
|
|
983
2693
|
async saveMessage(_record) {
|
|
984
|
-
|
|
2694
|
+
logger9.debug("saveMessage called (noop in browser)");
|
|
985
2695
|
}
|
|
986
2696
|
async findMessageById(messageId) {
|
|
987
2697
|
try {
|
|
@@ -1189,12 +2899,14 @@ var BrowserLoggerFactory = class {
|
|
|
1189
2899
|
if (this.loggers.has(name)) {
|
|
1190
2900
|
return this.loggers.get(name);
|
|
1191
2901
|
}
|
|
1192
|
-
const
|
|
1193
|
-
this.loggers.set(name,
|
|
1194
|
-
return
|
|
2902
|
+
const logger11 = new BrowserLogger(name, this.options);
|
|
2903
|
+
this.loggers.set(name, logger11);
|
|
2904
|
+
return logger11;
|
|
1195
2905
|
}
|
|
1196
2906
|
};
|
|
1197
|
-
|
|
2907
|
+
|
|
2908
|
+
// src/runtime/sse/RemoteAgentIdResolver.ts
|
|
2909
|
+
var logger10 = createLogger("agentx/RemoteAgentIdResolver");
|
|
1198
2910
|
var RemoteAgentIdResolver = class {
|
|
1199
2911
|
constructor(options) {
|
|
1200
2912
|
__publicField(this, "client");
|
|
@@ -1204,19 +2916,19 @@ var RemoteAgentIdResolver = class {
|
|
|
1204
2916
|
});
|
|
1205
2917
|
}
|
|
1206
2918
|
async resolveForRun(imageId, containerId) {
|
|
1207
|
-
|
|
2919
|
+
logger10.debug("Resolving agent ID for run", { imageId, containerId });
|
|
1208
2920
|
const response = await this.client.post(`images/${imageId}/run`, {
|
|
1209
2921
|
json: { containerId }
|
|
1210
2922
|
}).json();
|
|
1211
|
-
|
|
2923
|
+
logger10.info("Agent ID resolved for run", { imageId, agentId: response.agentId });
|
|
1212
2924
|
return response.agentId;
|
|
1213
2925
|
}
|
|
1214
2926
|
async resolveForResume(sessionId, containerId) {
|
|
1215
|
-
|
|
2927
|
+
logger10.debug("Resolving agent ID for resume", { sessionId, containerId });
|
|
1216
2928
|
const response = await this.client.post(`sessions/${sessionId}/resume`, {
|
|
1217
2929
|
json: { containerId }
|
|
1218
2930
|
}).json();
|
|
1219
|
-
|
|
2931
|
+
logger10.info("Agent ID resolved for resume", { sessionId, agentId: response.agentId });
|
|
1220
2932
|
return response.agentId;
|
|
1221
2933
|
}
|
|
1222
2934
|
};
|
|
@@ -1250,7 +2962,7 @@ var SSERuntime = class {
|
|
|
1250
2962
|
this.loggerFactory = new BrowserLoggerFactory({
|
|
1251
2963
|
collapsed: true
|
|
1252
2964
|
});
|
|
1253
|
-
|
|
2965
|
+
setLoggerFactory(this.loggerFactory);
|
|
1254
2966
|
this.repository = new RemoteRepository({
|
|
1255
2967
|
serverUrl: this.serverUrl,
|
|
1256
2968
|
headers: this.headers
|