@ai-setting/roy-agent-core 1.5.14-test → 1.5.15-test

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.
Files changed (141) hide show
  1. package/package.json +1 -1
  2. package/dist/config/index.d.ts +0 -1250
  3. package/dist/config/index.js +0 -32
  4. package/dist/env/agent/index.d.ts +0 -2279
  5. package/dist/env/agent/index.js +0 -24
  6. package/dist/env/commands/index.d.ts +0 -1131
  7. package/dist/env/commands/index.js +0 -14
  8. package/dist/env/debug/formatters/index.d.ts +0 -236
  9. package/dist/env/debug/formatters/index.js +0 -11
  10. package/dist/env/debug/index.d.ts +0 -1652
  11. package/dist/env/debug/index.js +0 -26
  12. package/dist/env/hook/index.d.ts +0 -279
  13. package/dist/env/hook/index.js +0 -29
  14. package/dist/env/index.d.ts +0 -3481
  15. package/dist/env/index.js +0 -82
  16. package/dist/env/llm/index.d.ts +0 -1760
  17. package/dist/env/llm/index.js +0 -40
  18. package/dist/env/log-trace/index.d.ts +0 -1574
  19. package/dist/env/log-trace/index.js +0 -83
  20. package/dist/env/mcp/index.d.ts +0 -1331
  21. package/dist/env/mcp/index.js +0 -39
  22. package/dist/env/mcp/tool/index.d.ts +0 -183
  23. package/dist/env/mcp/tool/index.js +0 -14
  24. package/dist/env/memory/built-in/index.d.ts +0 -232
  25. package/dist/env/memory/built-in/index.js +0 -11
  26. package/dist/env/memory/index.d.ts +0 -1799
  27. package/dist/env/memory/index.js +0 -56
  28. package/dist/env/memory/plugin/index.d.ts +0 -747
  29. package/dist/env/memory/plugin/index.js +0 -36
  30. package/dist/env/prompt/index.d.ts +0 -1164
  31. package/dist/env/prompt/index.js +0 -20
  32. package/dist/env/session/index.d.ts +0 -1908
  33. package/dist/env/session/index.js +0 -25
  34. package/dist/env/session/storage/index.d.ts +0 -564
  35. package/dist/env/session/storage/index.js +0 -18
  36. package/dist/env/skill/index.d.ts +0 -1266
  37. package/dist/env/skill/index.js +0 -34
  38. package/dist/env/skill/tool/index.d.ts +0 -193
  39. package/dist/env/skill/tool/index.js +0 -9
  40. package/dist/env/task/delegate/index.d.ts +0 -1612
  41. package/dist/env/task/delegate/index.js +0 -18
  42. package/dist/env/task/events/index.d.ts +0 -171
  43. package/dist/env/task/events/index.js +0 -7
  44. package/dist/env/task/hooks/index.d.ts +0 -624
  45. package/dist/env/task/hooks/index.js +0 -7
  46. package/dist/env/task/index.d.ts +0 -1553
  47. package/dist/env/task/index.js +0 -34
  48. package/dist/env/task/plugins/index.d.ts +0 -466
  49. package/dist/env/task/plugins/index.js +0 -23
  50. package/dist/env/task/storage/index.d.ts +0 -241
  51. package/dist/env/task/storage/index.js +0 -14
  52. package/dist/env/task/tools/index.d.ts +0 -1485
  53. package/dist/env/task/tools/index.js +0 -17
  54. package/dist/env/task/tools/operation/index.d.ts +0 -1484
  55. package/dist/env/task/tools/operation/index.js +0 -15
  56. package/dist/env/tool/built-in/index.d.ts +0 -218
  57. package/dist/env/tool/built-in/index.js +0 -25
  58. package/dist/env/tool/index.d.ts +0 -1396
  59. package/dist/env/tool/index.js +0 -39
  60. package/dist/env/workflow/decorators/index.d.ts +0 -2161
  61. package/dist/env/workflow/decorators/index.js +0 -27
  62. package/dist/env/workflow/engine/index.d.ts +0 -3453
  63. package/dist/env/workflow/engine/index.js +0 -28
  64. package/dist/env/workflow/index.d.ts +0 -3546
  65. package/dist/env/workflow/index.js +0 -136
  66. package/dist/env/workflow/nodes/index.d.ts +0 -2092
  67. package/dist/env/workflow/nodes/index.js +0 -19
  68. package/dist/env/workflow/service/index.d.ts +0 -227
  69. package/dist/env/workflow/service/index.js +0 -13
  70. package/dist/env/workflow/storage/index.d.ts +0 -165
  71. package/dist/env/workflow/storage/index.js +0 -27
  72. package/dist/env/workflow/tools/index.d.ts +0 -416
  73. package/dist/env/workflow/tools/index.js +0 -159
  74. package/dist/env/workflow/types/index.d.ts +0 -2255
  75. package/dist/env/workflow/types/index.js +0 -98
  76. package/dist/env/workflow/utils/index.d.ts +0 -2031
  77. package/dist/env/workflow/utils/index.js +0 -637
  78. package/dist/index.d.ts +0 -7858
  79. package/dist/index.js +0 -399
  80. package/dist/shared/@ai-setting/roy-agent-core-0rtxwr28.js +0 -258
  81. package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +0 -36
  82. package/dist/shared/@ai-setting/roy-agent-core-1akcqxj9.js +0 -349
  83. package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +0 -117
  84. package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +0 -11
  85. package/dist/shared/@ai-setting/roy-agent-core-3jywqmdd.js +0 -393
  86. package/dist/shared/@ai-setting/roy-agent-core-3rr5k71j.js +0 -200
  87. package/dist/shared/@ai-setting/roy-agent-core-44hnfb02.js +0 -299
  88. package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +0 -206
  89. package/dist/shared/@ai-setting/roy-agent-core-4txzpsbt.js +0 -393
  90. package/dist/shared/@ai-setting/roy-agent-core-5x94xmt6.js +0 -350
  91. package/dist/shared/@ai-setting/roy-agent-core-69jskqjg.js +0 -180
  92. package/dist/shared/@ai-setting/roy-agent-core-6kvtahqv.js +0 -408
  93. package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +0 -284
  94. package/dist/shared/@ai-setting/roy-agent-core-81w1963m.js +0 -762
  95. package/dist/shared/@ai-setting/roy-agent-core-8gxth0eh.js +0 -10
  96. package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +0 -14
  97. package/dist/shared/@ai-setting/roy-agent-core-93zfb3r1.js +0 -922
  98. package/dist/shared/@ai-setting/roy-agent-core-9yxb3ty9.js +0 -15
  99. package/dist/shared/@ai-setting/roy-agent-core-b0x5dda6.js +0 -1130
  100. package/dist/shared/@ai-setting/roy-agent-core-bcbqy27c.js +0 -14
  101. package/dist/shared/@ai-setting/roy-agent-core-bvr1761x.js +0 -653
  102. package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +0 -93
  103. package/dist/shared/@ai-setting/roy-agent-core-d7cyjkf7.js +0 -872
  104. package/dist/shared/@ai-setting/roy-agent-core-dh9d7a3m.js +0 -11
  105. package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +0 -64
  106. package/dist/shared/@ai-setting/roy-agent-core-eajcvp4e.js +0 -378
  107. package/dist/shared/@ai-setting/roy-agent-core-f7q2x5z6.js +0 -492
  108. package/dist/shared/@ai-setting/roy-agent-core-fs0mn2jk.js +0 -52
  109. package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +0 -171
  110. package/dist/shared/@ai-setting/roy-agent-core-g99pxzn5.js +0 -862
  111. package/dist/shared/@ai-setting/roy-agent-core-gbqcyegm.js +0 -1387
  112. package/dist/shared/@ai-setting/roy-agent-core-gjq1yk68.js +0 -208
  113. package/dist/shared/@ai-setting/roy-agent-core-gq20wsgv.js +0 -139
  114. package/dist/shared/@ai-setting/roy-agent-core-gwc4h96n.js +0 -534
  115. package/dist/shared/@ai-setting/roy-agent-core-jfh9q2qh.js +0 -204
  116. package/dist/shared/@ai-setting/roy-agent-core-jvatggbb.js +0 -603
  117. package/dist/shared/@ai-setting/roy-agent-core-kkbwepqb.js +0 -97
  118. package/dist/shared/@ai-setting/roy-agent-core-pjr12nnd.js +0 -587
  119. package/dist/shared/@ai-setting/roy-agent-core-psv4v63c.js +0 -176
  120. package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +0 -60
  121. package/dist/shared/@ai-setting/roy-agent-core-qqceba6k.js +0 -442
  122. package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +0 -57
  123. package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +0 -66
  124. package/dist/shared/@ai-setting/roy-agent-core-r9ezzemr.js +0 -10
  125. package/dist/shared/@ai-setting/roy-agent-core-rhmtwnw1.js +0 -267
  126. package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +0 -584
  127. package/dist/shared/@ai-setting/roy-agent-core-rvxg1wps.js +0 -102
  128. package/dist/shared/@ai-setting/roy-agent-core-satmq6sh.js +0 -549
  129. package/dist/shared/@ai-setting/roy-agent-core-sx7wsvnn.js +0 -15
  130. package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +0 -213
  131. package/dist/shared/@ai-setting/roy-agent-core-vf215qfv.js +0 -812
  132. package/dist/shared/@ai-setting/roy-agent-core-vkz81f7v.js +0 -1316
  133. package/dist/shared/@ai-setting/roy-agent-core-vn2bc59q.js +0 -1205
  134. package/dist/shared/@ai-setting/roy-agent-core-wa1kzqky.js +0 -328
  135. package/dist/shared/@ai-setting/roy-agent-core-wft9ra24.js +0 -20
  136. package/dist/shared/@ai-setting/roy-agent-core-wrcy0h6z.js +0 -2098
  137. package/dist/shared/@ai-setting/roy-agent-core-xq8hhqb8.js +0 -419
  138. package/dist/shared/@ai-setting/roy-agent-core-xs5rsgat.js +0 -368
  139. package/dist/shared/@ai-setting/roy-agent-core-zbkpc41z.js +0 -377
  140. package/dist/shared/@ai-setting/roy-agent-core-zgypchmt.js +0 -172
  141. package/dist/shared/@ai-setting/roy-agent-core-zpn0bqa8.js +0 -103
@@ -1,1387 +0,0 @@
1
- import {
2
- ContextError,
3
- ErrorCodes
4
- } from "./roy-agent-core-ctdhjv68.js";
5
- import {
6
- envKeyToConfigKey
7
- } from "./roy-agent-core-qxhq8ven.js";
8
- import {
9
- BaseComponent
10
- } from "./roy-agent-core-kkbwepqb.js";
11
- import {
12
- TracedAs,
13
- init_decorator
14
- } from "./roy-agent-core-zgypchmt.js";
15
- import {
16
- createLogger,
17
- init_logger
18
- } from "./roy-agent-core-44hnfb02.js";
19
- import {
20
- __legacyDecorateClassTS,
21
- __require
22
- } from "./roy-agent-core-fs0mn2jk.js";
23
-
24
- // src/env/environment.ts
25
- init_logger();
26
-
27
- // src/utils/id.ts
28
- function generateId(prefix = "id") {
29
- const timestamp = Date.now().toString(36);
30
- const random = Math.random().toString(36).substring(2, 11);
31
- return `${prefix}_${timestamp}_${random}`;
32
- }
33
- function generateDescendingId(prefix = "id") {
34
- const timestamp = (Number.MAX_SAFE_INTEGER - Date.now()).toString(36);
35
- const random = Math.random().toString(36).substring(2, 11);
36
- return `${prefix}_${timestamp}_${random}`;
37
- }
38
-
39
- // src/env/environment.ts
40
- init_decorator();
41
- import * as fsSync from "fs";
42
- import * as path from "path";
43
- var logger = createLogger("environment");
44
-
45
- class BaseEnvironment extends BaseComponent {
46
- name;
47
- version;
48
- components = new Map;
49
- constructor(config) {
50
- super();
51
- this.name = config?.name ?? "base-environment";
52
- this.version = config?.version ?? "1.0.0";
53
- this.registerDefaultComponents();
54
- }
55
- registerDefaultComponents() {}
56
- getConfig() {
57
- return {
58
- name: this.name,
59
- version: this.version,
60
- enabled: true,
61
- env: this
62
- };
63
- }
64
- registerComponent(component) {
65
- this.components.set(component.name, component);
66
- logger.debug(`Component registered: ${component.name}`);
67
- }
68
- unregisterComponent(name) {
69
- const component = this.components.get(name);
70
- if (component) {
71
- this.components.delete(name);
72
- logger.debug(`Component unregistered: ${name}`);
73
- }
74
- }
75
- getComponent(name) {
76
- return this.components.get(name);
77
- }
78
- listComponents() {
79
- return Array.from(this.components.values());
80
- }
81
- async handle_query(query, context) {
82
- const agentComponent = this.getComponent("agent");
83
- if (!agentComponent) {
84
- throw new Error("AgentComponent not found. Please register AgentComponent before calling handle_query.");
85
- }
86
- let systemPrompt = "You are a helpful assistant.";
87
- let promptSource = "fallback";
88
- try {
89
- const promptComponent = this.getComponent("prompt");
90
- if (promptComponent) {
91
- const loadedPrompt = await promptComponent.getPrompt("default");
92
- if (loadedPrompt) {
93
- systemPrompt = loadedPrompt;
94
- promptSource = "PromptComponent";
95
- }
96
- }
97
- } catch (err) {
98
- logger.warn(`[handle_query] Failed to get prompt from PromptComponent: ${err}`);
99
- }
100
- logger.info(`[handle_query] Using system prompt from ${promptSource}, length: ${systemPrompt.length}`);
101
- let finalSystemPrompt = systemPrompt;
102
- if (systemPrompt.includes("{{memory}}")) {
103
- try {
104
- const memoryComponent = this.getComponent("memory");
105
- if (memoryComponent) {
106
- const memoryContent = await memoryComponent.recallMemory();
107
- finalSystemPrompt = systemPrompt.replace("{{memory}}", memoryContent || "(No memory)");
108
- logger.info(`[handle_query] Injected memory content, length: ${memoryContent.length}`);
109
- } else {
110
- finalSystemPrompt = systemPrompt.replace("{{memory}}", "(Memory component not available)");
111
- }
112
- } catch (err) {
113
- logger.warn(`[handle_query] Failed to load memory content: ${err}`);
114
- finalSystemPrompt = systemPrompt.replace("{{memory}}", "(Failed to load memory)");
115
- }
116
- }
117
- if (finalSystemPrompt.includes("{{workspace_dir}}")) {
118
- const workspaceDir = process.cwd();
119
- finalSystemPrompt = finalSystemPrompt.replace("{{workspace_dir}}", workspaceDir);
120
- logger.debug(`[handle_query] Injected workspace_dir: ${workspaceDir}`);
121
- }
122
- const agentName = context?.agentType && context.agentType !== "default" ? context.agentType : "default";
123
- let agent = agentComponent.getAgent(agentName);
124
- if (!agent) {
125
- if (agentName !== "default") {
126
- logger.warn(`[handle_query] Agent "${agentName}" not found, falling back to "default"`);
127
- }
128
- agent = agentComponent.getAgent("default");
129
- }
130
- if (!agent) {
131
- agent = agentComponent.registerAgent("default", {
132
- type: "primary",
133
- systemPrompt: finalSystemPrompt
134
- });
135
- }
136
- const result = await agentComponent.run(agent.name, query, context);
137
- if (result.error) {
138
- const errorMsg = result.error.toLowerCase();
139
- if (errorMsg.includes("context") || errorMsg.includes("threshold") || errorMsg.includes("token") || result.error.includes("CTX_001")) {
140
- const usageMatch = result.error.match(/(\d+)\/(\d+)\s*\(([\d.]+)%\)/);
141
- let usage;
142
- let contextWindow;
143
- if (usageMatch) {
144
- const totalTokens = parseInt(usageMatch[1], 10);
145
- usage = {
146
- promptTokens: totalTokens,
147
- completionTokens: 0,
148
- totalTokens
149
- };
150
- contextWindow = parseInt(usageMatch[2], 10);
151
- }
152
- const ctxError = new ContextError(result.error, ErrorCodes.CONTEXT_THRESHOLD_EXCEEDED, context?.sessionId, usage, contextWindow);
153
- throw ctxError;
154
- }
155
- throw new Error(result.error);
156
- }
157
- return result.finalText || "";
158
- }
159
- async handle_action(action, context) {
160
- throw new Error("handle_action not implemented. Override in subclass.");
161
- }
162
- eventHandlers = new Map;
163
- wildcardHandlers = new Set;
164
- subscribe(handler) {
165
- this.wildcardHandlers.add(handler);
166
- logger.debug(`EnvEvent handler subscribed (wildcard)`);
167
- return () => {
168
- this.wildcardHandlers.delete(handler);
169
- logger.debug(`EnvEvent handler unsubscribed (wildcard)`);
170
- };
171
- }
172
- subscribeTo(eventType, handler) {
173
- const types = Array.isArray(eventType) ? eventType : [eventType];
174
- for (const type of types) {
175
- if (!this.eventHandlers.has(type)) {
176
- this.eventHandlers.set(type, new Set);
177
- }
178
- this.eventHandlers.get(type).add(handler);
179
- }
180
- logger.debug(`EnvEvent handler subscribed for types: ${types.join(", ")}`);
181
- return () => {
182
- for (const type of types) {
183
- this.eventHandlers.get(type)?.delete(handler);
184
- }
185
- logger.debug(`EnvEvent handler unsubscribed for types: ${types.join(", ")}`);
186
- };
187
- }
188
- subscribeAll(handler) {
189
- return this.subscribe(handler);
190
- }
191
- pushEnvEvent(event) {
192
- const fullEvent = "id" in event && event.id ? event : {
193
- id: event.id ?? generateId(),
194
- type: event.type,
195
- timestamp: event.timestamp ?? Date.now(),
196
- metadata: {
197
- ...event.metadata,
198
- env_name: event.metadata?.env_name ?? this.name
199
- },
200
- payload: event.payload ?? {}
201
- };
202
- for (const handler of this.wildcardHandlers) {
203
- try {
204
- handler(fullEvent);
205
- } catch (error) {
206
- logger.error(`Error in EnvEvent handler: ${error}`);
207
- }
208
- }
209
- const handlers = this.eventHandlers.get(fullEvent.type);
210
- if (handlers) {
211
- for (const handler of handlers) {
212
- try {
213
- handler(fullEvent);
214
- } catch (error) {
215
- logger.error(`Error in EnvEvent handler for ${fullEvent.type}: ${error}`);
216
- }
217
- }
218
- }
219
- }
220
- emit(type, payload, metadata) {
221
- const event = {
222
- id: generateId(),
223
- type,
224
- timestamp: Date.now(),
225
- metadata: {
226
- env_name: this.name,
227
- ...metadata
228
- },
229
- payload
230
- };
231
- this.pushEnvEvent(event);
232
- }
233
- async initializeComponents() {
234
- logger.debug(`Starting component initialization, total: ${this.components.size}`);
235
- const configComp = this.components.get("config");
236
- if (configComp && configComp.getStatus() === "created") {
237
- logger.debug(`Initializing ConfigComponent first...`);
238
- await configComp.init({
239
- name: "config",
240
- version: configComp.version,
241
- enabled: true,
242
- env: this
243
- });
244
- logger.debug(`ConfigComponent initialized`);
245
- } else {
246
- logger.debug(`No ConfigComponent found, skipping first stage`);
247
- }
248
- const otherComponents = Array.from(this.components.values()).filter((c) => c.getStatus() === "created");
249
- if (otherComponents.length > 0) {
250
- logger.debug(`Initializing ${otherComponents.length} other components...`);
251
- for (const component of otherComponents) {
252
- logger.debug(`Initializing component: ${component.name}`);
253
- await component.init({
254
- name: component.name,
255
- version: component.version,
256
- enabled: true,
257
- env: this
258
- });
259
- logger.debug(`Component initialized: ${component.name}`);
260
- }
261
- }
262
- logger.debug(`All components initialized`);
263
- }
264
- async startComponents() {
265
- const allComponents = Array.from(this.components.values());
266
- if (allComponents.length > 0) {
267
- logger.debug(`Starting ${allComponents.length} components...`);
268
- for (const component of allComponents) {
269
- logger.debug(`Starting component: ${component.name} (current status: ${component.getStatus()})`);
270
- await component.start();
271
- logger.debug(`Component started: ${component.name}`);
272
- }
273
- }
274
- }
275
- async stopComponents() {
276
- const componentsToStop = Array.from(this.components.values()).filter((c) => c.getStatus() !== "stopped");
277
- if (componentsToStop.length > 0) {
278
- logger.debug(`Stopping ${componentsToStop.length} components...`);
279
- for (const component of componentsToStop) {
280
- logger.debug(`Stopping component: ${component.name}`);
281
- await component.stop();
282
- logger.debug(`Component stopped: ${component.name}`);
283
- }
284
- }
285
- }
286
- async onInit() {
287
- await this.initializeComponents();
288
- logger.info(`Environment "${this.name}" initialized`);
289
- }
290
- async onStart() {
291
- await this.startComponents();
292
- logger.info(`Environment "${this.name}" started`);
293
- }
294
- async onStop() {
295
- await this.stopComponents();
296
- this.eventHandlers.clear();
297
- this.wildcardHandlers.clear();
298
- logger.info(`Environment "${this.name}" stopped`);
299
- }
300
- async init() {
301
- Object.defineProperty(this, "env", {
302
- value: this,
303
- writable: true,
304
- enumerable: false,
305
- configurable: true
306
- });
307
- this.setStatus("initializing");
308
- await this.onInit();
309
- this.setStatus("running");
310
- }
311
- async start() {
312
- if (this._started)
313
- return;
314
- this._started = true;
315
- await this.onStart();
316
- this.setStatus("running");
317
- logger.info(`Environment "${this.name}" started`);
318
- }
319
- async stop() {
320
- this.setStatus("stopping");
321
- await this.onStop();
322
- this.setStatus("stopped");
323
- }
324
- async loadServiceConfig(configPath) {
325
- const configComponent = this.getComponent("config");
326
- if (!configComponent) {
327
- throw new Error("ConfigComponent not found. Please register ConfigComponent before loading service config.");
328
- }
329
- const xdgDataHome = configComponent.getXdgDataHome();
330
- const fullPath = path.resolve(xdgDataHome, configPath);
331
- if (!fsSync.existsSync(fullPath)) {
332
- throw new Error(`Service config file not found: ${fullPath}`);
333
- }
334
- const content = fsSync.readFileSync(fullPath, "utf-8");
335
- let config;
336
- try {
337
- config = JSON.parse(content);
338
- } catch (e) {
339
- throw new Error(`Failed to parse service config: ${e}`);
340
- }
341
- logger.debug(`Service config loaded from: ${fullPath}`);
342
- return config;
343
- }
344
- generateComponentOptions(componentName, configEntry) {
345
- const configComponent = this.getComponent("config");
346
- if (!configComponent) {
347
- throw new Error("ConfigComponent not found. Please register ConfigComponent before generating component options.");
348
- }
349
- const options = {
350
- configComponent,
351
- configPath: configEntry.configPath,
352
- envPrefix: configEntry.envPrefix,
353
- config: configEntry.config
354
- };
355
- logger.debug(`Generated options for component: ${componentName}`);
356
- return options;
357
- }
358
- async registerComponentWithConfig(component, configEntry) {
359
- if (!this.components.has(component.name)) {
360
- this.registerComponent(component);
361
- }
362
- const options = this.generateComponentOptions(component.name, configEntry);
363
- if (component.getStatus() === "running") {
364
- logger.debug(`Component ${component.name} already initialized, skipping`);
365
- return;
366
- }
367
- await component.init({
368
- name: component.name,
369
- version: component.version,
370
- enabled: configEntry.enabled ?? true,
371
- env: this,
372
- options
373
- });
374
- logger.debug(`Component ${component.name} registered and initialized with config`);
375
- }
376
- async initFromConfig(configPath) {
377
- if (!this.env) {
378
- Object.defineProperty(this, "env", {
379
- value: this,
380
- writable: true,
381
- enumerable: false,
382
- configurable: true
383
- });
384
- }
385
- const serviceConfig = await this.loadServiceConfig(configPath);
386
- if (serviceConfig.environment) {
387
- if (serviceConfig.environment.name) {
388
- this.name = serviceConfig.environment.name;
389
- }
390
- if (serviceConfig.environment.version) {
391
- this.version = serviceConfig.environment.version;
392
- }
393
- }
394
- const configComponent = this.getComponent("config");
395
- if (!configComponent) {
396
- throw new Error("ConfigComponent not found. Please register ConfigComponent before initFromConfig.");
397
- }
398
- if (configComponent.getStatus() === "created") {
399
- await configComponent.init({
400
- name: "config",
401
- version: configComponent.version,
402
- enabled: true,
403
- env: this
404
- });
405
- }
406
- const components = serviceConfig.components || {};
407
- for (const [componentName, configEntry] of Object.entries(components)) {
408
- if (configEntry.enabled === false) {
409
- logger.debug(`Component ${componentName} is disabled, skipping`);
410
- continue;
411
- }
412
- const component = this.getComponent(componentName);
413
- if (!component) {
414
- logger.warn(`Component ${componentName} not registered, skipping`);
415
- continue;
416
- }
417
- if (component.name === "config")
418
- continue;
419
- await this.registerComponentWithConfig(component, configEntry);
420
- }
421
- this.setStatus("running");
422
- logger.info(`Environment "${this.name}" initialized from config: ${configPath}`);
423
- }
424
- }
425
- __legacyDecorateClassTS([
426
- TracedAs("env.handle_query", { recordParams: true, recordResult: true, log: true })
427
- ], BaseEnvironment.prototype, "handle_query", null);
428
- // src/env/event-source/event-source-component.ts
429
- import { spawn, exec } from "child_process";
430
- import { promisify } from "util";
431
- import { join } from "path";
432
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
433
- init_logger();
434
-
435
- // src/env/event-source/event-source-config-registration.ts
436
- var EVENT_SOURCE_DEFAULTS = {
437
- "event-source.enabled": true,
438
- "event-source.persistenceEnabled": true
439
- };
440
- var EVENT_SOURCE_CONFIG_REGISTRATION = {
441
- name: "event-source",
442
- sources: [
443
- { type: "env", envPrefix: "EVENT_SOURCE", priority: 20, watch: false }
444
- ],
445
- keys: [
446
- { key: "event-source.enabled", sources: ["env", "file"] },
447
- { key: "event-source.persistenceEnabled", sources: ["env", "file"] },
448
- { key: "event-source.configPath", sources: ["env", "file"] }
449
- ]
450
- };
451
-
452
- // src/env/event-source/event-source-component.ts
453
- var execAsyncImpl = promisify(exec);
454
- function getExecAsync() {
455
- return execAsyncImpl;
456
- }
457
- var logger2 = createLogger("event-source");
458
-
459
- class EventSourceComponent extends BaseComponent {
460
- name = "event-source";
461
- version = "1.0.0";
462
- sources = new Map;
463
- statuses = new Map;
464
- processes = new Map;
465
- handlers = new Map;
466
- timers = new Map;
467
- buffers = new Map;
468
- configPath = "";
469
- persistenceEnabled = true;
470
- configComponent;
471
- configWatcher;
472
- async onInit() {
473
- await this.loadConfig();
474
- }
475
- async init(options) {
476
- if (options?.env) {
477
- this.env = options.env;
478
- }
479
- this.setStatus("initializing");
480
- if (options?.name)
481
- Object.defineProperty(this, "name", { value: options.name, writable: false });
482
- if (options?.version)
483
- Object.defineProperty(this, "version", { value: options.version, writable: false });
484
- if (options?.enabled !== undefined)
485
- this._enabled = options.enabled;
486
- const opts = options?.options;
487
- if (opts?.configComponent) {
488
- this.configComponent = opts.configComponent;
489
- await this.registerConfig(opts);
490
- } else {
491
- throw new Error("ConfigComponent is required for EventSourceComponent initialization");
492
- }
493
- await this.onInit();
494
- this.setStatus("running");
495
- }
496
- async onStart() {}
497
- async onStop() {
498
- this.configWatcher?.();
499
- this.configWatcher = undefined;
500
- const runningSources = Array.from(this.statuses.entries()).filter(([_, status]) => status === "running").map(([id]) => id);
501
- for (const id of runningSources) {
502
- await this.stopSource(id);
503
- }
504
- this.sources.clear();
505
- this.statuses.clear();
506
- this.processes.clear();
507
- this.handlers.clear();
508
- this.timers.clear();
509
- this.buffers.clear();
510
- }
511
- async registerConfig(options) {
512
- const configComponent = options.configComponent;
513
- if (!configComponent)
514
- return;
515
- const { configPath, config } = options;
516
- const envPrefix = "EVENT_SOURCE";
517
- configComponent.registerComponent(EVENT_SOURCE_CONFIG_REGISTRATION);
518
- if (configPath) {
519
- configComponent.registerSource({
520
- type: "file",
521
- relativePath: configPath,
522
- optional: true,
523
- watch: false
524
- });
525
- }
526
- configComponent.registerSource({
527
- type: "env",
528
- envPrefix,
529
- priority: 20,
530
- watch: false
531
- });
532
- await configComponent.load("event-source");
533
- for (const envKey of Object.keys(process.env)) {
534
- const configKey = envKeyToConfigKey(envKey, envPrefix, "event-source");
535
- if (!configKey)
536
- continue;
537
- const value = process.env[envKey];
538
- if (value !== undefined) {
539
- await configComponent.set(configKey, value);
540
- }
541
- }
542
- for (const [key, value] of Object.entries(EVENT_SOURCE_DEFAULTS)) {
543
- if (configComponent.get(key) === undefined) {
544
- await configComponent.set(key, value);
545
- }
546
- }
547
- if (configComponent.get("event-source.configPath") === undefined) {
548
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
549
- const dataDir = join(home, ".roy-agent");
550
- await configComponent.set("event-source.configPath", join(dataDir, "event-sources.json"));
551
- }
552
- if (config) {
553
- const flatConfig = this.flattenConfig(config);
554
- for (const [key, value] of Object.entries(flatConfig)) {
555
- await configComponent.set(key, value);
556
- }
557
- }
558
- this.registerConfigWatcher(configComponent);
559
- }
560
- buildConfig() {
561
- const configComponent = this.configComponent;
562
- if (!configComponent) {
563
- return {
564
- enabled: true,
565
- persistenceEnabled: true,
566
- configPath: ""
567
- };
568
- }
569
- return {
570
- enabled: configComponent.get("event-source.enabled") ?? true,
571
- persistenceEnabled: configComponent.get("event-source.persistenceEnabled") ?? true,
572
- configPath: configComponent.get("event-source.configPath") ?? ""
573
- };
574
- }
575
- flattenConfig(obj, prefix = "event-source") {
576
- const result = {};
577
- for (const [key, value] of Object.entries(obj)) {
578
- const fullKey = `${prefix}.${key}`;
579
- if (value && typeof value === "object" && !Array.isArray(value)) {
580
- Object.assign(result, this.flattenConfig(value, fullKey));
581
- } else {
582
- result[fullKey] = value;
583
- }
584
- }
585
- return result;
586
- }
587
- registerConfigWatcher(configComponent) {
588
- if (typeof configComponent.watch !== "function") {
589
- return;
590
- }
591
- this.configWatcher = configComponent.watch("event-source.*", (event) => {
592
- this.onConfigChange(event);
593
- });
594
- }
595
- onConfigChange(event) {
596
- logger2.info(`EventSource config changed: ${event.key}`, {
597
- oldValue: event.oldValue,
598
- newValue: event.newValue
599
- });
600
- }
601
- register(config) {
602
- if (this.sources.has(config.id)) {
603
- throw new Error(`EventSource already exists: ${config.id}`);
604
- }
605
- this.sources.set(config.id, config);
606
- this.statuses.set(config.id, "created");
607
- logger2.debug(`EventSource registered: ${config.id} (${config.type})`);
608
- this.saveConfig().catch((err) => {
609
- logger2.error(`Failed to save config after registering ${config.id}:`, err);
610
- });
611
- }
612
- unregister(id) {
613
- const status = this.statuses.get(id);
614
- if (status === "running") {
615
- this.stopSource(id);
616
- }
617
- const existed = this.sources.has(id);
618
- this.sources.delete(id);
619
- this.statuses.delete(id);
620
- this.handlers.delete(id);
621
- this.buffers.delete(id);
622
- if (existed) {
623
- logger2.debug(`EventSource unregistered: ${id}`);
624
- this.saveConfig().catch((err) => {
625
- logger2.error(`Failed to save config after unregistering ${id}:`, err);
626
- });
627
- }
628
- return existed;
629
- }
630
- get(id) {
631
- return this.sources.get(id);
632
- }
633
- list() {
634
- return Array.from(this.sources.values());
635
- }
636
- getEventSourceStatus(id) {
637
- return this.statuses.get(id);
638
- }
639
- getEventSourceStatusById(id) {
640
- return this.statuses.get(id);
641
- }
642
- onEvent(id, handler) {
643
- this.handlers.set(id, handler);
644
- }
645
- offEvent(id) {
646
- this.handlers.delete(id);
647
- }
648
- async startSource(id) {
649
- const config = this.sources.get(id);
650
- if (!config) {
651
- throw new Error(`EventSource not found: ${id}`);
652
- }
653
- const currentStatus = this.statuses.get(id);
654
- if (currentStatus === "running") {
655
- return;
656
- }
657
- this.statuses.set(id, "starting");
658
- try {
659
- switch (config.type) {
660
- case "lark-cli":
661
- await this.startLarkCli(id, config);
662
- break;
663
- case "timer":
664
- await this.startTimer(id, config);
665
- break;
666
- case "websocket":
667
- await this.startWebSocket(id, config);
668
- break;
669
- default:
670
- throw new Error(`Unsupported event source type: ${config.type}`);
671
- }
672
- this.statuses.set(id, "running");
673
- this.getEnv()?.pushEnvEvent({
674
- type: "event-source.started",
675
- payload: { sourceId: id, sourceType: config.type }
676
- });
677
- logger2.info(`EventSource started: ${id} (${config.type})`);
678
- } catch (error) {
679
- this.statuses.set(id, "error");
680
- logger2.error(`EventSource failed to start: ${id}`, error);
681
- throw error;
682
- }
683
- }
684
- async stopSource(id) {
685
- const status = this.statuses.get(id);
686
- logger2.info(`[EventSource ${id}] stopSource called, current status: ${status}`);
687
- if (status === "stopped" || status === "created") {
688
- logger2.info(`[EventSource ${id}] already stopped/created, skipping`);
689
- return;
690
- }
691
- this.statuses.set(id, "stopping");
692
- const processInfo = this.processes.get(id);
693
- const child = processInfo?.child;
694
- logger2.info(`[EventSource ${id}] process info: ${processInfo ? `pid=${processInfo.child.pid}` : "none"}`);
695
- if (processInfo && child) {
696
- child.removeAllListeners("exit");
697
- child.removeAllListeners("error");
698
- child.stdout?.removeAllListeners("data");
699
- child.stderr?.removeAllListeners("data");
700
- const killProcess = (pid, signal) => {
701
- try {
702
- process.kill(pid, signal);
703
- return true;
704
- } catch (e) {
705
- return false;
706
- }
707
- };
708
- const pidsToKill = processInfo.pids.length > 0 ? processInfo.pids : processInfo.child.pid ? [processInfo.child.pid] : [];
709
- logger2.info(`[EventSource ${id}] sending SIGTERM to ${pidsToKill.length} processes: ${pidsToKill.join(", ")}`);
710
- for (const pid of pidsToKill) {
711
- killProcess(pid, "SIGTERM");
712
- }
713
- await new Promise((resolve2) => {
714
- const timeout = setTimeout(() => {
715
- logger2.warn(`[EventSource ${id}] SIGTERM timeout, sending SIGKILL to ${pidsToKill.length} processes`);
716
- for (const pid of pidsToKill) {
717
- killProcess(pid, "SIGKILL");
718
- }
719
- resolve2();
720
- }, 3000);
721
- try {
722
- const onceResult = child.once?.("exit", () => {
723
- clearTimeout(timeout);
724
- for (const pid of pidsToKill) {
725
- if (pid !== processInfo.child.pid) {
726
- killProcess(pid, "SIGKILL");
727
- }
728
- }
729
- resolve2();
730
- });
731
- if (!onceResult || typeof onceResult.once !== "function") {
732
- child.on("exit", () => {
733
- clearTimeout(timeout);
734
- for (const pid of pidsToKill) {
735
- if (pid !== processInfo.child.pid) {
736
- killProcess(pid, "SIGKILL");
737
- }
738
- }
739
- resolve2();
740
- });
741
- }
742
- } catch (e) {
743
- logger2.warn(`[EventSource ${id}] failed to register exit listener: ${e}`);
744
- }
745
- });
746
- this.processes.delete(id);
747
- } else if (child) {
748
- child.removeAllListeners("exit");
749
- child.removeAllListeners("error");
750
- child.stdout?.removeAllListeners("data");
751
- child.stderr?.removeAllListeners("data");
752
- const pid = child.pid;
753
- const pgid = child.pgid;
754
- try {
755
- if (pgid && pgid > 0 && pgid !== pid) {
756
- logger2.info(`[EventSource ${id}] killing process group ${pgid}`);
757
- try {
758
- process.kill(-pgid, "SIGTERM");
759
- } catch (e) {
760
- logger2.warn(`[EventSource ${id}] failed to kill process group: ${e}`);
761
- }
762
- }
763
- logger2.info(`[EventSource ${id}] killing main process ${pid}`);
764
- child.kill("SIGTERM");
765
- await new Promise((resolve2) => {
766
- const timeout = setTimeout(() => {
767
- logger2.warn(`[EventSource ${id}] SIGTERM timeout, sending SIGKILL`);
768
- if (pgid && pgid > 0 && pgid !== pid) {
769
- try {
770
- process.kill(-pgid, "SIGKILL");
771
- } catch (e) {
772
- logger2.warn(`[EventSource ${id}] failed to kill process group with SIGKILL: ${e}`);
773
- }
774
- }
775
- child.kill("SIGKILL");
776
- resolve2();
777
- }, 3000);
778
- child.once("exit", () => {
779
- clearTimeout(timeout);
780
- resolve2();
781
- });
782
- });
783
- } catch (error) {
784
- logger2.error(`[EventSource ${id}] Failed to kill process:`, error);
785
- try {
786
- child.kill("SIGKILL");
787
- } catch {}
788
- }
789
- this.processes.delete(id);
790
- } else {
791
- logger2.warn(`[EventSource ${id}] no child process found in processes map`);
792
- }
793
- const timer = this.timers.get(id);
794
- if (timer) {
795
- clearInterval(timer);
796
- this.timers.delete(id);
797
- }
798
- this.buffers.delete(id);
799
- const config = this.sources.get(id);
800
- this.statuses.set(id, "stopped");
801
- this.getEnv()?.pushEnvEvent({
802
- type: "event-source.stopped",
803
- payload: { sourceId: id, sourceType: config?.type }
804
- });
805
- logger2.info(`EventSource stopped: ${id}`);
806
- }
807
- async findRelatedProcesses(pattern) {
808
- const pids = [];
809
- const platform = process.platform;
810
- try {
811
- const exec2 = getExecAsync();
812
- if (platform === "win32") {
813
- const escapedPattern = pattern.replace(/'/g, "''").replace(/"/g, '`"');
814
- const psCommand = `Get-CimInstance Win32_Process | Where-Object { $_.CommandLine -like '*${escapedPattern}*' } | Select-Object -ExpandProperty ProcessId`;
815
- const { stdout } = await exec2(`powershell -Command "${psCommand}"`);
816
- const matches = stdout.replace(/\r\n/g, `
817
- `).match(/\d+/g);
818
- if (matches) {
819
- for (const match of matches) {
820
- const pid = parseInt(match, 10);
821
- if (!isNaN(pid) && pid > 0) {
822
- pids.push(pid);
823
- }
824
- }
825
- }
826
- } else {
827
- const { stdout } = await exec2(`pgrep -f "${pattern.replace(/"/g, "\\\"")}"`);
828
- const lines = stdout.trim().split(`
829
- `);
830
- for (const line of lines) {
831
- const trimmed = line.trim();
832
- if (trimmed) {
833
- const pid = parseInt(trimmed, 10);
834
- if (!isNaN(pid) && pid > 0) {
835
- pids.push(pid);
836
- }
837
- }
838
- }
839
- }
840
- } catch (error) {
841
- logger2.debug(`[EventSource] findRelatedProcesses: no processes found for pattern "${pattern}"`);
842
- }
843
- return pids;
844
- }
845
- async trackRelatedProcesses(id) {
846
- const processInfo = this.processes.get(id);
847
- if (!processInfo)
848
- return;
849
- const command = processInfo?.command || "";
850
- const commandParts = command.split(" ");
851
- const baseCommand = commandParts[0];
852
- const eventKeyword = "event";
853
- let relatedPids = await this.findRelatedProcesses(baseCommand);
854
- if (relatedPids.length < 2) {
855
- const morePids = await this.findRelatedProcesses(eventKeyword);
856
- for (const pid of morePids) {
857
- if (!relatedPids.includes(pid)) {
858
- relatedPids.push(pid);
859
- }
860
- }
861
- }
862
- const ownPid = process.pid;
863
- relatedPids = relatedPids.filter((pid) => pid !== ownPid);
864
- for (const pid of relatedPids) {
865
- if (!processInfo.pids.includes(pid)) {
866
- processInfo.pids.push(pid);
867
- }
868
- }
869
- const mainPid = processInfo.child.pid;
870
- if (mainPid && !processInfo.pids.includes(mainPid)) {
871
- processInfo.pids.unshift(mainPid);
872
- }
873
- logger2.info(`[EventSource ${id}] tracked ${processInfo.pids.length} related processes: ${processInfo.pids.join(", ")}`);
874
- }
875
- startLarkCli(id, config) {
876
- return new Promise((resolve2, reject) => {
877
- const command = config.command || "lark-cli event +subscribe";
878
- logger2.info(`Starting lark-cli event source: ${id}`);
879
- logger2.debug(`Executing command: ${command}`);
880
- const isWindows = process.platform === "win32";
881
- const shell = isWindows ? "cmd.exe" : "sh";
882
- const shellArgs = isWindows ? ["/c", command] : ["-c", `exec ${command}`];
883
- const child = spawn(shell, shellArgs, {
884
- stdio: ["ignore", "pipe", "pipe"],
885
- detached: false,
886
- windowsHide: true
887
- });
888
- this.processes.set(id, {
889
- child,
890
- pgid: child.pgid,
891
- pids: [],
892
- command
893
- });
894
- let startupTimeout = null;
895
- let settled = false;
896
- let startupConfirmed = false;
897
- const handleStartupSuccess = async () => {
898
- if (settled)
899
- return;
900
- settled = true;
901
- startupConfirmed = true;
902
- clearTimeout(startupTimeout);
903
- this.statuses.set(id, "running");
904
- logger2.info(`[EventSource ${id}] confirmed running`);
905
- try {
906
- await this.trackRelatedProcesses(id);
907
- } catch (e) {
908
- logger2.warn(`[EventSource ${id}] failed to track related processes: ${e}`);
909
- }
910
- resolve2();
911
- };
912
- startupTimeout = setTimeout(() => {
913
- if (!settled && !startupConfirmed) {
914
- handleStartupSuccess();
915
- }
916
- }, 1000);
917
- child.stdout?.on("data", (data) => {
918
- const output = data.toString();
919
- this.processStream(id, output);
920
- if (output.includes('"ok": true') || output.includes('"ok":true')) {
921
- if (!settled) {
922
- handleStartupSuccess();
923
- }
924
- }
925
- });
926
- child.stderr?.on("data", (data) => {
927
- const output = data.toString();
928
- if (output.includes('"ok": false') || output.includes('"ok":false')) {
929
- if (!settled) {
930
- settled = true;
931
- clearTimeout(startupTimeout);
932
- this.statuses.set(id, "error");
933
- child.kill();
934
- try {
935
- const errorObj = JSON.parse(output);
936
- reject(new Error(errorObj.error?.message || `lark-cli error: ${output}`));
937
- } catch {
938
- reject(new Error(`lark-cli error: ${output}`));
939
- }
940
- }
941
- }
942
- });
943
- child.on("exit", (code) => {
944
- if (!settled) {
945
- if (code !== 0 && code !== null) {
946
- settled = true;
947
- clearTimeout(startupTimeout);
948
- logger2.warn(`[EventSource ${id}] exited with code ${code}`);
949
- this.statuses.set(id, "error");
950
- reject(new Error(`lark-cli exited with code ${code}`));
951
- }
952
- }
953
- });
954
- child.on("error", (error) => {
955
- if (!settled) {
956
- settled = true;
957
- clearTimeout(startupTimeout);
958
- logger2.error(`[EventSource ${id}] process error:`, error);
959
- this.statuses.set(id, "error");
960
- reject(error);
961
- }
962
- });
963
- });
964
- }
965
- async startTimer(id, config) {
966
- const interval = config.interval || 60000;
967
- logger2.info(`Starting timer event source: ${id}, interval: ${interval}ms`);
968
- const timer = setInterval(() => {
969
- const message = config.options?.message || `Timer event from ${config.name}`;
970
- this.handleEvent(id, JSON.stringify({
971
- type: "timer.tick",
972
- payload: {
973
- message,
974
- timestamp: Date.now()
975
- }
976
- }));
977
- }, interval);
978
- this.timers.set(id, timer);
979
- this.handleEvent(id, JSON.stringify({
980
- type: "timer.tick",
981
- payload: {
982
- message: config.options?.message || `Timer event from ${config.name}`,
983
- timestamp: Date.now()
984
- }
985
- }));
986
- }
987
- async startWebSocket(id, config) {
988
- const url = config.url;
989
- if (!url) {
990
- throw new Error("WebSocket URL is required");
991
- }
992
- logger2.info(`Starting WebSocket event source: ${id}, url: ${url}`);
993
- try {
994
- const { WebSocket } = await import("ws");
995
- const ws = new WebSocket(url, {
996
- headers: config.headers
997
- });
998
- const wrapper = {
999
- child: {
1000
- kill: () => ws.close(),
1001
- on: (event, cb) => {
1002
- ws.on(event, cb);
1003
- }
1004
- },
1005
- pids: []
1006
- };
1007
- this.processes.set(id, wrapper);
1008
- ws.on("message", (data) => {
1009
- this.processStream(id, data.toString());
1010
- });
1011
- ws.on("error", (error) => {
1012
- logger2.error(`[EventSource ${id}] WebSocket error:`, error);
1013
- });
1014
- ws.on("close", () => {
1015
- logger2.info(`[EventSource ${id}] WebSocket closed`);
1016
- this.statuses.set(id, "stopped");
1017
- });
1018
- } catch (error) {
1019
- throw new Error(`Failed to import ws module: ${error}`);
1020
- }
1021
- }
1022
- processStream(sourceId, data) {
1023
- let buffer = this.buffers.get(sourceId) || "";
1024
- buffer += data;
1025
- const lines = buffer.split(`
1026
- `);
1027
- buffer = lines.pop() || "";
1028
- this.buffers.set(sourceId, buffer);
1029
- for (const line of lines) {
1030
- if (line.trim()) {
1031
- this.handleEvent(sourceId, line);
1032
- }
1033
- }
1034
- }
1035
- handleEvent(sourceId, rawData) {
1036
- const config = this.sources.get(sourceId);
1037
- if (!config)
1038
- return;
1039
- try {
1040
- const rawEvent = JSON.parse(rawData);
1041
- let eventType;
1042
- if (rawEvent.header?.event_type) {
1043
- eventType = rawEvent.header.event_type;
1044
- } else if (rawEvent.schema) {
1045
- eventType = `lark.${rawEvent.schema}`;
1046
- } else if (rawEvent.type) {
1047
- eventType = rawEvent.type;
1048
- } else {
1049
- eventType = "unknown";
1050
- }
1051
- if (config.eventTypes?.length && !this.matchEventType(eventType, config.eventTypes)) {
1052
- return;
1053
- }
1054
- const { metadata, replyChannel, recommendedAction } = this.extractMetadata(config.type, rawEvent, eventType);
1055
- const message = this.formatEventMessage(config.type, rawEvent, eventType);
1056
- const event = {
1057
- sourceId,
1058
- type: eventType,
1059
- timestamp: Date.now(),
1060
- payload: {
1061
- sourceId,
1062
- sourceType: config.type,
1063
- rawEvent,
1064
- message,
1065
- metadata,
1066
- replyChannel,
1067
- recommendedAction,
1068
- timestamp: Date.now()
1069
- }
1070
- };
1071
- const handler = this.handlers.get(sourceId);
1072
- if (handler) {
1073
- try {
1074
- const result = handler(event);
1075
- if (result instanceof Promise) {
1076
- result.catch((error) => {
1077
- logger2.error(`[EventSource ${sourceId}] Handler error:`, error);
1078
- });
1079
- }
1080
- } catch (error) {
1081
- logger2.error(`[EventSource ${sourceId}] Handler error:`, error);
1082
- }
1083
- }
1084
- this.getEnv()?.pushEnvEvent({
1085
- type: `event-source.event.${config.type}`,
1086
- payload: event
1087
- });
1088
- } catch (error) {
1089
- if (error instanceof SyntaxError) {
1090
- logger2.debug(`[EventSource ${sourceId}] Non-JSON data: ${rawData.substring(0, 100)}`);
1091
- const config2 = this.sources.get(sourceId);
1092
- if (config2) {
1093
- const event = {
1094
- sourceId,
1095
- type: "raw",
1096
- timestamp: Date.now(),
1097
- payload: {
1098
- sourceId,
1099
- sourceType: config2.type,
1100
- rawEvent: rawData,
1101
- message: rawData,
1102
- metadata: {},
1103
- timestamp: Date.now()
1104
- }
1105
- };
1106
- const handler = this.handlers.get(sourceId);
1107
- if (handler) {
1108
- handler(event);
1109
- }
1110
- }
1111
- } else {
1112
- logger2.error(`[EventSource ${sourceId}] Failed to handle event:`, error);
1113
- }
1114
- }
1115
- }
1116
- matchEventType(eventType, patterns) {
1117
- for (const pattern of patterns) {
1118
- if (pattern === "*")
1119
- return true;
1120
- if (pattern.endsWith(".*")) {
1121
- const prefix = pattern.slice(0, -2);
1122
- if (eventType.startsWith(prefix + ".") || eventType === prefix)
1123
- return true;
1124
- }
1125
- if (eventType === pattern)
1126
- return true;
1127
- }
1128
- return false;
1129
- }
1130
- extractMetadata(sourceType, rawEvent, eventType) {
1131
- const event = rawEvent;
1132
- const metadata = {};
1133
- let replyChannel;
1134
- let recommendedAction;
1135
- switch (sourceType) {
1136
- case "lark-cli":
1137
- const larkInnerEvent = event.event;
1138
- const header = event.header;
1139
- const message = larkInnerEvent?.message || event.message;
1140
- const sender = larkInnerEvent?.sender || event.sender;
1141
- const senderId = sender?.sender_id;
1142
- if (header) {
1143
- metadata.eventType = header.event_type;
1144
- metadata.appId = header.app_id;
1145
- metadata.tenantKey = header.tenant_key;
1146
- }
1147
- if (message) {
1148
- metadata.chatId = message.chat_id;
1149
- metadata.chatType = message.chat_type;
1150
- metadata.messageId = message.message_id;
1151
- metadata.messageType = message.message_type;
1152
- }
1153
- if (senderId) {
1154
- metadata.senderId = senderId.open_id || senderId.user_id || senderId.union_id;
1155
- }
1156
- if (eventType === "im.message.receive_v1") {
1157
- replyChannel = {
1158
- type: "lark-cli",
1159
- appId: metadata.appId,
1160
- chatId: metadata.chatId,
1161
- messageId: metadata.messageId
1162
- };
1163
- recommendedAction = {
1164
- action: "处理飞书消息并回复",
1165
- replyTo: {
1166
- appId: metadata.appId,
1167
- chatId: metadata.chatId,
1168
- messageId: metadata.messageId
1169
- }
1170
- };
1171
- }
1172
- break;
1173
- case "timer":
1174
- metadata.eventType = "timer.tick";
1175
- recommendedAction = {
1176
- action: "执行定时任务"
1177
- };
1178
- break;
1179
- case "websocket":
1180
- metadata.eventType = eventType;
1181
- replyChannel = {
1182
- type: "websocket"
1183
- };
1184
- recommendedAction = {
1185
- action: "处理 WebSocket 消息"
1186
- };
1187
- break;
1188
- default:
1189
- metadata.eventType = eventType;
1190
- recommendedAction = {
1191
- action: "处理事件"
1192
- };
1193
- }
1194
- return { metadata, replyChannel, recommendedAction };
1195
- }
1196
- formatEventMessage(sourceType, rawEvent, eventType) {
1197
- const event = rawEvent;
1198
- switch (sourceType) {
1199
- case "lark-cli": {
1200
- const larkEvent = event;
1201
- const larkInnerEvent = larkEvent.event;
1202
- const larkMessage = larkInnerEvent?.message || larkEvent.message;
1203
- const larkSender = larkInnerEvent?.sender || larkEvent.sender;
1204
- if (larkMessage) {
1205
- const senderId = larkSender?.sender_id;
1206
- const openId = senderId?.open_id || senderId?.user_id || senderId?.email || senderId?.union_id || "未知用户";
1207
- let content = "无消息内容";
1208
- if (larkMessage.content) {
1209
- try {
1210
- const contentObj = JSON.parse(larkMessage.content);
1211
- content = contentObj.text || contentObj.content || larkMessage.content;
1212
- } catch {
1213
- content = larkMessage.content;
1214
- }
1215
- }
1216
- return `[飞书消息] ${openId}: ${content}`;
1217
- }
1218
- const larkSenderRecord = larkEvent.sender;
1219
- const senderIdRecord = larkSenderRecord?.sender_id;
1220
- if (larkEvent.message_id || larkEvent.schema?.includes("message")) {
1221
- const senderId = senderIdRecord?.open_id || senderIdRecord?.user_id || senderIdRecord?.email || senderIdRecord?.union_id || "未知用户";
1222
- const content = larkEvent.text || larkEvent.content || JSON.stringify(larkEvent);
1223
- return `[飞书消息] ${senderId}: ${content}`;
1224
- }
1225
- return `[飞书事件] ${eventType || larkEvent.schema || "unknown"}`;
1226
- }
1227
- case "timer": {
1228
- const timerEvent = event;
1229
- const timerMessage = timerEvent.payload?.message || timerEvent.message || "tick";
1230
- return `[定时任务] ${timerMessage}`;
1231
- }
1232
- case "websocket":
1233
- return `[WebSocket] ${JSON.stringify(rawEvent).substring(0, 200)}`;
1234
- default:
1235
- return `[${sourceType}] ${JSON.stringify(rawEvent).substring(0, 200)}`;
1236
- }
1237
- }
1238
- getConfigFilePath() {
1239
- if (this.configPath) {
1240
- return this.configPath;
1241
- }
1242
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
1243
- const dataDir = join(home, ".roy-agent");
1244
- if (!existsSync2(dataDir)) {
1245
- mkdirSync(dataDir, { recursive: true });
1246
- }
1247
- return join(dataDir, "event-sources.json");
1248
- }
1249
- async saveConfig() {
1250
- if (!this.persistenceEnabled) {
1251
- return;
1252
- }
1253
- try {
1254
- const configPath = this.getConfigFilePath();
1255
- const config = {
1256
- version: "1.0.0",
1257
- sources: Array.from(this.sources.values())
1258
- };
1259
- const content = JSON.stringify(config, null, 2);
1260
- writeFileSync(configPath, content, "utf-8");
1261
- logger2.debug(`Saved ${this.sources.size} event source configurations to ${configPath}`);
1262
- } catch (error) {
1263
- logger2.error("Failed to save event source configurations:", error);
1264
- throw error;
1265
- }
1266
- }
1267
- async loadConfig() {
1268
- if (!this.persistenceEnabled) {
1269
- return;
1270
- }
1271
- try {
1272
- const configPath = this.getConfigFilePath();
1273
- if (!existsSync2(configPath)) {
1274
- logger2.debug(`No event source config file found at ${configPath}`);
1275
- return;
1276
- }
1277
- const content = readFileSync2(configPath, "utf-8");
1278
- const config = JSON.parse(content);
1279
- if (!config.sources || !Array.isArray(config.sources)) {
1280
- logger2.warn("Invalid event source config format, skipping load");
1281
- return;
1282
- }
1283
- let loadedCount = 0;
1284
- for (const source of config.sources) {
1285
- if (!this.sources.has(source.id)) {
1286
- this.sources.set(source.id, source);
1287
- this.statuses.set(source.id, "created");
1288
- loadedCount++;
1289
- }
1290
- }
1291
- logger2.info(`Loaded ${loadedCount} event source configurations from ${configPath}`);
1292
- } catch (error) {
1293
- logger2.error("Failed to load event source configurations:", error);
1294
- }
1295
- }
1296
- }
1297
- // src/env/event-source/event-source-agent-handler.ts
1298
- init_logger();
1299
- var logger3 = createLogger("event-source-agent-handler");
1300
-
1301
- class EventSourceAgentHandler {
1302
- config;
1303
- constructor(config = {}) {
1304
- this.config = {
1305
- enabled: config.enabled ?? true,
1306
- prefix: config.prefix ?? "[事件源]",
1307
- includeRawEvent: config.includeRawEvent ?? false,
1308
- includeTimestamp: config.includeTimestamp ?? true
1309
- };
1310
- }
1311
- createHandler() {
1312
- return (event) => {
1313
- if (!this.config.enabled) {
1314
- return;
1315
- }
1316
- const message = this.formatEventForAgent(event);
1317
- logger3.debug(`[AgentHandler] Formatted event: ${message.substring(0, 100)}`);
1318
- return message;
1319
- };
1320
- }
1321
- formatEventForAgent(event) {
1322
- const parts = [];
1323
- parts.push(this.config.prefix);
1324
- if (this.config.includeTimestamp) {
1325
- const time = new Date(event.timestamp).toLocaleString("zh-CN");
1326
- parts.push(`[${time}]`);
1327
- }
1328
- parts.push(`来源: ${event.payload.sourceType}`);
1329
- parts.push(`类型: ${event.type}`);
1330
- parts.push(`内容: ${event.payload.message}`);
1331
- if (this.config.includeRawEvent) {
1332
- const rawStr = typeof event.payload.rawEvent === "string" ? event.payload.rawEvent : JSON.stringify(event.payload.rawEvent);
1333
- parts.push(`原始数据: ${rawStr}`);
1334
- }
1335
- return parts.join(" ");
1336
- }
1337
- updateConfig(config) {
1338
- this.config = {
1339
- ...this.config,
1340
- ...config
1341
- };
1342
- }
1343
- getConfig() {
1344
- return { ...this.config };
1345
- }
1346
- }
1347
- // src/env/event-source/types.ts
1348
- function isValidEventSourceType(type) {
1349
- return ["lark-cli", "websocket", "timer", "http-webhook", "file-watcher"].includes(type);
1350
- }
1351
- function getDefaultConfigForType(type) {
1352
- switch (type) {
1353
- case "timer":
1354
- return { interval: 60000 };
1355
- case "lark-cli":
1356
- return { command: "lark-cli event +subscribe" };
1357
- case "websocket":
1358
- return {};
1359
- default:
1360
- return {};
1361
- }
1362
- }
1363
- function validateEventSourceConfig(config) {
1364
- const errors = [];
1365
- if (!config.id) {
1366
- errors.push("EventSource ID is required");
1367
- }
1368
- if (!config.name) {
1369
- errors.push("EventSource name is required");
1370
- }
1371
- if (!isValidEventSourceType(config.type)) {
1372
- errors.push(`Invalid EventSource type: ${config.type}`);
1373
- }
1374
- if (config.type === "timer") {
1375
- if (!config.interval || config.interval <= 0) {
1376
- errors.push("Timer interval must be a positive number");
1377
- }
1378
- }
1379
- if (config.type === "lark-cli" && !config.command) {
1380
- errors.push("lark-cli command is required");
1381
- }
1382
- if (config.type === "websocket" && !config.url) {
1383
- errors.push("WebSocket URL is required");
1384
- }
1385
- return errors;
1386
- }
1387
- export { generateId, generateDescendingId, BaseEnvironment, EventSourceComponent, EventSourceAgentHandler, isValidEventSourceType, getDefaultConfigForType, validateEventSourceConfig };