@ai-setting/roy-agent-core 1.7.66 → 1.7.67

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 (37) hide show
  1. package/dist/env/agent/agent-component.d.ts +29 -0
  2. package/dist/env/agent/agent-component.js +1 -1
  3. package/dist/env/agent/index.js +1 -1
  4. package/dist/env/agent/types.d.ts +16 -0
  5. package/dist/env/environment.d.ts +13 -0
  6. package/dist/env/event-source/event-source-handlers.js +4 -3
  7. package/dist/env/event-source/index.js +5 -4
  8. package/dist/env/event-source/timer-handler.d.ts +93 -1
  9. package/dist/env/index.js +10 -9
  10. package/dist/env/prompt/index.js +3 -2
  11. package/dist/env/prompt/prompts-index.d.ts +2 -7
  12. package/dist/env/task/delegate/delegate-tool.d.ts +21 -1
  13. package/dist/env/task/delegate/delegate-tool.js +3 -2
  14. package/dist/env/task/delegate/index.js +3 -2
  15. package/dist/env/task/index.js +5 -4
  16. package/dist/env/task/mcp/index.js +2 -1
  17. package/dist/env/task/plugins/__e2e__/laya-completion-e2e.d.ts +16 -0
  18. package/dist/env/task/plugins/index.js +3 -2
  19. package/dist/env/task/plugins/laya-completion-plugin.d.ts +133 -0
  20. package/dist/env/task/plugins/laya-port.d.ts +23 -0
  21. package/dist/env/task/task-component.d.ts +43 -0
  22. package/dist/env/task/tools/completion-copy.d.ts +27 -0
  23. package/dist/env/task/tools/index.js +2 -1
  24. package/dist/index.js +11 -10
  25. package/dist/shared/@ai-setting/{roy-agent-core-nr2m4xw1.js → roy-agent-core-1k83dq3a.js} +13 -3
  26. package/dist/shared/@ai-setting/{roy-agent-core-4882qsjx.js → roy-agent-core-1kxf910n.js} +1 -1
  27. package/dist/shared/@ai-setting/roy-agent-core-6m4bw8jy.js +6 -0
  28. package/dist/shared/@ai-setting/roy-agent-core-8zas6w5q.js +1083 -0
  29. package/dist/shared/@ai-setting/{roy-agent-core-v8bz7d8x.js → roy-agent-core-b7jbqfsy.js} +24 -10
  30. package/dist/shared/@ai-setting/{roy-agent-core-2wxbx36p.js → roy-agent-core-dnjm17sa.js} +21 -2
  31. package/dist/shared/@ai-setting/{roy-agent-core-t0ktaevq.js → roy-agent-core-h5vmff8w.js} +60 -4
  32. package/dist/shared/@ai-setting/{roy-agent-core-j1kksatb.js → roy-agent-core-hfr6bzts.js} +67 -10
  33. package/dist/shared/@ai-setting/{roy-agent-core-8nksrtnf.js → roy-agent-core-k4ps1hxp.js} +201 -16
  34. package/dist/shared/@ai-setting/{roy-agent-core-vs5gxgwh.js → roy-agent-core-ma35jyd9.js} +14 -3
  35. package/dist/shared/@ai-setting/{roy-agent-core-cvm1xgmg.js → roy-agent-core-wksgtqf9.js} +1 -1
  36. package/package.json +1 -1
  37. package/dist/shared/@ai-setting/roy-agent-core-8mjnb7xc.js +0 -654
@@ -0,0 +1,1083 @@
1
+ import {
2
+ LayaDecisionPort,
3
+ createAutoTaskPlugin,
4
+ createLayaDecisionPlugin,
5
+ loadLayaAuthForPurpose,
6
+ pickGateConfidence
7
+ } from "./roy-agent-core-b7jbqfsy.js";
8
+ import {
9
+ TaskHookPoints
10
+ } from "./roy-agent-core-1pg0fepg.js";
11
+ import {
12
+ ContextError,
13
+ ErrorCodes
14
+ } from "./roy-agent-core-ctdhjv68.js";
15
+ import {
16
+ BaseComponent
17
+ } from "./roy-agent-core-pgvcf91v.js";
18
+ import {
19
+ init_hook
20
+ } from "./roy-agent-core-ax9e9szb.js";
21
+ import {
22
+ init_context
23
+ } from "./roy-agent-core-qqaak24r.js";
24
+ import {
25
+ getEnvContext,
26
+ init_env_context,
27
+ runWithEnvContextAsync
28
+ } from "./roy-agent-core-7cbpmk4q.js";
29
+ import {
30
+ TracedAs,
31
+ envQueryParamFilter,
32
+ init_decorator,
33
+ init_trace_filters
34
+ } from "./roy-agent-core-qq96p0tj.js";
35
+ import {
36
+ createLogger,
37
+ init_logger
38
+ } from "./roy-agent-core-7f7t9wwp.js";
39
+ import {
40
+ __legacyDecorateClassTS
41
+ } from "./roy-agent-core-fs0mn2jk.js";
42
+
43
+ // src/env/environment.ts
44
+ init_logger();
45
+
46
+ // src/utils/id.ts
47
+ function generateId(prefix = "id") {
48
+ const timestamp = Date.now().toString(36);
49
+ const random = Math.random().toString(36).substring(2, 11);
50
+ return `${prefix}_${timestamp}_${random}`;
51
+ }
52
+ function generateDescendingId(prefix = "id") {
53
+ const timestamp = (Number.MAX_SAFE_INTEGER - Date.now()).toString(36);
54
+ const random = Math.random().toString(36).substring(2, 11);
55
+ return `${prefix}_${timestamp}_${random}`;
56
+ }
57
+
58
+ // src/env/environment.ts
59
+ init_decorator();
60
+ init_trace_filters();
61
+ init_env_context();
62
+ import * as fsSync from "fs";
63
+ import * as path from "path";
64
+
65
+ // src/env/task/plugins/laya-completion-plugin.ts
66
+ init_logger();
67
+ init_decorator();
68
+ var logger = createLogger("plugin:laya-completion");
69
+ var LAYA_COMPLETION_THRESHOLD = 0.92;
70
+ var CHOICE_PASS = "PASS_COMPLETED";
71
+ var CHOICE_FAIL = "FAIL_INCOMPLETE";
72
+ var MAX_OPERATIONS_IN_STATE = 20;
73
+ var OP_TITLE_MAX = 60;
74
+ var OP_DESC_MAX = 120;
75
+ var GOALS_MAX = 400;
76
+ function buildCompletionHint(task, confidence) {
77
+ return [
78
+ "[TASK_COMPLETION_HINT] 决策模型检测到「目标 vs 交付物」可能不匹配:任务已标记完成,但操作记录链显示目标或交付物可能未达成。",
79
+ "",
80
+ `任务:#${task.id} [${task.type}] ${task.title}`,
81
+ `状态:${task.status} | 判定置信度:${confidence.toFixed(4)}`,
82
+ "",
83
+ "⚠️ 你必须核实本提示:先用 task_get(task_id=" + task.id + ") 复核任务的目标(description / goals_and_expected_deliverables)与交付物证据(context.deliverable_storage_path、操作记录链)。",
84
+ "核实后二选一执行:",
85
+ "(a) 确认未完成 → task_update(task_id=" + task.id + ", status=todo) 重开任务继续推进;",
86
+ "(b) 确认已完成 → task_operation_create(task_id=" + task.id + ", milestone_type=decision, ...) 落一条操作记录说明已完成的理由。",
87
+ "不允许无视本提示。"
88
+ ].join(`
89
+ `);
90
+ }
91
+ function renderOperations(ops) {
92
+ if (ops.length === 0)
93
+ return "(无操作记录)";
94
+ const sorted = [...ops].sort((a, b) => new Date(a.timestamp ?? 0).getTime() - new Date(b.timestamp ?? 0).getTime());
95
+ let windowed;
96
+ if (sorted.length <= MAX_OPERATIONS_IN_STATE) {
97
+ windowed = sorted;
98
+ } else {
99
+ const tail = sorted.slice(-(MAX_OPERATIONS_IN_STATE - 1));
100
+ const head = sorted.slice(0, 1);
101
+ const seen = new Set(tail.map((o) => o.id));
102
+ windowed = seen.has(head[0].id) ? tail : [...head, ...tail];
103
+ }
104
+ return windowed.map((op, i) => {
105
+ const title = (op.milestoneTitle || "").slice(0, OP_TITLE_MAX);
106
+ const desc = (op.milestoneDescription || "").replace(/\n/g, " ").slice(0, OP_DESC_MAX);
107
+ const proc = (op.processDescription || "").replace(/\n/g, " ").slice(0, OP_DESC_MAX);
108
+ const parts = [`#${i + 1} [${op.milestoneType}] ${title}`];
109
+ if (desc)
110
+ parts.push(` ${desc}`);
111
+ if (proc)
112
+ parts.push(` 过程:${proc}`);
113
+ return parts.join(`
114
+ `);
115
+ }).join(`
116
+ `);
117
+ }
118
+ function readDeliverablePath(task) {
119
+ try {
120
+ const parsed = JSON.parse(task.context || "{}");
121
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
122
+ const p = parsed.deliverable_storage_path;
123
+ return typeof p === "string" ? p : "";
124
+ }
125
+ } catch {}
126
+ return "";
127
+ }
128
+ function looksLikeFilePath(token) {
129
+ if (token.startsWith("//"))
130
+ return false;
131
+ if ((token.match(/\//g) ?? []).length >= 2)
132
+ return true;
133
+ return /\.[A-Za-z0-9]+$/.test(token);
134
+ }
135
+ function firstPathToken(text) {
136
+ const m = text.match(/(?:^|[\s((【「::,,])(\/[A-Za-z0-9._~\-/@%+]{2,})/);
137
+ if (!m)
138
+ return null;
139
+ return looksLikeFilePath(m[1]) ? m[1] : null;
140
+ }
141
+ var CHECKLIST_MAX = 1200;
142
+ var DELIVERABLE_SPLIT = /[,,;;、\n]/;
143
+ var DELIVERABLE_PLUS_SPLIT = /\s\+\s/;
144
+ function stripDeliverableToken(t) {
145
+ const seg = t.trim();
146
+ if (!seg)
147
+ return null;
148
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(seg))
149
+ return null;
150
+ const m = seg.match(/(?:^|[\s((【「::,,])(\/[A-Za-z0-9._~\-/@%+]{2,})/);
151
+ if (!m)
152
+ return null;
153
+ const path = m[1].replace(/[。,、;:)】」"'”’.,;:!?)\]}]+$/u, "");
154
+ return path.startsWith("/") ? path : null;
155
+ }
156
+ function isUrlSegment(seg) {
157
+ return /^[a-z][a-z0-9+.-]*:\/\//i.test(seg.trim());
158
+ }
159
+ function splitDeliverableSegments(deliverable) {
160
+ return deliverable.split(DELIVERABLE_PLUS_SPLIT).flatMap((s) => s.split(DELIVERABLE_SPLIT)).flatMap((s) => splitUrlSegments(s)).flatMap((s) => splitSpaceSeparatedPaths(s)).map((s) => s.trim()).filter(Boolean);
161
+ }
162
+ function splitUrlSegments(seg) {
163
+ const re = /([a-z][a-z0-9+.-]*:\/\/\S+)/gi;
164
+ const parts = [];
165
+ let last = 0;
166
+ let m;
167
+ while ((m = re.exec(seg)) !== null) {
168
+ const before = seg.slice(last, m.index).trim();
169
+ if (before)
170
+ parts.push(before);
171
+ const url = m[1];
172
+ if (/^file:\/\//i.test(url)) {
173
+ const local = url.replace(/^file:\/\//i, "");
174
+ if (local)
175
+ parts.push(local);
176
+ } else {
177
+ parts.push(url);
178
+ }
179
+ last = m.index + url.length;
180
+ }
181
+ const rest = seg.slice(last).trim();
182
+ if (rest)
183
+ parts.push(rest);
184
+ return parts.length > 0 ? parts : [seg];
185
+ }
186
+ function spaceSeparatedPathStarts(seg) {
187
+ const re = /(?:^|[\s((【「::,,])(\/[A-Za-z0-9._~\-/@%+]{2,})/g;
188
+ const starts = [];
189
+ let m;
190
+ while ((m = re.exec(seg)) !== null) {
191
+ const pathStart = m[0].startsWith("/") ? m.index : m.index + 1;
192
+ if (m[1].startsWith("//"))
193
+ continue;
194
+ starts.push(pathStart);
195
+ }
196
+ return starts;
197
+ }
198
+ function splitSpaceSeparatedPaths(seg) {
199
+ const starts = spaceSeparatedPathStarts(seg);
200
+ if (starts.length < 2)
201
+ return [seg];
202
+ const parts = [seg.slice(0, starts[1])];
203
+ for (let i = 1;i < starts.length; i++) {
204
+ const end = i + 1 < starts.length ? starts[i + 1] : seg.length;
205
+ parts.push(seg.slice(starts[i], end));
206
+ }
207
+ return parts;
208
+ }
209
+ function isPathLikeDeliverable(deliverable) {
210
+ if (!deliverable.includes("/"))
211
+ return false;
212
+ const segs = splitDeliverableSegments(deliverable);
213
+ if (segs.length === 0)
214
+ return false;
215
+ const paths = segs.map(stripDeliverableToken).filter((p) => p !== null);
216
+ if (paths.length === 0)
217
+ return false;
218
+ return segs.every((s, i) => stripDeliverableToken(s) !== null || isUrlSegment(s));
219
+ }
220
+ function renderCriteriaChecklist(goalsText, deliverable) {
221
+ if (!deliverable || deliverable === "(未声明)")
222
+ return null;
223
+ if (!isPathLikeDeliverable(deliverable))
224
+ return null;
225
+ const items = goalsText.split(`
226
+ `).map((l) => l.trim()).filter((l) => /^\d+\s*[.、))]/.test(l));
227
+ if (items.length === 0)
228
+ return null;
229
+ const tokens = items.map(firstPathToken);
230
+ if (tokens.some((t) => t === null))
231
+ return null;
232
+ const declared = splitDeliverableSegments(deliverable).map(stripDeliverableToken).filter((t) => t !== null);
233
+ const declaredSet = new Set(declared);
234
+ const lines = items.map((item, i) => {
235
+ const token = tokens[i];
236
+ const done = declaredSet.has(token);
237
+ const origNum = item.match(/^(\d+)\s*[.、))]/)?.[1] ?? String(i + 1);
238
+ return done ? `${origNum}. ${token} 已产出` : `${origNum}. ${token} 未产出`;
239
+ });
240
+ const anyUndone = tokens.some((t) => !declaredSet.has(t));
241
+ const raw = `【逐条对照】${lines.join(";")},目标${anyUndone ? "未完成" : "全部完成"}`;
242
+ if (raw.length > CHECKLIST_MAX) {
243
+ const suffix = `目标${anyUndone ? "未完成" : "全部完成"}`;
244
+ const head = raw.slice(0, CHECKLIST_MAX - suffix.length - 2);
245
+ const lastSep = head.lastIndexOf(";");
246
+ const cut = lastSep > 0 ? head.slice(0, lastSep) : head;
247
+ return `${cut};…,${suffix}`;
248
+ }
249
+ return raw;
250
+ }
251
+ function renderCompletionState(task, ops) {
252
+ const goals = (task.goals_and_expected_deliverables || "(无)").replace(/\n/g, " ").slice(0, GOALS_MAX);
253
+ const deliverable = readDeliverablePath(task) || "(未声明)";
254
+ const checklist = renderCriteriaChecklist(task.goals_and_expected_deliverables || "", deliverable);
255
+ return `【任务标题】${task.title}
256
+ ` + `【任务目标】${goals}
257
+ ` + `【交付物声明】${deliverable}
258
+ ` + (checklist ? `${checklist}
259
+ ` : "") + `【操作记录】
260
+ ` + renderOperations(ops);
261
+ }
262
+ function buildCompletionQuestion() {
263
+ return {
264
+ completion_check: {
265
+ type: "choice",
266
+ instructions: "根据任务目标、交付物声明与操作记录链,判断该任务是否真正达成目标且产出交付物。" + `若证据充分支持已完成,选 ${CHOICE_PASS};若目标或交付物疑似未达成,选 ${CHOICE_FAIL}。`,
267
+ criteria: {
268
+ [CHOICE_PASS]: "目标已达成且交付物已产出",
269
+ [CHOICE_FAIL]: "目标或交付物疑似未达成"
270
+ }
271
+ }
272
+ };
273
+ }
274
+
275
+ class LayaCompletionPlugin {
276
+ name = "laya-completion";
277
+ version = "1.0.0";
278
+ description = "Task #4760 — task:after.complete 完成判定(目标/交付物 match,只提示不拦截)";
279
+ options;
280
+ port = null;
281
+ portResolved = false;
282
+ constructor(options = {}) {
283
+ this.options = options;
284
+ if (options.decisionPort) {
285
+ this.port = options.decisionPort;
286
+ this.portResolved = true;
287
+ }
288
+ }
289
+ isDisabled() {
290
+ return this.port?.isDisabled() ?? false;
291
+ }
292
+ async resolvePort() {
293
+ if (this.portResolved)
294
+ return this.port;
295
+ this.portResolved = true;
296
+ try {
297
+ const auth = await loadLayaAuthForPurpose(this.options.authPath ?? `${process.env.HOME ?? "~"}/.roy-agent/auth.json`, "goal");
298
+ if (!auth)
299
+ return null;
300
+ this.port = new LayaDecisionPort({
301
+ baseURL: auth.baseURL,
302
+ apiKey: auth.apiKey,
303
+ model: auth.model,
304
+ timeoutMs: this.options.timeoutMs,
305
+ maxStrikes: this.options.maxStrikes
306
+ });
307
+ } catch (err) {
308
+ logger.warn(`[laya-completion] loadLayaAuth failed (fail-open): ${err?.message}`);
309
+ this.port = null;
310
+ }
311
+ return this.port;
312
+ }
313
+ async execute(ctx, taskComponent) {
314
+ try {
315
+ const data = normalizeHookCtx(ctx);
316
+ await this.run(data, taskComponent);
317
+ } catch (err) {
318
+ logger.warn(`[laya-completion] unexpected failure, ignored: ${err?.message}`);
319
+ }
320
+ }
321
+ async run(ctx, taskComponent) {
322
+ if (!taskComponent) {
323
+ logger.warn("[laya-completion] taskComponent not injected — skip");
324
+ return;
325
+ }
326
+ if (ctx.terminalStatus !== "completed") {
327
+ logger.debug(`[laya-completion] terminalStatus=${ctx.terminalStatus} — skip (only completed)`);
328
+ return;
329
+ }
330
+ const task = ctx.task;
331
+ if (!task?.id)
332
+ return;
333
+ let ops = [];
334
+ try {
335
+ ops = await taskComponent.listOperations({
336
+ taskId: task.id,
337
+ limit: 1e6,
338
+ offset: 0
339
+ });
340
+ } catch (err) {
341
+ logger.warn(`[laya-completion] listOperations failed (fail-open): ${err?.message}`);
342
+ return;
343
+ }
344
+ logger.info(`[laya-completion] judging task #${task.id}: chain=${ops?.length ?? 0} ops, terminalStatus=${ctx.terminalStatus}`);
345
+ if (!ops || ops.length === 0) {
346
+ logger.debug("[laya-completion] empty operation chain — pass through");
347
+ return;
348
+ }
349
+ const port = await this.resolvePort();
350
+ if (!port) {
351
+ logger.debug("[laya-completion] no decision port configured — skip");
352
+ return;
353
+ }
354
+ if (port.isDisabled()) {
355
+ logger.debug("[laya-completion] port self-disabled (circuit open) — skip");
356
+ return;
357
+ }
358
+ const req = {
359
+ state: renderCompletionState(task, ops),
360
+ questions: buildCompletionQuestion()
361
+ };
362
+ let answer;
363
+ try {
364
+ const res = await port.decide(req);
365
+ answer = res?.answers?.["completion_check"];
366
+ } catch (err) {
367
+ logger.warn(`[laya-completion] decide failed (fail-open): ${err?.message}`);
368
+ return;
369
+ }
370
+ if (!answer || typeof answer.choice !== "string") {
371
+ logger.debug("[laya-completion] malformed answer — skip");
372
+ return;
373
+ }
374
+ const confidence = pickGateConfidence(answer);
375
+ const threshold = this.options.completionThreshold ?? LAYA_COMPLETION_THRESHOLD;
376
+ if (confidence < threshold) {
377
+ logger.debug(`[laya-completion] confidence ${confidence} < ${threshold} — pass through`);
378
+ return;
379
+ }
380
+ if (answer.choice !== CHOICE_FAIL) {
381
+ logger.debug(`[laya-completion] choice=${answer.choice} (not FAIL_INCOMPLETE) — no hint`);
382
+ return;
383
+ }
384
+ await this.writeHint(task, confidence, taskComponent);
385
+ }
386
+ async writeHint(task, confidence, taskComponent) {
387
+ const hint = buildCompletionHint(task, confidence);
388
+ try {
389
+ let parsed = {};
390
+ try {
391
+ const p = JSON.parse(task.context || "{}");
392
+ if (p && typeof p === "object" && !Array.isArray(p)) {
393
+ parsed = p;
394
+ }
395
+ } catch {}
396
+ parsed.completion_hint = hint;
397
+ await taskComponent.updateTaskContext(task.id, JSON.stringify(parsed));
398
+ logger.info(`[laya-completion] hint written to task #${task.id} context (conf=${confidence.toFixed(4)})`);
399
+ } catch (err) {
400
+ logger.warn(`[laya-completion] updateTask hint failed (ignored): ${err?.message}`);
401
+ }
402
+ try {
403
+ await taskComponent.createOperation({
404
+ taskId: task.id,
405
+ sessionId: "laya-completion",
406
+ milestoneType: "decision",
407
+ milestoneTitle: "[TASK_COMPLETION_HINT] 目标/交付物疑似未达成",
408
+ milestoneDescription: `决策模型判定 FAIL_INCOMPLETE(conf=${confidence.toFixed(4)})。hint 已写入 task.context.completion_hint,等待 agent 核实。`
409
+ });
410
+ } catch (err) {
411
+ logger.warn(`[laya-completion] createOperation hint failed (ignored): ${err?.message}`);
412
+ }
413
+ }
414
+ }
415
+ __legacyDecorateClassTS([
416
+ TracedAs("task.laya.completion.onAfterComplete", {
417
+ recordParams: false,
418
+ recordResult: false,
419
+ log: false,
420
+ paramFilter: (args) => {
421
+ const raw = args[0] ?? {};
422
+ const ctx = raw?.data ?? raw;
423
+ return {
424
+ taskId: ctx?.task?.id,
425
+ terminalStatus: ctx?.terminalStatus,
426
+ hasTaskComponent: Boolean(args[1])
427
+ };
428
+ },
429
+ resultFilter: (_res) => ({ ok: true })
430
+ })
431
+ ], LayaCompletionPlugin.prototype, "execute", null);
432
+ function normalizeHookCtx(ctx) {
433
+ const maybe = ctx;
434
+ return maybe && typeof maybe === "object" && maybe.data ? maybe.data : ctx;
435
+ }
436
+ function createLayaCompletionPlugin(options) {
437
+ const inner = options && Object.keys(options).length > 0 ? new LayaCompletionPlugin(options) : getSharedCompletionPlugin();
438
+ return {
439
+ name: "laya-completion",
440
+ priority: 20,
441
+ execute: async (ctx) => {
442
+ await inner.execute(ctx, inner.__taskComponent);
443
+ },
444
+ plugin: inner
445
+ };
446
+ }
447
+ var sharedCompletionPlugin = null;
448
+ function getSharedCompletionPlugin() {
449
+ if (!sharedCompletionPlugin) {
450
+ sharedCompletionPlugin = new LayaCompletionPlugin;
451
+ }
452
+ return sharedCompletionPlugin;
453
+ }
454
+ function registerLayaCompletionTaskHook(taskComponent, options) {
455
+ if (!taskComponent) {
456
+ logger.warn("[registerLayaCompletionTaskHook] TaskComponent not available — skip (fail-open)");
457
+ return false;
458
+ }
459
+ try {
460
+ const hook = createLayaCompletionPlugin(options);
461
+ hook.plugin.__taskComponent = taskComponent;
462
+ taskComponent.unregisterHook(TaskHookPoints.AFTER_COMPLETE, hook.name);
463
+ taskComponent.registerHook(TaskHookPoints.AFTER_COMPLETE, {
464
+ name: hook.name,
465
+ priority: hook.priority,
466
+ execute: async (ctx) => {
467
+ try {
468
+ const data = ctx && typeof ctx === "object" && "data" in ctx ? ctx.data : ctx;
469
+ await hook.plugin.execute(data, taskComponent);
470
+ } catch (err) {
471
+ logger.warn(`[registerLayaCompletionTaskHook] hook execution failed (ignored): ${err?.message}`);
472
+ }
473
+ }
474
+ });
475
+ logger.info(`[registerLayaCompletionTaskHook] registered hook "${hook.name}" at ${TaskHookPoints.AFTER_COMPLETE} (priority=${hook.priority})`);
476
+ return true;
477
+ } catch (err) {
478
+ logger.warn(`[registerLayaCompletionTaskHook] registration failed (ignored): ${err?.message}`);
479
+ return false;
480
+ }
481
+ }
482
+
483
+ // src/env/environment.ts
484
+ var logger2 = createLogger("environment");
485
+ function registerLayaDecisionTaskHook(taskComponent, options) {
486
+ if (!taskComponent) {
487
+ logger2.warn("[registerLayaDecisionTaskHook] TaskComponent not available — skip (fail-open)");
488
+ return false;
489
+ }
490
+ try {
491
+ const hook = createLayaDecisionPlugin(options);
492
+ taskComponent.unregisterHook(TaskHookPoints.BEFORE_CREATE, hook.name);
493
+ taskComponent.registerHook(TaskHookPoints.BEFORE_CREATE, {
494
+ name: hook.name,
495
+ priority: hook.priority,
496
+ execute: async (ctx) => {
497
+ try {
498
+ const data = ctx && typeof ctx === "object" && "data" in ctx ? ctx.data : ctx;
499
+ await hook.execute(data);
500
+ } catch (err) {
501
+ logger2.warn(`[registerLayaDecisionTaskHook] hook execution failed (ignored): ${err?.message}`);
502
+ }
503
+ }
504
+ });
505
+ logger2.info(`[registerLayaDecisionTaskHook] registered hook "${hook.name}" at ${TaskHookPoints.BEFORE_CREATE} (priority=${hook.priority})`);
506
+ return true;
507
+ } catch (err) {
508
+ logger2.warn(`[registerLayaDecisionTaskHook] registration failed (ignored): ${err?.message}`);
509
+ return false;
510
+ }
511
+ }
512
+ var DEFAULT_AGENT_NAME = "Roy";
513
+ function injectAgentNamePlaceholder(prompt, context) {
514
+ if (!prompt.includes("{{agent_name}}")) {
515
+ return prompt;
516
+ }
517
+ const metadata = context?.metadata;
518
+ const defaultAgentName = typeof metadata?.defaultAgentName === "string" && metadata.defaultAgentName.length > 0 ? metadata.defaultAgentName : DEFAULT_AGENT_NAME;
519
+ return prompt.replace(/\{\{agent_name\}\}/g, defaultAgentName);
520
+ }
521
+
522
+ class BaseEnvironment extends BaseComponent {
523
+ name;
524
+ version;
525
+ components = new Map;
526
+ constructor(config) {
527
+ super();
528
+ this.name = config?.name ?? "base-environment";
529
+ this.version = config?.version ?? "1.0.0";
530
+ this.registerDefaultComponents();
531
+ }
532
+ registerDefaultComponents() {}
533
+ getConfig() {
534
+ return {
535
+ name: this.name,
536
+ version: this.version,
537
+ enabled: true,
538
+ env: this
539
+ };
540
+ }
541
+ registerComponent(component) {
542
+ this.components.set(component.name, component);
543
+ logger2.debug(`Component registered: ${component.name}`);
544
+ }
545
+ unregisterComponent(name) {
546
+ const component = this.components.get(name);
547
+ if (component) {
548
+ this.components.delete(name);
549
+ logger2.debug(`Component unregistered: ${name}`);
550
+ }
551
+ }
552
+ getComponent(name) {
553
+ return this.components.get(name);
554
+ }
555
+ listComponents() {
556
+ return Array.from(this.components.values());
557
+ }
558
+ async handle_query(query, context) {
559
+ const agentComponent = this.getComponent("agent");
560
+ if (!agentComponent) {
561
+ throw new Error("AgentComponent not found. Please register AgentComponent before calling handle_query.");
562
+ }
563
+ const agentName = context?.agentType && context.agentType !== "default" ? context.agentType : "default";
564
+ const registry = agentComponent.getRegistry?.();
565
+ if (registry) {
566
+ const agentDef = registry.get(agentName);
567
+ if (agentDef?.type === "workflow") {
568
+ const existingCtx = getEnvContext();
569
+ const workflowEnvContext = {
570
+ envEvent: context || { type: "workflow" },
571
+ sourceId: "workflow",
572
+ userId: context?.metadata?.userId || "",
573
+ replyChannel: existingCtx?.replyChannel,
574
+ pluginEnabled: existingCtx?.pluginEnabled,
575
+ agentContext: existingCtx?.agentContext ?? {}
576
+ };
577
+ return await runWithEnvContextAsync(workflowEnvContext, async () => {
578
+ return await this.handleWorkflowAgentQuery(agentName, query, agentComponent, context);
579
+ });
580
+ }
581
+ }
582
+ let systemPrompt = "You are a helpful assistant.";
583
+ let promptSource = "fallback";
584
+ try {
585
+ const promptComponent = this.getComponent("prompt");
586
+ if (promptComponent) {
587
+ const loadedPrompt = await promptComponent.getPrompt("default", {}, {
588
+ agentType: "primary"
589
+ });
590
+ if (loadedPrompt) {
591
+ systemPrompt = loadedPrompt;
592
+ promptSource = "PromptComponent";
593
+ }
594
+ }
595
+ } catch (err) {
596
+ logger2.warn(`[handle_query] Failed to get prompt from PromptComponent: ${err}`);
597
+ }
598
+ logger2.info(`[handle_query] Using system prompt from ${promptSource}, length: ${systemPrompt.length}`);
599
+ let finalSystemPrompt = systemPrompt;
600
+ if (systemPrompt.includes("{{memory}}")) {
601
+ try {
602
+ const memoryComponent = this.getComponent("memory");
603
+ if (memoryComponent) {
604
+ const memoryContent = await memoryComponent.recallMemory();
605
+ finalSystemPrompt = systemPrompt.replace("{{memory}}", memoryContent || "(No memory)");
606
+ logger2.info(`[handle_query] Injected memory content, length: ${memoryContent.length}`);
607
+ } else {
608
+ finalSystemPrompt = systemPrompt.replace("{{memory}}", "(Memory component not available)");
609
+ }
610
+ } catch (err) {
611
+ logger2.warn(`[handle_query] Failed to load memory content: ${err}`);
612
+ finalSystemPrompt = systemPrompt.replace("{{memory}}", "(Failed to load memory)");
613
+ }
614
+ }
615
+ if (finalSystemPrompt.includes("{{workspace_dir}}")) {
616
+ const workspaceDir = process.cwd();
617
+ finalSystemPrompt = finalSystemPrompt.replace("{{workspace_dir}}", workspaceDir);
618
+ logger2.debug(`[handle_query] Injected workspace_dir: ${workspaceDir}`);
619
+ }
620
+ {
621
+ const prev = finalSystemPrompt;
622
+ finalSystemPrompt = injectAgentNamePlaceholder(finalSystemPrompt, context);
623
+ if (prev !== finalSystemPrompt) {
624
+ const metadata = context?.metadata;
625
+ const injectedName = typeof metadata?.defaultAgentName === "string" && metadata.defaultAgentName.length > 0 ? metadata.defaultAgentName : DEFAULT_AGENT_NAME;
626
+ logger2.debug(`[handle_query] Injected agent_name: ${injectedName}`);
627
+ }
628
+ }
629
+ let agent = agentComponent.getAgent(agentName);
630
+ if (!agent) {
631
+ if (agentName !== "default") {
632
+ logger2.warn(`[handle_query] Agent "${agentName}" not found, falling back to "default"`);
633
+ }
634
+ agent = agentComponent.getAgent("default");
635
+ }
636
+ if (!agent) {
637
+ const defaultDeniedTools = [
638
+ "echo",
639
+ "glob",
640
+ "grep",
641
+ "write_file",
642
+ "edit_file",
643
+ "task_create",
644
+ "task_update",
645
+ "task_delete",
646
+ "task_complete",
647
+ "task_operation_create",
648
+ "task_operation_update",
649
+ "task_operation_delete",
650
+ "skill",
651
+ "record_memory",
652
+ "recall_memory",
653
+ "search_sessions",
654
+ "get_session",
655
+ "write_memory"
656
+ ];
657
+ try {
658
+ const toolComponent = this.getComponent("tool");
659
+ if (toolComponent?.listTools) {
660
+ const allTools = toolComponent.listTools();
661
+ const mcpTools = allTools.filter((t) => t.name.startsWith("mcp_")).map((t) => t.name);
662
+ if (mcpTools.length > 0) {
663
+ defaultDeniedTools.push(...mcpTools);
664
+ logger2.debug(`[handle_query] Dynamically denied MCP tools: ${mcpTools.join(", ")}`);
665
+ }
666
+ }
667
+ } catch (err) {
668
+ logger2.warn(`[handle_query] Failed to dynamically filter MCP tools: ${err}`);
669
+ }
670
+ agent = agentComponent.registerAgent("default", {
671
+ type: "primary",
672
+ systemPrompt: finalSystemPrompt,
673
+ deniedTools: defaultDeniedTools
674
+ });
675
+ logger2.info(`[handle_query] Created default receptionist agent with deniedTools: ${defaultDeniedTools.length} tools denied`);
676
+ try {
677
+ const autoTaskPlugin = createAutoTaskPlugin({
678
+ threshold: 20
679
+ });
680
+ agentComponent.registerPlugin("default", autoTaskPlugin);
681
+ logger2.info("[handle_query] AutoTaskPlugin v5.0 registered on default agent (threshold=20)");
682
+ } catch (err) {
683
+ logger2.warn(`[handle_query] Failed to register AutoTaskPlugin: ${err}`);
684
+ }
685
+ } else {
686
+ if (agent.config?.systemPrompt) {
687
+ if (agent.config.systemPrompt.includes("{{memory}}")) {
688
+ try {
689
+ const memoryComponent = this.getComponent("memory");
690
+ if (memoryComponent) {
691
+ const memoryContent = await memoryComponent.recallMemory();
692
+ agent.config.systemPrompt = agent.config.systemPrompt.replace("{{memory}}", memoryContent || "(No memory)");
693
+ } else {
694
+ agent.config.systemPrompt = agent.config.systemPrompt.replace("{{memory}}", "(Memory component not available)");
695
+ }
696
+ } catch (err) {
697
+ logger2.warn(`[handle_query] Failed to inject memory for agent ${agentName}: ${err}`);
698
+ agent.config.systemPrompt = agent.config.systemPrompt.replace("{{memory}}", "(Failed to load memory)");
699
+ }
700
+ }
701
+ if (agent.config.systemPrompt.includes("{{workspace_dir}}")) {
702
+ agent.config.systemPrompt = agent.config.systemPrompt.replace("{{workspace_dir}}", process.cwd());
703
+ }
704
+ agent.config.systemPrompt = injectAgentNamePlaceholder(agent.config.systemPrompt, context);
705
+ }
706
+ logger2.debug(`[handle_query] Injected memory/workspace_dir for existing agent: ${agentName}`);
707
+ }
708
+ try {
709
+ const taskComponent = this.getComponent("task");
710
+ registerLayaDecisionTaskHook(taskComponent);
711
+ } catch (err) {
712
+ logger2.warn(`[handle_query] Failed to register LayaDecisionTaskHook: ${err}`);
713
+ }
714
+ try {
715
+ const taskComponent = this.getComponent("task");
716
+ registerLayaCompletionTaskHook(taskComponent);
717
+ } catch (err) {
718
+ logger2.warn(`[handle_query] Failed to register LayaCompletionTaskHook: ${err}`);
719
+ }
720
+ const result = await agentComponent.run(agent.name, query, context);
721
+ if (result.error) {
722
+ if (result.originalError instanceof ContextError) {
723
+ throw result.originalError;
724
+ }
725
+ const errorMsg = result.error.toLowerCase();
726
+ if (errorMsg.includes("context") || errorMsg.includes("threshold") || errorMsg.includes("token") || result.error.includes("CTX_001")) {
727
+ const usageMatch = result.error.match(/(\d+)\/(\d+)\s*\(([\d.]+)%\)/);
728
+ let usage;
729
+ let contextWindow;
730
+ if (usageMatch) {
731
+ const totalTokens = parseInt(usageMatch[1], 10);
732
+ usage = {
733
+ promptTokens: totalTokens,
734
+ completionTokens: 0,
735
+ totalTokens
736
+ };
737
+ contextWindow = parseInt(usageMatch[2], 10);
738
+ }
739
+ const ctxError = new ContextError(result.error, ErrorCodes.CONTEXT_THRESHOLD_EXCEEDED, context?.sessionId, usage, contextWindow);
740
+ throw ctxError;
741
+ }
742
+ throw new Error(result.error, result.originalError ? { cause: result.originalError } : undefined);
743
+ }
744
+ return result.finalText || "";
745
+ }
746
+ async handleWorkflowAgentQuery(agentName, query, agentComponent, context) {
747
+ const registry = agentComponent.getRegistry?.();
748
+ if (!registry) {
749
+ return null;
750
+ }
751
+ const agentDef = registry.get(agentName);
752
+ if (!agentDef || agentDef.type !== "workflow") {
753
+ return null;
754
+ }
755
+ const workflowComponent = this.getComponent("workflow");
756
+ if (!workflowComponent) {
757
+ throw new Error(`WorkflowComponent not available — cannot run workflow agent "${agentName}". ` + `Ensure the workflow component is registered.`);
758
+ }
759
+ const workflowName = agentDef.workflow;
760
+ if (!workflowName) {
761
+ throw new Error(`Agent "${agentName}" has type 'workflow' but no workflow configured.`);
762
+ }
763
+ const svc = workflowComponent.getService?.();
764
+ if (!svc || typeof svc.getWorkflowByName !== "function") {
765
+ throw new Error(`WorkflowService not available. Cannot run workflow agent "${agentName}".`);
766
+ }
767
+ const workflow = svc.getWorkflowByName(workflowName);
768
+ if (!workflow) {
769
+ throw new Error(`Workflow "${workflowName}" not found. ` + `Use 'roy-agent workflow add' to register it first.`);
770
+ }
771
+ const wfResult = await workflowComponent.runWorkflow(workflow.definition, { query }, { context });
772
+ if (wfResult.status === "paused") {
773
+ return JSON.stringify({
774
+ status: "paused",
775
+ message: `Workflow "${workflowName}" paused, waiting for user input.`,
776
+ pendingNodeId: wfResult.pendingNodeId,
777
+ query: wfResult.query,
778
+ sessionId: wfResult.sessionId,
779
+ hint: `Resume with: roy-agent workflow run -s ${wfResult.sessionId} --input "your response"`
780
+ });
781
+ }
782
+ if (wfResult.status === "failed") {
783
+ throw new Error(`Workflow "${workflowName}" execution failed: ${wfResult.error || "Unknown error (status: " + wfResult.status + ")"}`);
784
+ }
785
+ if (typeof wfResult.output === "string") {
786
+ return wfResult.output;
787
+ }
788
+ if (wfResult.output !== undefined && wfResult.output !== null) {
789
+ return JSON.stringify(wfResult.output);
790
+ }
791
+ if (wfResult.error) {
792
+ throw new Error(`Workflow "${workflowName}" completed with error: ${wfResult.error}`);
793
+ }
794
+ return "";
795
+ }
796
+ async handle_action(action, context) {
797
+ throw new Error("handle_action not implemented. Override in subclass.");
798
+ }
799
+ eventHandlers = new Map;
800
+ wildcardHandlers = new Set;
801
+ subscribe(handler) {
802
+ this.wildcardHandlers.add(handler);
803
+ logger2.debug(`EnvEvent handler subscribed (wildcard)`);
804
+ return () => {
805
+ this.wildcardHandlers.delete(handler);
806
+ logger2.debug(`EnvEvent handler unsubscribed (wildcard)`);
807
+ };
808
+ }
809
+ subscribeTo(eventType, handler) {
810
+ const types = Array.isArray(eventType) ? eventType : [eventType];
811
+ for (const type of types) {
812
+ if (!this.eventHandlers.has(type)) {
813
+ this.eventHandlers.set(type, new Set);
814
+ }
815
+ this.eventHandlers.get(type).add(handler);
816
+ }
817
+ logger2.debug(`EnvEvent handler subscribed for types: ${types.join(", ")}`);
818
+ return () => {
819
+ for (const type of types) {
820
+ this.eventHandlers.get(type)?.delete(handler);
821
+ }
822
+ logger2.debug(`EnvEvent handler unsubscribed for types: ${types.join(", ")}`);
823
+ };
824
+ }
825
+ subscribeAll(handler) {
826
+ return this.subscribe(handler);
827
+ }
828
+ pushEnvEvent(event) {
829
+ const fullEvent = "id" in event && event.id ? event : {
830
+ id: event.id ?? generateId(),
831
+ type: event.type,
832
+ timestamp: event.timestamp ?? Date.now(),
833
+ metadata: {
834
+ ...event.metadata,
835
+ env_name: event.metadata?.env_name ?? this.name
836
+ },
837
+ payload: event.payload ?? {}
838
+ };
839
+ for (const handler of this.wildcardHandlers) {
840
+ try {
841
+ handler(fullEvent);
842
+ } catch (error) {
843
+ logger2.error(`Error in EnvEvent handler: ${error}`);
844
+ }
845
+ }
846
+ const handlers = this.eventHandlers.get(fullEvent.type);
847
+ if (handlers) {
848
+ for (const handler of handlers) {
849
+ try {
850
+ handler(fullEvent);
851
+ } catch (error) {
852
+ logger2.error(`Error in EnvEvent handler for ${fullEvent.type}: ${error}`);
853
+ }
854
+ }
855
+ }
856
+ }
857
+ emit(type, payload, metadata) {
858
+ const event = {
859
+ id: generateId(),
860
+ type,
861
+ timestamp: Date.now(),
862
+ metadata: {
863
+ env_name: this.name,
864
+ ...metadata
865
+ },
866
+ payload
867
+ };
868
+ this.pushEnvEvent(event);
869
+ }
870
+ async initializeComponents() {
871
+ logger2.debug(`Starting component initialization, total: ${this.components.size}`);
872
+ const configComp = this.components.get("config");
873
+ if (configComp && configComp.getStatus() === "created") {
874
+ logger2.debug(`Initializing ConfigComponent first...`);
875
+ await configComp.init({
876
+ name: "config",
877
+ version: configComp.version,
878
+ enabled: true,
879
+ env: this
880
+ });
881
+ logger2.debug(`ConfigComponent initialized`);
882
+ } else {
883
+ logger2.debug(`No ConfigComponent found, skipping first stage`);
884
+ }
885
+ const otherComponents = Array.from(this.components.values()).filter((c) => c.getStatus() === "created");
886
+ if (otherComponents.length > 0) {
887
+ logger2.debug(`Initializing ${otherComponents.length} other components...`);
888
+ for (const component of otherComponents) {
889
+ logger2.debug(`Initializing component: ${component.name}`);
890
+ await component.init({
891
+ name: component.name,
892
+ version: component.version,
893
+ enabled: true,
894
+ env: this
895
+ });
896
+ logger2.debug(`Component initialized: ${component.name}`);
897
+ }
898
+ }
899
+ logger2.debug(`All components initialized`);
900
+ }
901
+ async startComponents() {
902
+ const allComponents = Array.from(this.components.values());
903
+ if (allComponents.length > 0) {
904
+ logger2.debug(`Starting ${allComponents.length} components...`);
905
+ for (const component of allComponents) {
906
+ logger2.debug(`Starting component: ${component.name} (current status: ${component.getStatus()})`);
907
+ await component.start();
908
+ logger2.debug(`Component started: ${component.name}`);
909
+ }
910
+ }
911
+ }
912
+ async stopComponents() {
913
+ const componentsToStop = Array.from(this.components.values()).filter((c) => c.getStatus() !== "stopped").reverse();
914
+ if (componentsToStop.length > 0) {
915
+ logger2.debug(`Stopping ${componentsToStop.length} components...`);
916
+ for (const component of componentsToStop) {
917
+ logger2.debug(`Stopping component: ${component.name}`);
918
+ await component.stop();
919
+ logger2.debug(`Component stopped: ${component.name}`);
920
+ }
921
+ }
922
+ }
923
+ async onInit() {
924
+ await this.initializeComponents();
925
+ logger2.info(`Environment "${this.name}" initialized`);
926
+ }
927
+ async onStart() {
928
+ await this.startComponents();
929
+ logger2.info(`Environment "${this.name}" started`);
930
+ }
931
+ async onStop() {
932
+ await this.stopComponents();
933
+ this.eventHandlers.clear();
934
+ this.wildcardHandlers.clear();
935
+ logger2.info(`Environment "${this.name}" stopped`);
936
+ }
937
+ async init() {
938
+ Object.defineProperty(this, "env", {
939
+ value: this,
940
+ writable: true,
941
+ enumerable: false,
942
+ configurable: true
943
+ });
944
+ this.setStatus("initializing");
945
+ await this.onInit();
946
+ this.setStatus("running");
947
+ }
948
+ async start() {
949
+ if (this._started)
950
+ return;
951
+ this._started = true;
952
+ await this.onStart();
953
+ this.setStatus("running");
954
+ logger2.info(`Environment "${this.name}" started`);
955
+ }
956
+ async stop() {
957
+ this.setStatus("stopping");
958
+ await this.onStop();
959
+ this.setStatus("stopped");
960
+ }
961
+ async loadServiceConfig(configPath) {
962
+ const configComponent = this.getComponent("config");
963
+ if (!configComponent) {
964
+ throw new Error("ConfigComponent not found. Please register ConfigComponent before loading service config.");
965
+ }
966
+ const xdgDataHome = configComponent.getXdgDataHome();
967
+ const fullPath = path.resolve(xdgDataHome, configPath);
968
+ if (!fsSync.existsSync(fullPath)) {
969
+ throw new Error(`Service config file not found: ${fullPath}`);
970
+ }
971
+ const content = fsSync.readFileSync(fullPath, "utf-8");
972
+ let config;
973
+ try {
974
+ config = JSON.parse(content);
975
+ } catch (e) {
976
+ throw new Error(`Failed to parse service config: ${e}`);
977
+ }
978
+ logger2.debug(`Service config loaded from: ${fullPath}`);
979
+ return config;
980
+ }
981
+ generateComponentOptions(componentName, configEntry) {
982
+ const configComponent = this.getComponent("config");
983
+ if (!configComponent) {
984
+ throw new Error("ConfigComponent not found. Please register ConfigComponent before generating component options.");
985
+ }
986
+ const options = {
987
+ configComponent,
988
+ configPath: configEntry.configPath,
989
+ envPrefix: configEntry.envPrefix,
990
+ config: configEntry.config
991
+ };
992
+ logger2.debug(`Generated options for component: ${componentName}`);
993
+ return options;
994
+ }
995
+ async registerComponentWithConfig(component, configEntry) {
996
+ if (!this.components.has(component.name)) {
997
+ this.registerComponent(component);
998
+ }
999
+ const options = this.generateComponentOptions(component.name, configEntry);
1000
+ if (component.getStatus() === "running") {
1001
+ logger2.debug(`Component ${component.name} already initialized, skipping`);
1002
+ return;
1003
+ }
1004
+ await component.init({
1005
+ name: component.name,
1006
+ version: component.version,
1007
+ enabled: configEntry.enabled ?? true,
1008
+ env: this,
1009
+ options
1010
+ });
1011
+ logger2.debug(`Component ${component.name} registered and initialized with config`);
1012
+ }
1013
+ async initFromConfig(configPath) {
1014
+ if (!this.env) {
1015
+ Object.defineProperty(this, "env", {
1016
+ value: this,
1017
+ writable: true,
1018
+ enumerable: false,
1019
+ configurable: true
1020
+ });
1021
+ }
1022
+ const serviceConfig = await this.loadServiceConfig(configPath);
1023
+ if (serviceConfig.environment) {
1024
+ if (serviceConfig.environment.name) {
1025
+ this.name = serviceConfig.environment.name;
1026
+ }
1027
+ if (serviceConfig.environment.version) {
1028
+ this.version = serviceConfig.environment.version;
1029
+ }
1030
+ }
1031
+ const configComponent = this.getComponent("config");
1032
+ if (!configComponent) {
1033
+ throw new Error("ConfigComponent not found. Please register ConfigComponent before initFromConfig.");
1034
+ }
1035
+ if (configComponent.getStatus() === "created") {
1036
+ await configComponent.init({
1037
+ name: "config",
1038
+ version: configComponent.version,
1039
+ enabled: true,
1040
+ env: this
1041
+ });
1042
+ }
1043
+ const components = serviceConfig.components || {};
1044
+ for (const [componentName, configEntry] of Object.entries(components)) {
1045
+ if (configEntry.enabled === false) {
1046
+ logger2.debug(`Component ${componentName} is disabled, skipping`);
1047
+ continue;
1048
+ }
1049
+ const component = this.getComponent(componentName);
1050
+ if (!component) {
1051
+ logger2.warn(`Component ${componentName} not registered, skipping`);
1052
+ continue;
1053
+ }
1054
+ if (component.name === "config")
1055
+ continue;
1056
+ await this.registerComponentWithConfig(component, configEntry);
1057
+ }
1058
+ this.setStatus("running");
1059
+ logger2.info(`Environment "${this.name}" initialized from config: ${configPath}`);
1060
+ }
1061
+ }
1062
+ __legacyDecorateClassTS([
1063
+ TracedAs("env.handle_query", {
1064
+ paramFilter: envQueryParamFilter,
1065
+ recordResult: false,
1066
+ logResult: true,
1067
+ log: true
1068
+ })
1069
+ ], BaseEnvironment.prototype, "handle_query", null);
1070
+ __legacyDecorateClassTS([
1071
+ TracedAs("env.handle_workflow_agent_query", {
1072
+ paramFilter: envQueryParamFilter,
1073
+ recordResult: false,
1074
+ logResult: true,
1075
+ log: true
1076
+ })
1077
+ ], BaseEnvironment.prototype, "handleWorkflowAgentQuery", null);
1078
+
1079
+ // src/env/index.ts
1080
+ init_hook();
1081
+ init_context();
1082
+
1083
+ export { generateId, generateDescendingId, BaseEnvironment };