@ai-setting/roy-agent-core 1.4.12 → 1.4.13

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 (57) hide show
  1. package/dist/index.d.ts +7825 -0
  2. package/dist/index.js +13073 -19300
  3. package/dist/shared/chunk-0q6s9wm6.js +249 -0
  4. package/dist/shared/chunk-1aakcfp1.js +15 -0
  5. package/dist/shared/chunk-1d4rwms4.js +25 -0
  6. package/dist/shared/chunk-1pf5mfgd.js +82 -0
  7. package/dist/shared/chunk-1qwabsm0.js +154 -0
  8. package/dist/shared/chunk-25x2pdtp.js +107 -0
  9. package/dist/shared/chunk-2b5kbhx3.js +366 -0
  10. package/dist/shared/chunk-91bas8w5.js +20 -0
  11. package/dist/shared/chunk-9qzt1v1p.js +10 -0
  12. package/dist/shared/chunk-a9qmy3sc.js +296 -0
  13. package/dist/shared/chunk-g6j5n3gv.js +549 -0
  14. package/dist/shared/chunk-hs7tbmje.js +24 -0
  15. package/dist/shared/chunk-mf5xqbdh.js +14 -0
  16. package/dist/shared/chunk-q9j99fsm.js +368 -0
  17. package/dist/{env/workflow/engine/index.js → shared/chunk-rncy3rtd.js} +330 -1581
  18. package/dist/shared/chunk-t1rh6jtm.js +205 -0
  19. package/dist/{env/task/hooks/index.js → shared/chunk-wbkh7wat.js} +3 -18
  20. package/dist/shared/chunk-yqmx37vm.js +10 -0
  21. package/dist/shared/chunk-ze20rksg.js +102 -0
  22. package/package.json +7 -7
  23. package/dist/config/index.js +0 -1670
  24. package/dist/env/agent/index.js +0 -3035
  25. package/dist/env/commands/index.js +0 -1685
  26. package/dist/env/debug/formatters/index.js +0 -639
  27. package/dist/env/debug/index.js +0 -2300
  28. package/dist/env/hook/index.js +0 -273
  29. package/dist/env/index.js +0 -12591
  30. package/dist/env/llm/index.js +0 -2736
  31. package/dist/env/log-trace/index.js +0 -1779
  32. package/dist/env/mcp/index.js +0 -2173
  33. package/dist/env/mcp/tool/index.js +0 -1149
  34. package/dist/env/memory/built-in/index.js +0 -225
  35. package/dist/env/memory/index.js +0 -2171
  36. package/dist/env/memory/plugin/index.js +0 -1263
  37. package/dist/env/prompt/index.js +0 -2107
  38. package/dist/env/session/index.js +0 -3594
  39. package/dist/env/session/storage/index.js +0 -2049
  40. package/dist/env/skill/index.js +0 -1635
  41. package/dist/env/skill/tool/index.js +0 -114
  42. package/dist/env/task/delegate/index.js +0 -1844
  43. package/dist/env/task/index.js +0 -3578
  44. package/dist/env/task/plugins/index.js +0 -1626
  45. package/dist/env/task/storage/index.js +0 -1464
  46. package/dist/env/task/tools/index.js +0 -344
  47. package/dist/env/task/tools/operation/index.js +0 -270
  48. package/dist/env/tool/built-in/index.js +0 -1151
  49. package/dist/env/tool/index.js +0 -2284
  50. package/dist/env/workflow/decorators/index.js +0 -449
  51. package/dist/env/workflow/index.js +0 -6214
  52. package/dist/env/workflow/nodes/index.js +0 -650
  53. package/dist/env/workflow/service/index.js +0 -262
  54. package/dist/env/workflow/storage/index.js +0 -1236
  55. package/dist/env/workflow/tools/index.js +0 -1081
  56. package/dist/env/workflow/types/index.js +0 -479
  57. package/dist/env/workflow/utils/index.js +0 -1631
@@ -1,3578 +0,0 @@
1
- // @bun
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- function __accessProp(key) {
7
- return this[key];
8
- }
9
- var __toCommonJS = (from) => {
10
- var entry = (__moduleCache ??= new WeakMap).get(from), desc;
11
- if (entry)
12
- return entry;
13
- entry = __defProp({}, "__esModule", { value: true });
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (var key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(entry, key))
17
- __defProp(entry, key, {
18
- get: __accessProp.bind(from, key),
19
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
20
- });
21
- }
22
- __moduleCache.set(from, entry);
23
- return entry;
24
- };
25
- var __moduleCache;
26
- var __returnValue = (v) => v;
27
- function __exportSetter(name, newValue) {
28
- this[name] = __returnValue.bind(null, newValue);
29
- }
30
- var __export = (target, all) => {
31
- for (var name in all)
32
- __defProp(target, name, {
33
- get: all[name],
34
- enumerable: true,
35
- configurable: true,
36
- set: __exportSetter.bind(all, name)
37
- });
38
- };
39
- var __legacyDecorateClassTS = function(decorators, target, key, desc) {
40
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
41
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
42
- r = Reflect.decorate(decorators, target, key, desc);
43
- else
44
- for (var i = decorators.length - 1;i >= 0; i--)
45
- if (d = decorators[i])
46
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
47
- return c > 3 && r && Object.defineProperty(target, key, r), r;
48
- };
49
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
50
- var __require = import.meta.require;
51
-
52
- // packages/core/src/env/log-trace/span-storage.ts
53
- var exports_span_storage = {};
54
- __export(exports_span_storage, {
55
- SQLiteSpanStorage: () => SQLiteSpanStorage
56
- });
57
-
58
- class SQLiteSpanStorage {
59
- db = null;
60
- dbPath;
61
- initialized = false;
62
- constructor(dbPath) {
63
- if (!dbPath) {
64
- throw new Error("SQLiteSpanStorage requires a valid dbPath parameter");
65
- }
66
- if (dbPath === ":memory:") {
67
- throw new Error("SQLiteSpanStorage does not support :memory: mode. Use a file path instead.");
68
- }
69
- this.dbPath = dbPath;
70
- }
71
- async initialize() {
72
- if (this.initialized)
73
- return;
74
- const { Database } = __require("bun:sqlite");
75
- const fs = __require("fs");
76
- const path = __require("path");
77
- const dir = path.dirname(this.dbPath);
78
- if (!fs.existsSync(dir)) {
79
- fs.mkdirSync(dir, { recursive: true });
80
- }
81
- this.db = new Database(this.dbPath);
82
- this.db.run("PRAGMA journal_mode=WAL");
83
- this.db.run("PRAGMA busy_timeout=5000");
84
- this.db.run("PRAGMA synchronous=NORMAL");
85
- this.db.run(`
86
- CREATE TABLE IF NOT EXISTS span (
87
- span_id TEXT PRIMARY KEY,
88
- trace_id TEXT NOT NULL,
89
- parent_span_id TEXT,
90
- name TEXT NOT NULL,
91
- kind TEXT NOT NULL,
92
- status TEXT NOT NULL,
93
- start_time INTEGER NOT NULL,
94
- end_time INTEGER,
95
- attributes TEXT,
96
- result TEXT,
97
- error TEXT,
98
- time_created INTEGER NOT NULL
99
- )
100
- `);
101
- this.db.run("CREATE INDEX IF NOT EXISTS idx_span_trace ON span(trace_id)");
102
- this.db.run("CREATE INDEX IF NOT EXISTS idx_span_parent ON span(parent_span_id)");
103
- this.initialized = true;
104
- }
105
- save(span) {
106
- if (!this.db)
107
- return;
108
- const stmt = this.db.prepare(`
109
- INSERT OR REPLACE INTO span
110
- (span_id, trace_id, parent_span_id, name, kind, status, start_time, end_time, attributes, result, error, time_created)
111
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
112
- `);
113
- const resultValue = span.result !== undefined && span.result !== null ? typeof span.result === "string" ? span.result : JSON.stringify(span.result) : null;
114
- stmt.run(span.spanId, span.traceId, span.parentSpanId || null, span.name, span.kind, span.status, span.startTime, span.endTime || null, JSON.stringify(span.attributes), resultValue, span.error || null, Date.now());
115
- }
116
- saveBatch(spans) {
117
- for (const span of spans) {
118
- this.save(span);
119
- }
120
- }
121
- findByTraceId(traceId) {
122
- if (!this.db)
123
- return [];
124
- const rows = this.db.prepare("SELECT * FROM span WHERE trace_id = ?").all(traceId);
125
- return this.buildTree(rows.map(this.rowToSpan));
126
- }
127
- findBySpanId(spanId) {
128
- if (!this.db)
129
- return;
130
- const row = this.db.prepare("SELECT * FROM span WHERE span_id = ?").get(spanId);
131
- return row ? this.rowToSpan(row) : undefined;
132
- }
133
- listTraces(limit = 10) {
134
- if (!this.db)
135
- return [];
136
- const rows = this.db.prepare(`
137
- SELECT trace_id,
138
- MIN(start_time) as start_time,
139
- MAX(end_time) as end_time,
140
- COUNT(*) as span_count
141
- FROM span
142
- GROUP BY trace_id
143
- ORDER BY start_time DESC
144
- LIMIT ?
145
- `).all(limit);
146
- return rows.map((row) => ({
147
- traceId: row.trace_id,
148
- rootSpanName: "unknown",
149
- startTime: row.start_time,
150
- endTime: row.end_time,
151
- duration: row.end_time - row.start_time,
152
- spanCount: row.span_count,
153
- status: "ok"
154
- }));
155
- }
156
- deleteByTraceId(traceId) {
157
- if (this.db) {
158
- this.db.prepare("DELETE FROM span WHERE trace_id = ?").run(traceId);
159
- }
160
- }
161
- close() {
162
- if (this.db) {
163
- this.db.close();
164
- this.db = null;
165
- }
166
- }
167
- rowToSpan(row) {
168
- return {
169
- traceId: row.trace_id,
170
- spanId: row.span_id,
171
- parentSpanId: row.parent_span_id,
172
- name: row.name,
173
- kind: row.kind,
174
- status: row.status,
175
- startTime: row.start_time,
176
- endTime: row.end_time,
177
- attributes: row.attributes ? JSON.parse(row.attributes) : {},
178
- result: row.result || undefined,
179
- error: row.error || undefined
180
- };
181
- }
182
- buildTree(spans) {
183
- const spanMap = new Map;
184
- const roots = [];
185
- for (const span of spans) {
186
- spanMap.set(span.spanId, { ...span, children: [] });
187
- }
188
- for (const span of spanMap.values()) {
189
- if (span.parentSpanId) {
190
- const parent = spanMap.get(span.parentSpanId);
191
- if (parent) {
192
- parent.children.push(span);
193
- } else {
194
- roots.push(span);
195
- }
196
- } else {
197
- roots.push(span);
198
- }
199
- }
200
- return roots;
201
- }
202
- }
203
-
204
- // packages/core/src/env/log-trace/opentelemetry/propagation.ts
205
- function padLeft(str, length) {
206
- return str.padStart(length, "0");
207
- }
208
- function isValidHex(str) {
209
- return /^[0-9a-f]+$/i.test(str);
210
- }
211
- function serialize(context) {
212
- const traceId = padLeft(context.traceId.toLowerCase(), TRACE_ID_LENGTH);
213
- const spanId = padLeft(context.spanId.toLowerCase(), PARENT_SPAN_ID_LENGTH);
214
- const parts = [
215
- TRACE_CONTEXT_VERSION,
216
- traceId,
217
- spanId,
218
- TRACE_FLAGS_SAMPLED
219
- ];
220
- return parts.join("-");
221
- }
222
- function parse(traceparent) {
223
- if (!traceparent || typeof traceparent !== "string") {
224
- return;
225
- }
226
- const trimmed = traceparent.trim();
227
- const parts = trimmed.split("-");
228
- if (parts.length !== 4) {
229
- return;
230
- }
231
- const [version, traceId, senderSpanId, flags] = parts;
232
- if (version !== TRACE_CONTEXT_VERSION) {
233
- if (version > TRACE_CONTEXT_VERSION) {
234
- return;
235
- }
236
- }
237
- if (traceId.length !== TRACE_ID_LENGTH || !isValidHex(traceId)) {
238
- return;
239
- }
240
- if (senderSpanId.length !== PARENT_SPAN_ID_LENGTH || !isValidHex(senderSpanId)) {
241
- return;
242
- }
243
- if (flags.length !== FLAGS_LENGTH || !isValidHex(flags)) {
244
- return;
245
- }
246
- return {
247
- traceId: traceId.toLowerCase(),
248
- spanId: senderSpanId.toLowerCase()
249
- };
250
- }
251
- var TRACE_CONTEXT_VERSION = "00", TRACE_FLAGS_SAMPLED = "01", TRACEPARENT_HEADER = "TRACEPARENT", TRACE_ID_LENGTH = 32, PARENT_SPAN_ID_LENGTH = 16, FLAGS_LENGTH = 2, propagation;
252
- var init_propagation = __esm(() => {
253
- propagation = {
254
- inject(carrier, context) {
255
- carrier[TRACEPARENT_HEADER] = serialize(context);
256
- },
257
- extract(carrier) {
258
- const traceparent = carrier[TRACEPARENT_HEADER];
259
- if (!traceparent) {
260
- return;
261
- }
262
- return parse(traceparent);
263
- },
264
- getTraceparentHeader() {
265
- return TRACEPARENT_HEADER;
266
- }
267
- };
268
- });
269
-
270
- // packages/core/src/env/log-trace/types.ts
271
- var SpanKind, SpanStatus;
272
- var init_types = __esm(() => {
273
- ((SpanKind2) => {
274
- SpanKind2["CLIENT"] = "client";
275
- SpanKind2["SERVER"] = "server";
276
- SpanKind2["INTERNAL"] = "internal";
277
- })(SpanKind ||= {});
278
- ((SpanStatus2) => {
279
- SpanStatus2["OK"] = "ok";
280
- SpanStatus2["ERROR"] = "error";
281
- })(SpanStatus ||= {});
282
- });
283
-
284
- // packages/core/src/env/log-trace/opentelemetry/tracer-provider.ts
285
- var exports_tracer_provider = {};
286
- __export(exports_tracer_provider, {
287
- resetTracerProvider: () => resetTracerProvider,
288
- getTracerProvider: () => getTracerProvider,
289
- OTelTracerProvider: () => OTelTracerProvider
290
- });
291
-
292
- class OTelSpanImpl {
293
- name;
294
- kind;
295
- spanContext;
296
- attributes = {};
297
- startTime;
298
- endTime;
299
- error;
300
- storage;
301
- parentSpanContext;
302
- onEnd;
303
- constructor(name, spanContext, storage, parentSpanContext, onEnd) {
304
- this.name = name;
305
- this.kind = "internal";
306
- this.spanContext = spanContext;
307
- this.parentSpanContext = parentSpanContext;
308
- this.startTime = Date.now();
309
- this.storage = storage;
310
- this.onEnd = onEnd;
311
- }
312
- setAttribute(key, value) {
313
- this.attributes[key] = value;
314
- }
315
- addEvent(name, attributes) {
316
- const events = this.attributes._events || [];
317
- events.push({ name, attributes });
318
- this.attributes._events = events;
319
- }
320
- end(result, error) {
321
- this.endTime = Date.now();
322
- if (error) {
323
- this.error = error.message;
324
- }
325
- this.storage.save({
326
- traceId: this.spanContext.traceId,
327
- spanId: this.spanContext.spanId,
328
- parentSpanId: this.spanContext.parentSpanId,
329
- name: this.name,
330
- kind: this.kind,
331
- status: error ? "error" /* ERROR */ : "ok" /* OK */,
332
- startTime: this.startTime,
333
- endTime: this.endTime,
334
- attributes: this.attributes,
335
- result,
336
- error: this.error
337
- });
338
- this.onEnd?.();
339
- }
340
- }
341
-
342
- class OTelTracerImpl {
343
- name;
344
- version;
345
- storage;
346
- currentContext;
347
- activeSpans = new Map;
348
- onSpanEndCallback;
349
- provider;
350
- constructor(name, version, storage, provider) {
351
- this.name = name;
352
- this.version = version;
353
- this.storage = storage;
354
- this.provider = provider;
355
- }
356
- setOnSpanEndCallback(callback) {
357
- this.onSpanEndCallback = callback;
358
- }
359
- getActiveSpanCount() {
360
- return this.activeSpans.size;
361
- }
362
- startSpan(name, options) {
363
- const parentFromOptions = options?.parent;
364
- const hasExplicitParent = options && "parent" in options;
365
- const globalContext = this.provider.getGlobalContext();
366
- let effectiveParentContext;
367
- if (hasExplicitParent) {
368
- effectiveParentContext = parentFromOptions;
369
- } else if (this.currentContext) {
370
- effectiveParentContext = this.currentContext;
371
- } else if (globalContext) {
372
- effectiveParentContext = globalContext;
373
- }
374
- const traceId = effectiveParentContext?.traceId || this.generateTraceId();
375
- const spanId = this.generateSpanId();
376
- let parentSpanId;
377
- if (hasExplicitParent && parentFromOptions) {
378
- parentSpanId = parentFromOptions.parentSpanId || parentFromOptions.spanId;
379
- } else if (this.currentContext) {
380
- parentSpanId = this.currentContext.spanId;
381
- } else if (globalContext) {
382
- parentSpanId = globalContext.spanId;
383
- }
384
- const spanContext = {
385
- traceId,
386
- spanId,
387
- parentSpanId
388
- };
389
- this.currentContext = {
390
- traceId,
391
- spanId,
392
- parentSpanId
393
- };
394
- const span = new OTelSpanImpl(name, spanContext, this.storage, effectiveParentContext, () => this.handleSpanEnd(spanContext.spanId, effectiveParentContext?.spanId));
395
- if (options?.attributes) {
396
- for (const [key, value] of Object.entries(options.attributes)) {
397
- span.setAttribute(key, value);
398
- }
399
- }
400
- this.activeSpans.set(spanId, span);
401
- return span;
402
- }
403
- injectToEnv(env) {
404
- if (this.currentContext) {
405
- propagation.inject(env, this.currentContext);
406
- }
407
- }
408
- getCurrentContext() {
409
- return this.currentContext;
410
- }
411
- setCurrentContext(context) {
412
- this.currentContext = context;
413
- }
414
- endSpan(span) {
415
- const spanContext = span.spanContext;
416
- this.activeSpans.delete(spanContext.spanId);
417
- const currentTraceId = this.currentContext?.traceId;
418
- if (spanContext.parentSpanId) {
419
- const parentSpan = this.activeSpans.get(spanContext.parentSpanId);
420
- if (parentSpan) {
421
- const parentContext = {
422
- traceId: spanContext.traceId,
423
- spanId: parentSpan.spanContext.spanId,
424
- parentSpanId: parentSpan.spanContext.parentSpanId
425
- };
426
- this.currentContext = parentContext;
427
- return parentContext;
428
- }
429
- if (currentTraceId) {
430
- const parentContext = {
431
- traceId: currentTraceId,
432
- spanId: spanContext.parentSpanId,
433
- parentSpanId: undefined
434
- };
435
- this.currentContext = parentContext;
436
- return parentContext;
437
- }
438
- }
439
- this.currentContext = undefined;
440
- return;
441
- }
442
- generateTraceId() {
443
- const timestamp = Date.now().toString(16).padStart(12, "0");
444
- const random = Array.from({ length: 5 }, () => Math.floor(Math.random() * 4294967295).toString(16).padStart(8, "0")).join("");
445
- return (timestamp + random).slice(0, 32).padStart(32, "0");
446
- }
447
- generateSpanId() {
448
- return Math.floor(Math.random() * 18446744073709552000).toString(16).padStart(16, "0");
449
- }
450
- handleSpanEnd(spanId, parentSpanId) {
451
- this.activeSpans.delete(spanId);
452
- const currentTraceId = this.currentContext?.traceId;
453
- if (parentSpanId) {
454
- const parentSpan = this.activeSpans.get(parentSpanId);
455
- if (parentSpan) {
456
- this.currentContext = {
457
- traceId: parentSpan.spanContext.traceId,
458
- spanId: parentSpan.spanContext.spanId,
459
- parentSpanId: parentSpan.spanContext.parentSpanId
460
- };
461
- return;
462
- }
463
- if (currentTraceId) {
464
- this.currentContext = {
465
- traceId: currentTraceId,
466
- spanId: parentSpanId,
467
- parentSpanId: undefined
468
- };
469
- return;
470
- }
471
- }
472
- this.currentContext = undefined;
473
- }
474
- }
475
-
476
- class OTelTracerProvider {
477
- tracers = new Map;
478
- storage;
479
- initialized = false;
480
- globalContext;
481
- constructor(storage, dbPath) {
482
- this.storage = storage || new SQLiteSpanStorage(dbPath || getDefaultDbPath());
483
- }
484
- async initialize() {
485
- if (this.initialized)
486
- return;
487
- await this.storage.initialize();
488
- this.initialized = true;
489
- }
490
- isInitialized() {
491
- return this.initialized;
492
- }
493
- getGlobalContext() {
494
- return this.globalContext;
495
- }
496
- setGlobalContext(context) {
497
- this.globalContext = context;
498
- }
499
- getTracer(name, version) {
500
- const key = `${name}@${version || "0.0.0"}`;
501
- let tracer = this.tracers.get(key);
502
- if (!tracer) {
503
- tracer = new OTelTracerImpl(name, version, this.storage, this);
504
- this.tracers.set(key, tracer);
505
- if (this.initialized) {
506
- this.restoreFromEnv(tracer);
507
- }
508
- }
509
- return tracer;
510
- }
511
- restoreFromEnv(tracer) {
512
- const extracted = propagation.extract(process.env);
513
- if (extracted) {
514
- tracer.setCurrentContext({
515
- traceId: extracted.traceId,
516
- spanId: extracted.spanId,
517
- parentSpanId: undefined
518
- });
519
- }
520
- }
521
- shutdown() {
522
- for (const tracer of this.tracers.values()) {}
523
- this.tracers.clear();
524
- this.storage.close();
525
- this.initialized = false;
526
- this.globalContext = undefined;
527
- delete process.env["TRACEPARENT"];
528
- delete process.env["TRACE_ID"];
529
- delete process.env["LOG_TRACE_REQUEST_ID"];
530
- }
531
- getStorage() {
532
- return this.storage;
533
- }
534
- }
535
- function getTracerProvider() {
536
- if (!providerInstance) {
537
- providerInstance = new OTelTracerProvider;
538
- }
539
- return providerInstance;
540
- }
541
- function resetTracerProvider() {
542
- if (providerInstance) {
543
- providerInstance.shutdown();
544
- providerInstance = null;
545
- }
546
- }
547
- function getDefaultDbPath() {
548
- const os = __require("os");
549
- const path = __require("path");
550
- const home = os.homedir();
551
- const dataHome = process.env.XDG_DATA_HOME || path.join(home, ".local", "share");
552
- return path.join(dataHome, "roy-agent", "traces.db");
553
- }
554
- var providerInstance = null;
555
- var init_tracer_provider = __esm(() => {
556
- init_propagation();
557
- init_types();
558
- });
559
-
560
- // packages/core/src/env/log-trace/logger.ts
561
- import { appendFileSync, existsSync, mkdirSync } from "fs";
562
- import { join } from "path";
563
- function simplifyFilePath(fullPath) {
564
- let path = fullPath.replace(/\\/g, "/");
565
- const bunfsMatch = path.match(/\/\$bunfs\/root\/(.+)$/);
566
- if (bunfsMatch) {
567
- const virtualPath = bunfsMatch[1];
568
- const packagesMatch = virtualPath.match(/(packages\/[^/]+\/src\/[^/]+\/.+)$/);
569
- if (packagesMatch) {
570
- return packagesMatch[1];
571
- }
572
- return virtualPath;
573
- }
574
- const fileProtocolMatch = path.match(/@roy-agent\+core@file\+([^/]+)\/node_modules\/@roy-agent\/core\/(.+)$/);
575
- if (fileProtocolMatch) {
576
- const rootPkg = fileProtocolMatch[1].replace(/\+/g, "/");
577
- const remaining = fileProtocolMatch[2];
578
- const prefix = rootPkg;
579
- const suffix = remaining.startsWith("src/") ? remaining : `src/${remaining}`;
580
- return `${prefix}/${suffix}`;
581
- }
582
- const packagesRootMatch = path.match(/(packages\/[^/]+\/src\/[^/]+\/.+)$/);
583
- if (packagesRootMatch) {
584
- return packagesRootMatch[1];
585
- }
586
- const rootMarkers = ["packages/core/src", "packages/core", "packages"];
587
- for (const marker of rootMarkers) {
588
- const idx = path.indexOf(marker);
589
- if (idx !== -1) {
590
- return path.substring(idx);
591
- }
592
- }
593
- return path;
594
- }
595
- function getDefaultLogDir() {
596
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
597
- try {
598
- const xdg = __require("xdg-basedir");
599
- if (xdg.xdgData) {
600
- return join(xdg.xdgData, "roy-agent", "logs");
601
- }
602
- } catch {}
603
- return join(home, ".local", "share", "roy-agent", "logs");
604
- }
605
- function isQuietMode() {
606
- return quietMode;
607
- }
608
- function setQuietMode(enabled) {
609
- quietMode = enabled;
610
- }
611
- function setConfigComponent(component) {
612
- configComponentInstance = component;
613
- }
614
- function getLogLevel() {
615
- if (configComponentInstance) {
616
- const level = configComponentInstance.get("log_trace.logging.level");
617
- if (level && ["debug", "info", "warn", "error"].includes(level)) {
618
- return level;
619
- }
620
- }
621
- const envLevel = process.env.LOG_LEVEL;
622
- if (envLevel && ["debug", "info", "warn", "error"].includes(envLevel)) {
623
- return envLevel;
624
- }
625
- return "info";
626
- }
627
- function getCategoryLogLevel(category) {
628
- if (configComponentInstance) {
629
- const levels = configComponentInstance.get("log_trace.logging.levels");
630
- if (levels && typeof levels === "object") {
631
- const categoryLevel = levels[category];
632
- if (categoryLevel && ["debug", "info", "warn", "error"].includes(categoryLevel)) {
633
- return categoryLevel;
634
- }
635
- }
636
- const directLevel = configComponentInstance.get(`log_trace.logging.levels.${category}`);
637
- if (directLevel && ["debug", "info", "warn", "error"].includes(directLevel)) {
638
- return directLevel;
639
- }
640
- }
641
- const envKey = `LOG_LEVEL_${category.toUpperCase().replace(/:/g, "_")}`;
642
- const envLevel = process.env[envKey];
643
- if (envLevel && ["debug", "info", "warn", "error"].includes(envLevel)) {
644
- return envLevel;
645
- }
646
- return getLogLevel();
647
- }
648
- function isAbsolutePath(path) {
649
- if (path.startsWith("/")) {
650
- return true;
651
- }
652
- if (/^[a-zA-Z]:[/\\]/.test(path)) {
653
- return true;
654
- }
655
- return false;
656
- }
657
- function expandHomeDir(path) {
658
- if (path.startsWith("~")) {
659
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
660
- return join(home, path.slice(1));
661
- }
662
- return path;
663
- }
664
- function getLogFile() {
665
- if (configComponentInstance) {
666
- const file = configComponentInstance.get("log_trace.logging.file");
667
- if (file) {
668
- return file;
669
- }
670
- }
671
- return "app.log";
672
- }
673
- function getLogDir() {
674
- if (configComponentInstance) {
675
- const dir = configComponentInstance.get("log_trace.logging.dir");
676
- if (dir) {
677
- return dir;
678
- }
679
- }
680
- return getDefaultLogDir();
681
- }
682
- function getMaxOutput() {
683
- if (configComponentInstance) {
684
- const maxOutput = configComponentInstance.get("log-trace.logging.maxOutput");
685
- if (typeof maxOutput === "number") {
686
- return maxOutput;
687
- }
688
- }
689
- return;
690
- }
691
- function setLogDirOverride(dir) {
692
- logDirOverride = dir;
693
- }
694
- function getLogDirOverride() {
695
- return logDirOverride;
696
- }
697
-
698
- class Logger {
699
- prefix;
700
- constructor(prefix) {
701
- this.prefix = prefix;
702
- }
703
- shouldLog(level) {
704
- const categoryLevel = getCategoryLogLevel(this.prefix);
705
- return levelPriority[level] >= levelPriority[categoryLevel];
706
- }
707
- ensureLogDirectory(dir) {
708
- if (!existsSync(dir)) {
709
- try {
710
- mkdirSync(dir, { recursive: true });
711
- } catch (err) {
712
- console.error("[Logger] Failed to create log directory:", dir, err);
713
- }
714
- }
715
- }
716
- getCallerLocation() {
717
- const originalLimit = Error.stackTraceLimit;
718
- Error.stackTraceLimit = 10;
719
- const err = new Error;
720
- Error.captureStackTrace(err, this.formatMessage);
721
- const stack = err.stack?.split(`
722
- `) || [];
723
- Error.stackTraceLimit = originalLimit;
724
- for (let i = 1;i < stack.length; i++) {
725
- const line = stack[i];
726
- if (line.includes("at ") && !line.includes("logger.ts") && !line.includes("formatMessage")) {
727
- const match = line.match(/at\s+.+\s+\((.+):(\d+):\d+\)/) || line.match(/at\s+(.+):(\d+):\d+/);
728
- if (match) {
729
- const filePath = match[1];
730
- const relativePath = this.getRelativePath(filePath);
731
- return {
732
- file: relativePath,
733
- line: parseInt(match[2], 10)
734
- };
735
- }
736
- }
737
- }
738
- return null;
739
- }
740
- getRelativePath(fullPath) {
741
- return simplifyFilePath(fullPath);
742
- }
743
- formatMessage(level, message, data) {
744
- const now = new Date;
745
- const timestamp = now.toLocaleString("zh-CN", {
746
- timeZone: "Asia/Shanghai",
747
- year: "numeric",
748
- month: "2-digit",
749
- day: "2-digit",
750
- hour: "2-digit",
751
- minute: "2-digit",
752
- second: "2-digit",
753
- hour12: false
754
- }).replace(/\//g, "-") + "." + String(now.getMilliseconds()).padStart(3, "0");
755
- const prefix = this.prefix ? `[${this.prefix}]` : "";
756
- let traceIdStr = "";
757
- try {
758
- const provider = getTracerProvider();
759
- const tracer = provider.getTracer("roy-tracer");
760
- const context = tracer.getCurrentContext();
761
- if (context?.traceId) {
762
- traceIdStr = `[traceId=${context.traceId}]`;
763
- }
764
- } catch {}
765
- let locationStr = "";
766
- if (data && typeof data === "object" && "callerLocation" in data) {
767
- const logData = data;
768
- locationStr = logData.callerLocation ? ` [${logData.callerLocation}]` : "";
769
- const { callerLocation: _callerLocation, ...rest } = logData;
770
- data = Object.keys(rest).length > 0 ? rest : undefined;
771
- } else {
772
- const location = this.getCallerLocation();
773
- if (location) {
774
- locationStr = ` [${location.file}:${location.line}]`;
775
- }
776
- }
777
- let formatted = `${timestamp} [${level.toUpperCase()}]${traceIdStr}${locationStr}${prefix} ${message}`;
778
- if (data !== undefined) {
779
- if (typeof data === "object") {
780
- formatted += " " + JSON.stringify(data).replace(/\n/g, "");
781
- } else {
782
- formatted += " " + String(data);
783
- }
784
- }
785
- const maxOutput = getMaxOutput();
786
- if (maxOutput && maxOutput > 0 && formatted.length > maxOutput) {
787
- formatted = formatted.substring(0, maxOutput) + " [TRUNCATED]";
788
- }
789
- return formatted;
790
- }
791
- writeToFile(message) {
792
- try {
793
- const dir = getLogDir();
794
- const filename = getLogFile();
795
- const expandedDir = expandHomeDir(dir);
796
- const resolvedDir = isAbsolutePath(expandedDir) ? expandedDir : join(process.cwd(), expandedDir);
797
- this.ensureLogDirectory(resolvedDir);
798
- const logFile = join(resolvedDir, filename);
799
- appendFileSync(logFile, message + `
800
- `, "utf-8");
801
- } catch (err) {
802
- console.error("[Logger] Failed to write to log file:", err);
803
- }
804
- }
805
- log(level, message, data) {
806
- if (!this.shouldLog(level))
807
- return;
808
- const formatted = this.formatMessage(level, message, data);
809
- this.writeToFile(formatted);
810
- if (!isQuietMode()) {
811
- const consoleMethod = level === "error" ? console.error : level === "warn" ? console.warn : level === "info" ? console.log : console.debug;
812
- consoleMethod(formatted);
813
- }
814
- }
815
- debug(message, data) {
816
- this.log("debug", message, data);
817
- }
818
- info(message, data) {
819
- this.log("info", message, data);
820
- }
821
- warn(message, data) {
822
- this.log("warn", message, data);
823
- }
824
- error(message, data) {
825
- this.log("error", message, data);
826
- }
827
- }
828
- function createLogger(prefix) {
829
- if (!loggerCache.has(prefix)) {
830
- loggerCache.set(prefix, new Logger(prefix));
831
- }
832
- return loggerCache.get(prefix);
833
- }
834
- function getLogLevels() {
835
- return ["debug", "info", "warn", "error"];
836
- }
837
- var configComponentInstance = null, quietMode = false, logDirOverride, levelPriority, loggerCache;
838
- var init_logger = __esm(() => {
839
- init_tracer_provider();
840
- levelPriority = {
841
- debug: 0,
842
- info: 1,
843
- warn: 2,
844
- error: 3
845
- };
846
- loggerCache = new Map;
847
- });
848
-
849
- // packages/core/src/env/hook/types.ts
850
- function createHook(meta, fn) {
851
- return {
852
- ...meta,
853
- execute: fn
854
- };
855
- }
856
- function createPriorityHook(name, fn, priority) {
857
- return createHook({ name, priority }, fn);
858
- }
859
- // packages/core/src/env/hook/hook-manager.ts
860
- class HookManager {
861
- _hooks = new Map;
862
- componentName;
863
- componentVersion;
864
- defaultPriority;
865
- constructor(options = {}) {
866
- this.componentName = options.componentName ?? "unknown";
867
- this.componentVersion = options.componentVersion ?? "0.0.0";
868
- this.defaultPriority = options.defaultPriority ?? 0;
869
- }
870
- register(hookPoint, hook) {
871
- const hooks = this.getOrCreateHooks(hookPoint);
872
- hooks.push(hook);
873
- }
874
- registerMany(hookPoint, hooks) {
875
- const hookList = this.getOrCreateHooks(hookPoint);
876
- hookList.push(...hooks);
877
- }
878
- unregister(hookPoint, name) {
879
- const hooks = this._hooks.get(hookPoint);
880
- if (!hooks)
881
- return false;
882
- const index = hooks.findIndex((h) => h.name === name);
883
- if (index === -1)
884
- return false;
885
- hooks.splice(index, 1);
886
- return true;
887
- }
888
- unregisterAll(hookPoint) {
889
- this._hooks.delete(hookPoint);
890
- }
891
- async execute(hookPoint, data, metadata = {}) {
892
- const hooks = this._hooks.get(hookPoint);
893
- if (!hooks || hooks.length === 0)
894
- return;
895
- const sortedHooks = this.sortHooks(hooks);
896
- const ctx = this.createContext(hookPoint, data, metadata, "before");
897
- for (const hook of sortedHooks) {
898
- await this.safeExecute(hook, ctx);
899
- }
900
- }
901
- async executeAndCollect(hookPoint, data, metadata = {}) {
902
- const hooks = this._hooks.get(hookPoint);
903
- if (!hooks || hooks.length === 0)
904
- return [];
905
- const sortedHooks = this.sortHooks(hooks);
906
- const ctx = this.createContext(hookPoint, data, metadata, "before");
907
- const results = [];
908
- for (const hook of sortedHooks) {
909
- const result = await this.safeExecuteAndReturn(hook, ctx);
910
- if (result !== undefined) {
911
- results.push(result);
912
- }
913
- }
914
- return results;
915
- }
916
- count(hookPoint) {
917
- return this._hooks.get(hookPoint)?.length ?? 0;
918
- }
919
- clear() {
920
- this._hooks.clear();
921
- }
922
- getHookPoints() {
923
- return Array.from(this._hooks.keys());
924
- }
925
- hasHooks(hookPoint) {
926
- return this.count(hookPoint) > 0;
927
- }
928
- setComponentInfo(name, version) {
929
- this.componentName = name;
930
- this.componentVersion = version;
931
- }
932
- get hooks() {
933
- return this._hooks;
934
- }
935
- async executeWithIntervention(hookPoint, data, metadata = {}) {
936
- const hooks = this._hooks.get(hookPoint);
937
- if (!hooks || hooks.length === 0) {
938
- return { stopped: false, results: [] };
939
- }
940
- const sortedHooks = this.sortHooks(hooks);
941
- const ctx = this.createContext(hookPoint, data, metadata, "before");
942
- const results = [];
943
- let stopped = false;
944
- let action;
945
- for (const hook of sortedHooks) {
946
- if (stopped)
947
- break;
948
- const result = await this.safeExecuteAndReturn(hook, ctx);
949
- results.push(result);
950
- if (result && typeof result === "object" && "stopped" in result) {
951
- const hookResult = result;
952
- if (hookResult.stopped) {
953
- stopped = true;
954
- action = hookResult.action;
955
- }
956
- }
957
- }
958
- return { stopped, action, results };
959
- }
960
- getOrCreateHooks(hookPoint) {
961
- let hooks = this._hooks.get(hookPoint);
962
- if (!hooks) {
963
- hooks = [];
964
- this._hooks.set(hookPoint, hooks);
965
- }
966
- return hooks;
967
- }
968
- sortHooks(hooks) {
969
- return [...hooks].sort((a, b) => {
970
- const priorityA = a.priority ?? this.defaultPriority;
971
- const priorityB = b.priority ?? this.defaultPriority;
972
- return priorityA - priorityB;
973
- });
974
- }
975
- createContext(hookPoint, data, metadata, phase) {
976
- return {
977
- component: {
978
- name: this.componentName,
979
- version: this.componentVersion
980
- },
981
- data,
982
- metadata,
983
- phase,
984
- hookPoint
985
- };
986
- }
987
- async safeExecute(hook, ctx) {
988
- try {
989
- await hook.execute(ctx);
990
- } catch (error) {
991
- console.error(`Hook "${hook.name}" failed:`, error);
992
- }
993
- }
994
- async safeExecuteAndReturn(hook, ctx) {
995
- try {
996
- return await hook.execute(ctx);
997
- } catch (error) {
998
- console.error(`Hook "${hook.name}" failed:`, error);
999
- return;
1000
- }
1001
- }
1002
- }
1003
- // packages/core/src/env/hook/global-hook-manager.ts
1004
- var globalHookManager = new HookManager;
1005
- var AgentHookPoints = {
1006
- BEFORE_START: "agent:before.start",
1007
- BEFORE_LLM: "agent:before.llm",
1008
- AFTER_LLM: "agent:after.llm",
1009
- BEFORE_TOOL: "agent:before.tool",
1010
- AFTER_TOOL: "agent:after.tool",
1011
- ON_ITERATION: "agent:on.iteration",
1012
- ON_THRESHOLD: "agent:on.threshold",
1013
- AFTER_COMPLETE: "agent:after.complete",
1014
- ON_ERROR: "agent:on.error"
1015
- };
1016
- var LLMHookPoints = {
1017
- BEFORE_INVOKE: "llm:before.invoke",
1018
- AFTER_INVOKE: "llm:after.invoke",
1019
- ON_STREAM: "llm:on.stream"
1020
- };
1021
- var ToolHookPoints = {
1022
- BEFORE_EXECUTE: "tool:before.execute",
1023
- AFTER_EXECUTE: "tool:after.execute",
1024
- BEFORE_REGISTER: "tool:before.register",
1025
- AFTER_REGISTER: "tool:after.register",
1026
- ON_ERROR: "tool:on.error"
1027
- };
1028
- var hookPointAliases = {
1029
- "before.tool": "tool:before.execute",
1030
- "after.tool": "tool:after.execute",
1031
- "llm.before-invoke": "llm:before.invoke",
1032
- "llm.after-invoke": "llm:after.invoke",
1033
- "llm.stream": "llm:on.stream"
1034
- };
1035
- function setupAliasHooks() {
1036
- const originalRegister = globalHookManager.register.bind(globalHookManager);
1037
- globalHookManager.register = function(hookPoint, hook) {
1038
- originalRegister(hookPoint, hook);
1039
- const alias = hookPointAliases[hookPoint];
1040
- if (alias) {
1041
- originalRegister(alias, hook);
1042
- }
1043
- };
1044
- }
1045
- setupAliasHooks();
1046
- async function executeAgentHook(hookPoint, data, metadata = {}) {
1047
- await globalHookManager.execute(hookPoint, data, metadata);
1048
- }
1049
- async function executeAgentHookWithIntervention(hookPoint, data, metadata = {}) {
1050
- return globalHookManager.executeWithIntervention(hookPoint, data, metadata);
1051
- }
1052
- async function executeLLMHook(hookPoint, data, metadata = {}) {
1053
- await globalHookManager.execute(hookPoint, data, metadata);
1054
- }
1055
- async function executeToolHook(hookPoint, data, metadata = {}) {
1056
- await globalHookManager.execute(hookPoint, data, metadata);
1057
- }
1058
- // packages/core/src/env/task/storage/sqlite-task-store.ts
1059
- init_logger();
1060
- import { join as join2 } from "path";
1061
- var logger = createLogger("task:store");
1062
- function getDefaultDataDir() {
1063
- const home = process.env.HOME || process.env.USERPROFILE || "/tmp";
1064
- return join2(home, ".local", "share");
1065
- }
1066
- function getDefaultTaskDbPath() {
1067
- return join2(getDefaultDataDir(), "roy-agent", "tasks.db");
1068
- }
1069
-
1070
- class SQLiteTaskStore {
1071
- db = null;
1072
- dbPath;
1073
- initialized = false;
1074
- tasksCache = new Map;
1075
- operationsCache = new Map;
1076
- constructor(dbPath) {
1077
- this.dbPath = dbPath || getDefaultTaskDbPath();
1078
- }
1079
- async initialize() {
1080
- if (this.initialized)
1081
- return;
1082
- const { Database } = __require("bun:sqlite");
1083
- if (this.dbPath !== ":memory:") {
1084
- const fs = __require("fs");
1085
- const path = __require("path");
1086
- const dir = path.dirname(this.dbPath);
1087
- if (!fs.existsSync(dir)) {
1088
- fs.mkdirSync(dir, { recursive: true });
1089
- }
1090
- }
1091
- this.db = new Database(this.dbPath);
1092
- this.db.run(`
1093
- CREATE TABLE IF NOT EXISTS task (
1094
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1095
- title TEXT NOT NULL,
1096
- description TEXT DEFAULT '',
1097
- status TEXT DEFAULT 'todo',
1098
- priority TEXT DEFAULT 'medium',
1099
- progress INTEGER DEFAULT 0,
1100
- current_status TEXT DEFAULT '',
1101
- goals_and_expected_deliverables TEXT DEFAULT '',
1102
- parent_task_id INTEGER,
1103
- created_at INTEGER NOT NULL,
1104
- updated_at INTEGER NOT NULL,
1105
- due_date TEXT,
1106
- tags TEXT
1107
- )
1108
- `);
1109
- this.db.run(`
1110
- CREATE TABLE IF NOT EXISTS task_operation (
1111
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1112
- task_id INTEGER NOT NULL,
1113
- session_id TEXT NOT NULL,
1114
- action_type TEXT NOT NULL,
1115
- action_title TEXT NOT NULL,
1116
- action_description TEXT DEFAULT '',
1117
- timestamp INTEGER NOT NULL,
1118
- md_path TEXT,
1119
- FOREIGN KEY (task_id) REFERENCES task(id) ON DELETE CASCADE
1120
- )
1121
- `);
1122
- this.db.run("CREATE INDEX IF NOT EXISTS idx_task_operation_task_id ON task_operation(task_id)");
1123
- this.db.run("CREATE INDEX IF NOT EXISTS idx_task_operation_session_id ON task_operation(session_id)");
1124
- this.db.run(`
1125
- CREATE TABLE IF NOT EXISTS task_tag (
1126
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1127
- name TEXT NOT NULL UNIQUE,
1128
- created_at INTEGER NOT NULL,
1129
- task_count INTEGER DEFAULT 0
1130
- )
1131
- `);
1132
- this.db.run(`
1133
- CREATE TABLE IF NOT EXISTS task_tag_relation (
1134
- task_id INTEGER NOT NULL,
1135
- tag_id INTEGER NOT NULL,
1136
- created_at INTEGER NOT NULL,
1137
- PRIMARY KEY (task_id, tag_id),
1138
- FOREIGN KEY (task_id) REFERENCES task(id) ON DELETE CASCADE,
1139
- FOREIGN KEY (tag_id) REFERENCES task_tag(id) ON DELETE CASCADE
1140
- )
1141
- `);
1142
- this.db.run("CREATE INDEX IF NOT EXISTS idx_task_tag_relation_tag_id ON task_tag_relation(tag_id)");
1143
- this.initialized = true;
1144
- logger.info(`TaskStore initialized at ${this.dbPath}`);
1145
- }
1146
- async createTask(options) {
1147
- await this.initialize();
1148
- const now = Date.now();
1149
- const stmt = this.db.prepare(`
1150
- INSERT INTO task (title, description, priority, parent_task_id,
1151
- goals_and_expected_deliverables, due_date, tags, status,
1152
- current_status, created_at, updated_at)
1153
- VALUES (?, ?, ?, ?, ?, ?, ?, 'todo', '', ?, ?)
1154
- `);
1155
- const result = stmt.run(options.title, options.description || "", options.priority || "medium", options.parent_task_id || null, options.goals_and_expected_deliverables || "", options.due_date || null, options.tags ? JSON.stringify(options.tags) : null, now, now);
1156
- const task = await this.getTask(result.lastInsertRowid);
1157
- if (task) {
1158
- this.tasksCache.set(task.id, task);
1159
- return task;
1160
- }
1161
- throw new Error("Failed to create task");
1162
- }
1163
- async getTask(id) {
1164
- await this.initialize();
1165
- if (this.tasksCache.has(id)) {
1166
- return this.tasksCache.get(id);
1167
- }
1168
- const stmt = this.db.prepare("SELECT * FROM task WHERE id = ?");
1169
- const row = stmt.get(id);
1170
- if (!row)
1171
- return;
1172
- const task = this.rowToTask(row);
1173
- this.tasksCache.set(id, task);
1174
- return task;
1175
- }
1176
- async updateTask(id, options) {
1177
- await this.initialize();
1178
- const task = await this.getTask(id);
1179
- if (!task)
1180
- return;
1181
- const updates = [];
1182
- const values = [];
1183
- if (options.title !== undefined) {
1184
- updates.push("title = ?");
1185
- values.push(options.title);
1186
- }
1187
- if (options.description !== undefined) {
1188
- updates.push("description = ?");
1189
- values.push(options.description);
1190
- }
1191
- if (options.status !== undefined) {
1192
- updates.push("status = ?");
1193
- values.push(options.status);
1194
- }
1195
- if (options.priority !== undefined) {
1196
- updates.push("priority = ?");
1197
- values.push(options.priority);
1198
- }
1199
- if (options.progress !== undefined) {
1200
- updates.push("progress = ?");
1201
- values.push(options.progress);
1202
- }
1203
- if (options.current_status !== undefined) {
1204
- updates.push("current_status = ?");
1205
- values.push(options.current_status);
1206
- }
1207
- if (options.goals_and_expected_deliverables !== undefined) {
1208
- updates.push("goals_and_expected_deliverables = ?");
1209
- values.push(options.goals_and_expected_deliverables);
1210
- }
1211
- if (options.due_date !== undefined) {
1212
- updates.push("due_date = ?");
1213
- values.push(options.due_date);
1214
- }
1215
- if (options.tags !== undefined) {
1216
- updates.push("tags = ?");
1217
- values.push(JSON.stringify(options.tags));
1218
- }
1219
- if (updates.length === 0)
1220
- return task;
1221
- updates.push("updated_at = ?");
1222
- values.push(Date.now());
1223
- values.push(id);
1224
- const stmt = this.db.prepare(`UPDATE task SET ${updates.join(", ")} WHERE id = ?`);
1225
- stmt.run(...values);
1226
- this.tasksCache.delete(id);
1227
- return this.getTask(id);
1228
- }
1229
- async deleteTask(id) {
1230
- await this.initialize();
1231
- const stmt = this.db.prepare("DELETE FROM task WHERE id = ?");
1232
- const result = stmt.run(id);
1233
- if (result.changes > 0) {
1234
- this.tasksCache.delete(id);
1235
- this.operationsCache.delete(id);
1236
- }
1237
- return result.changes > 0;
1238
- }
1239
- async listTasks(options) {
1240
- await this.initialize();
1241
- let sql = "SELECT * FROM task WHERE 1=1";
1242
- const params = [];
1243
- if (options?.status) {
1244
- sql += " AND status = ?";
1245
- params.push(options.status);
1246
- }
1247
- if (options?.priority) {
1248
- sql += " AND priority = ?";
1249
- params.push(options.priority);
1250
- }
1251
- if (options?.parent_task_id !== undefined) {
1252
- sql += " AND parent_task_id = ?";
1253
- params.push(options.parent_task_id);
1254
- }
1255
- sql += " ORDER BY updated_at DESC";
1256
- if (options?.limit) {
1257
- sql += " LIMIT ?";
1258
- params.push(options.limit);
1259
- }
1260
- if (options?.offset) {
1261
- sql += " OFFSET ?";
1262
- params.push(options.offset);
1263
- }
1264
- const stmt = this.db.prepare(sql);
1265
- const rows = stmt.all(...params);
1266
- return rows.map((row) => {
1267
- const task = this.rowToTask(row);
1268
- this.tasksCache.set(task.id, task);
1269
- return task;
1270
- });
1271
- }
1272
- async createOperation(options) {
1273
- await this.initialize();
1274
- const now = Date.now();
1275
- const stmt = this.db.prepare(`
1276
- INSERT INTO task_operation (task_id, session_id, action_type, action_title,
1277
- action_description, timestamp, md_path)
1278
- VALUES (?, ?, ?, ?, ?, ?, ?)
1279
- `);
1280
- const result = stmt.run(options.taskId, options.sessionId, options.actionType, options.actionTitle, options.actionDescription || "", now, options.mdPath || null);
1281
- this.operationsCache.delete(options.taskId);
1282
- const operation = await this.getOperation(result.lastInsertRowid);
1283
- if (!operation) {
1284
- throw new Error("Failed to create operation");
1285
- }
1286
- return operation;
1287
- }
1288
- async getOperation(id) {
1289
- await this.initialize();
1290
- const stmt = this.db.prepare("SELECT * FROM task_operation WHERE id = ?");
1291
- const row = stmt.get(id);
1292
- if (!row)
1293
- return;
1294
- return this.rowToOperation(row);
1295
- }
1296
- async updateOperation(id, updates) {
1297
- await this.initialize();
1298
- const op = await this.getOperation(id);
1299
- if (!op)
1300
- return;
1301
- const setClauses = [];
1302
- const values = [];
1303
- if (updates.actionTitle !== undefined) {
1304
- setClauses.push("action_title = ?");
1305
- values.push(updates.actionTitle);
1306
- }
1307
- if (updates.actionDescription !== undefined) {
1308
- setClauses.push("action_description = ?");
1309
- values.push(updates.actionDescription);
1310
- }
1311
- if (setClauses.length === 0)
1312
- return op;
1313
- const stmt = this.db.prepare(`UPDATE task_operation SET ${setClauses.join(", ")} WHERE id = ?`);
1314
- stmt.run(...values, id);
1315
- this.operationsCache.delete(op.taskId);
1316
- return this.getOperation(id);
1317
- }
1318
- async deleteOperation(id) {
1319
- await this.initialize();
1320
- const op = await this.getOperation(id);
1321
- if (!op)
1322
- return false;
1323
- const stmt = this.db.prepare("DELETE FROM task_operation WHERE id = ?");
1324
- const result = stmt.run(id);
1325
- if (result.changes > 0) {
1326
- this.operationsCache.delete(op.taskId);
1327
- }
1328
- return result.changes > 0;
1329
- }
1330
- async listOperations(options) {
1331
- await this.initialize();
1332
- const cacheKey = options.taskId;
1333
- if (!this.operationsCache.has(cacheKey)) {
1334
- const stmt = this.db.prepare("SELECT * FROM task_operation WHERE task_id = ? ORDER BY timestamp DESC");
1335
- const rows = stmt.all(options.taskId);
1336
- this.operationsCache.set(cacheKey, rows.map((row) => this.rowToOperation(row)));
1337
- }
1338
- let ops = this.operationsCache.get(cacheKey);
1339
- if (options.actionType) {
1340
- ops = ops.filter((op) => op.actionType === options.actionType);
1341
- }
1342
- const offset = options.offset || 0;
1343
- const limit = options.limit || 20;
1344
- return ops.slice(offset, offset + limit);
1345
- }
1346
- rowToTask(row) {
1347
- return {
1348
- id: row.id,
1349
- title: row.title,
1350
- description: row.description,
1351
- status: row.status,
1352
- priority: row.priority,
1353
- progress: row.progress,
1354
- current_status: row.current_status,
1355
- goals_and_expected_deliverables: row.goals_and_expected_deliverables,
1356
- parent_task_id: row.parent_task_id || undefined,
1357
- createdAt: new Date(row.created_at).toISOString(),
1358
- updatedAt: new Date(row.updated_at).toISOString(),
1359
- due_date: row.due_date || undefined,
1360
- tags: row.tags ? JSON.parse(row.tags) : undefined
1361
- };
1362
- }
1363
- rowToOperation(row) {
1364
- return {
1365
- id: row.id,
1366
- taskId: row.task_id,
1367
- sessionId: row.session_id,
1368
- actionType: row.action_type,
1369
- actionTitle: row.action_title,
1370
- actionDescription: row.action_description,
1371
- timestamp: new Date(row.timestamp).toISOString(),
1372
- mdPath: row.md_path || undefined
1373
- };
1374
- }
1375
- async createTag(name) {
1376
- await this.initialize();
1377
- const now = Date.now();
1378
- const existing = await this.getTagByName(name);
1379
- if (existing) {
1380
- return existing;
1381
- }
1382
- const stmt = this.db.prepare(`
1383
- INSERT INTO task_tag (name, created_at, task_count)
1384
- VALUES (?, ?, 0)
1385
- `);
1386
- const result = stmt.run(name, now);
1387
- return {
1388
- id: result.lastInsertRowid,
1389
- name,
1390
- createdAt: new Date(now).toISOString(),
1391
- taskCount: 0
1392
- };
1393
- }
1394
- async getTag(id) {
1395
- await this.initialize();
1396
- const stmt = this.db.prepare("SELECT * FROM task_tag WHERE id = ?");
1397
- const row = stmt.get(id);
1398
- if (!row)
1399
- return;
1400
- return this.rowToTag(row);
1401
- }
1402
- async getTagByName(name) {
1403
- await this.initialize();
1404
- const stmt = this.db.prepare("SELECT * FROM task_tag WHERE name = ?");
1405
- const row = stmt.get(name);
1406
- if (!row)
1407
- return;
1408
- return this.rowToTag(row);
1409
- }
1410
- async listTags(options) {
1411
- await this.initialize();
1412
- let sql = "SELECT * FROM task_tag";
1413
- const params = [];
1414
- const orderBy = options?.orderBy || "count";
1415
- if (orderBy === "count") {
1416
- sql += " ORDER BY task_count DESC";
1417
- } else if (orderBy === "name") {
1418
- sql += " ORDER BY name ASC";
1419
- } else {
1420
- sql += " ORDER BY created_at DESC";
1421
- }
1422
- if (options?.limit) {
1423
- sql += " LIMIT ?";
1424
- params.push(options.limit);
1425
- }
1426
- if (options?.offset) {
1427
- sql += " OFFSET ?";
1428
- params.push(options.offset);
1429
- }
1430
- const stmt = this.db.prepare(sql);
1431
- const rows = stmt.all(...params);
1432
- return rows.map((row) => this.rowToTag(row));
1433
- }
1434
- async searchTags(options) {
1435
- await this.initialize();
1436
- const sql = `
1437
- SELECT * FROM task_tag
1438
- WHERE name LIKE ?
1439
- ORDER BY task_count DESC
1440
- LIMIT ?
1441
- `;
1442
- const stmt = this.db.prepare(sql);
1443
- const rows = stmt.all(`%${options.query}%`, options.limit || 20);
1444
- return rows.map((row) => this.rowToTag(row));
1445
- }
1446
- async deleteTag(id) {
1447
- await this.initialize();
1448
- const stmt = this.db.prepare("DELETE FROM task_tag WHERE id = ?");
1449
- const result = stmt.run(id);
1450
- return result.changes > 0;
1451
- }
1452
- async addTagsToTask(taskId, tagIds) {
1453
- await this.initialize();
1454
- const now = Date.now();
1455
- const stmt = this.db.prepare(`
1456
- INSERT OR IGNORE INTO task_tag_relation (task_id, tag_id, created_at)
1457
- VALUES (?, ?, ?)
1458
- `);
1459
- for (const tagId of tagIds) {
1460
- stmt.run(taskId, tagId, now);
1461
- this.db.run(`
1462
- UPDATE task_tag SET task_count = task_count + 1 WHERE id = ?
1463
- `, tagId);
1464
- }
1465
- await this.syncTaskTagsJson(taskId);
1466
- }
1467
- async removeTagsFromTask(taskId, tagIds) {
1468
- await this.initialize();
1469
- const stmt = this.db.prepare("DELETE FROM task_tag_relation WHERE task_id = ? AND tag_id = ?");
1470
- for (const tagId of tagIds) {
1471
- stmt.run(taskId, tagId);
1472
- this.db.run(`
1473
- UPDATE task_tag SET task_count = MAX(0, task_count - 1) WHERE id = ?
1474
- `, tagId);
1475
- }
1476
- await this.syncTaskTagsJson(taskId);
1477
- }
1478
- async getTagsForTask(taskId) {
1479
- await this.initialize();
1480
- const sql = `
1481
- SELECT t.* FROM task_tag t
1482
- INNER JOIN task_tag_relation r ON t.id = r.tag_id
1483
- WHERE r.task_id = ?
1484
- ORDER BY t.name ASC
1485
- `;
1486
- const stmt = this.db.prepare(sql);
1487
- const rows = stmt.all(taskId);
1488
- return rows.map((row) => this.rowToTag(row));
1489
- }
1490
- async getTaskIdsByTags(tagNames) {
1491
- await this.initialize();
1492
- if (tagNames.length === 0)
1493
- return [];
1494
- const placeholders = tagNames.map(() => "?").join(", ");
1495
- const sql = `
1496
- SELECT DISTINCT r.task_id FROM task_tag_relation r
1497
- INNER JOIN task_tag t ON r.tag_id = t.id
1498
- WHERE t.name IN (${placeholders})
1499
- `;
1500
- const stmt = this.db.prepare(sql);
1501
- const rows = stmt.all(...tagNames);
1502
- return rows.map((row) => row.task_id);
1503
- }
1504
- async updateTaskTags(taskId, tagNames) {
1505
- await this.initialize();
1506
- const currentTags = await this.getTagsForTask(taskId);
1507
- if (currentTags.length > 0) {
1508
- await this.removeTagsFromTask(taskId, currentTags.map((t) => t.id));
1509
- }
1510
- const tagIds = [];
1511
- for (const name of tagNames) {
1512
- let tag = await this.getTagByName(name);
1513
- if (!tag) {
1514
- tag = await this.createTag(name);
1515
- }
1516
- tagIds.push(tag.id);
1517
- }
1518
- if (tagIds.length > 0) {
1519
- await this.addTagsToTask(taskId, tagIds);
1520
- }
1521
- }
1522
- async searchTasksByKeywords(keywords, options = {}) {
1523
- await this.initialize();
1524
- if (!keywords || keywords.length === 0) {
1525
- return [];
1526
- }
1527
- const { limit = 20, excludeTaskId } = options;
1528
- const tasks = new Map;
1529
- let taskSql = "SELECT * FROM task WHERE 1=1";
1530
- const taskParams = [];
1531
- if (excludeTaskId) {
1532
- taskSql += " AND id != ?";
1533
- taskParams.push(excludeTaskId);
1534
- }
1535
- taskSql += " ORDER BY updated_at DESC LIMIT ?";
1536
- taskParams.push(limit * 2);
1537
- const taskRows = this.db.prepare(taskSql).all(...taskParams);
1538
- for (const row of taskRows) {
1539
- const task = this.rowToTask(row);
1540
- let matchCount = 0;
1541
- if (task.title) {
1542
- const lowerTitle = task.title.toLowerCase();
1543
- for (const keyword of keywords) {
1544
- if (lowerTitle.includes(keyword.toLowerCase())) {
1545
- matchCount++;
1546
- }
1547
- }
1548
- }
1549
- if (task.tags && Array.isArray(task.tags)) {
1550
- for (const keyword of keywords) {
1551
- const lowerKeyword = keyword.toLowerCase();
1552
- if (task.tags.some((tag) => tag.toLowerCase().includes(lowerKeyword))) {
1553
- matchCount += 2;
1554
- }
1555
- }
1556
- }
1557
- if (task.description) {
1558
- const lowerDesc = task.description.toLowerCase();
1559
- for (const keyword of keywords) {
1560
- if (lowerDesc.includes(keyword.toLowerCase())) {
1561
- matchCount++;
1562
- }
1563
- }
1564
- }
1565
- if (task.goals_and_expected_deliverables) {
1566
- const lowerGoals = task.goals_and_expected_deliverables.toLowerCase();
1567
- for (const keyword of keywords) {
1568
- if (lowerGoals.includes(keyword.toLowerCase())) {
1569
- matchCount++;
1570
- }
1571
- }
1572
- }
1573
- if (matchCount > 0) {
1574
- tasks.set(task.id, { task, matchCount });
1575
- }
1576
- }
1577
- const allOps = this.db.prepare("SELECT DISTINCT task_id FROM task_operation WHERE 1=1").all();
1578
- for (const opRow of allOps) {
1579
- const opSql = `
1580
- SELECT * FROM task_operation
1581
- WHERE task_id = ?
1582
- AND (action_title LIKE ? OR action_description LIKE ?)
1583
- LIMIT 10
1584
- `;
1585
- for (const keyword of keywords) {
1586
- const pattern = `%${keyword}%`;
1587
- const ops = this.db.prepare(opSql).all(opRow.task_id, pattern, pattern);
1588
- if (ops.length > 0) {
1589
- const taskRow = this.db.prepare("SELECT * FROM task WHERE id = ?").get(opRow.task_id);
1590
- if (taskRow) {
1591
- const task = this.rowToTask(taskRow);
1592
- if (excludeTaskId && task.id === excludeTaskId)
1593
- continue;
1594
- const existing = tasks.get(task.id);
1595
- if (existing) {
1596
- existing.matchCount += 2;
1597
- } else {
1598
- tasks.set(task.id, { task, matchCount: 2 });
1599
- }
1600
- }
1601
- }
1602
- }
1603
- }
1604
- const results = Array.from(tasks.values()).sort((a, b) => b.matchCount - a.matchCount).slice(0, limit).map((item) => item.task);
1605
- return results;
1606
- }
1607
- async findSimilarTasksByKeywords(keywords, options = {}) {
1608
- const mergedOptions = { ...options, limit: options.limit ?? 5 };
1609
- return this.searchTasksByKeywords(keywords, mergedOptions);
1610
- }
1611
- async findSimilarTasks(taskId, limit = 5) {
1612
- await this.initialize();
1613
- const taskTags = await this.getTagsForTask(taskId);
1614
- if (taskTags.length === 0) {
1615
- return [];
1616
- }
1617
- const tagIds = taskTags.map((t) => t.id);
1618
- const placeholders = tagIds.map(() => "?").join(", ");
1619
- const sql = `
1620
- SELECT t.*, COUNT(r2.tag_id) as match_count
1621
- FROM task t
1622
- INNER JOIN task_tag_relation r ON t.id = r.task_id
1623
- INNER JOIN task_tag_relation r2 ON t.id = r2.task_id
1624
- WHERE r.tag_id IN (${placeholders})
1625
- AND t.id != ?
1626
- GROUP BY t.id
1627
- ORDER BY match_count DESC, t.updated_at DESC
1628
- LIMIT ?
1629
- `;
1630
- const stmt = this.db.prepare(sql);
1631
- const rows = stmt.all(...tagIds, taskId, limit);
1632
- return rows.map((row) => this.rowToTask(row));
1633
- }
1634
- async searchTasks(query, limit = 20) {
1635
- await this.initialize();
1636
- const sql = `
1637
- SELECT * FROM task
1638
- WHERE title LIKE ? OR description LIKE ?
1639
- ORDER BY updated_at DESC
1640
- LIMIT ?
1641
- `;
1642
- const stmt = this.db.prepare(sql);
1643
- const rows = stmt.all(`%${query}%`, `%${query}%`, limit);
1644
- return rows.map((row) => this.rowToTask(row));
1645
- }
1646
- rowToTag(row) {
1647
- return {
1648
- id: row.id,
1649
- name: row.name,
1650
- createdAt: new Date(row.created_at).toISOString(),
1651
- taskCount: row.task_count
1652
- };
1653
- }
1654
- async syncTaskTagsJson(taskId) {
1655
- const tags = await this.getTagsForTask(taskId);
1656
- const tagNames = tags.map((t) => t.name);
1657
- const stmt = this.db.prepare("UPDATE task SET tags = ? WHERE id = ?");
1658
- stmt.run(tagNames.length > 0 ? JSON.stringify(tagNames) : null, taskId);
1659
- this.tasksCache.delete(taskId);
1660
- }
1661
- async close() {
1662
- if (this.db) {
1663
- this.db.close();
1664
- this.db = null;
1665
- this.initialized = false;
1666
- }
1667
- }
1668
- }
1669
- // packages/core/src/env/task/tools/task-types.ts
1670
- import { z } from "zod";
1671
- var CreateTaskToolSchema = z.object({
1672
- title: z.string().describe("Task title"),
1673
- description: z.string().optional().describe("Task description"),
1674
- priority: z.enum(["low", "medium", "high"]).optional().describe("Task priority"),
1675
- goals_and_expected_deliverables: z.string().optional().describe("Goals and expected deliverables"),
1676
- due_date: z.string().optional().describe("Due date (ISO format)"),
1677
- tags: z.array(z.string()).optional().describe("Task tags (for search, stored in task.tags JSON field)")
1678
- });
1679
- var GetTaskToolSchema = z.object({
1680
- task_id: z.number().describe("Task ID"),
1681
- include_operations: z.boolean().optional().default(false).describe("Include operation records")
1682
- });
1683
- var ListTasksToolSchema = z.object({
1684
- status: z.enum(["todo", "active", "completed", "paused", "cancelled"]).optional(),
1685
- priority: z.enum(["low", "medium", "high"]).optional(),
1686
- limit: z.number().optional().default(20),
1687
- offset: z.number().optional().default(0)
1688
- });
1689
- var UpdateTaskToolSchema = z.object({
1690
- task_id: z.number().describe("Task ID"),
1691
- title: z.string().optional(),
1692
- description: z.string().optional(),
1693
- status: z.enum(["todo", "active", "completed", "paused", "cancelled"]).optional(),
1694
- priority: z.enum(["low", "medium", "high"]).optional(),
1695
- progress: z.number().min(0).max(100).optional(),
1696
- current_status: z.string().optional(),
1697
- goals_and_expected_deliverables: z.string().optional(),
1698
- due_date: z.string().optional(),
1699
- tags: z.array(z.string()).optional()
1700
- });
1701
- var DeleteTaskToolSchema = z.object({
1702
- task_id: z.number().describe("Task ID")
1703
- });
1704
-
1705
- // packages/core/src/env/task/tools/create-tool.ts
1706
- function createTaskTool(taskComponent) {
1707
- return {
1708
- name: "task_create",
1709
- description: "Create a new task. The task will be associated with the current session.",
1710
- parameters: CreateTaskToolSchema,
1711
- execute: async (args, ctx) => {
1712
- const params = CreateTaskToolSchema.parse(args);
1713
- const sessionId = ctx.session_id || "unknown";
1714
- try {
1715
- const task = await taskComponent.createTask({
1716
- title: params.title,
1717
- description: params.description,
1718
- priority: params.priority,
1719
- goals_and_expected_deliverables: params.goals_and_expected_deliverables,
1720
- due_date: params.due_date,
1721
- tags: params.tags,
1722
- sessionId
1723
- });
1724
- return {
1725
- success: true,
1726
- output: `Task created successfully: #${task.id} - ${task.title}`,
1727
- metadata: {
1728
- execution_time_ms: 0,
1729
- task_id: task.id,
1730
- status: task.status,
1731
- createdAt: task.createdAt
1732
- }
1733
- };
1734
- } catch (error) {
1735
- return {
1736
- success: false,
1737
- output: "",
1738
- error: error instanceof Error ? error.message : String(error),
1739
- metadata: { execution_time_ms: 0 }
1740
- };
1741
- }
1742
- }
1743
- };
1744
- }
1745
- // packages/core/src/env/task/tools/get-tool.ts
1746
- function getTaskTool(taskComponent) {
1747
- return {
1748
- name: "task_get",
1749
- description: "Get task details by ID. Optionally include operation records.",
1750
- parameters: GetTaskToolSchema,
1751
- execute: async (args, ctx) => {
1752
- const params = GetTaskToolSchema.parse(args);
1753
- try {
1754
- if (params.include_operations) {
1755
- const result = await taskComponent.getTaskWithOperations(params.task_id);
1756
- if (!result) {
1757
- return {
1758
- success: false,
1759
- output: "",
1760
- error: `Task not found: ${params.task_id}`,
1761
- metadata: { execution_time_ms: 0 }
1762
- };
1763
- }
1764
- return {
1765
- success: true,
1766
- output: JSON.stringify(result, null, 2),
1767
- metadata: { execution_time_ms: 0 }
1768
- };
1769
- } else {
1770
- const task = await taskComponent.getTask(params.task_id);
1771
- if (!task) {
1772
- return {
1773
- success: false,
1774
- output: "",
1775
- error: `Task not found: ${params.task_id}`,
1776
- metadata: { execution_time_ms: 0 }
1777
- };
1778
- }
1779
- return {
1780
- success: true,
1781
- output: JSON.stringify(task, null, 2),
1782
- metadata: { execution_time_ms: 0 }
1783
- };
1784
- }
1785
- } catch (error) {
1786
- return {
1787
- success: false,
1788
- output: "",
1789
- error: error instanceof Error ? error.message : String(error),
1790
- metadata: { execution_time_ms: 0 }
1791
- };
1792
- }
1793
- }
1794
- };
1795
- }
1796
- // packages/core/src/env/task/tools/list-tool.ts
1797
- function listTasksTool(taskComponent) {
1798
- return {
1799
- name: "task_list",
1800
- description: "List tasks with optional filters for status and priority.",
1801
- parameters: ListTasksToolSchema,
1802
- execute: async (args, ctx) => {
1803
- const params = ListTasksToolSchema.parse(args);
1804
- try {
1805
- const tasks = await taskComponent.listTasks({
1806
- status: params.status,
1807
- priority: params.priority,
1808
- limit: params.limit,
1809
- offset: params.offset
1810
- });
1811
- return {
1812
- success: true,
1813
- output: JSON.stringify({ tasks, count: tasks.length }),
1814
- metadata: { execution_time_ms: 0 }
1815
- };
1816
- } catch (error) {
1817
- return {
1818
- success: false,
1819
- output: "",
1820
- error: error instanceof Error ? error.message : String(error),
1821
- metadata: { execution_time_ms: 0 }
1822
- };
1823
- }
1824
- }
1825
- };
1826
- }
1827
- // packages/core/src/env/task/tools/update-tool.ts
1828
- function updateTaskTool(taskComponent) {
1829
- return {
1830
- name: "task_update",
1831
- description: "Update an existing task's properties. Status and progress changes will create operation records.",
1832
- parameters: UpdateTaskToolSchema,
1833
- execute: async (args, ctx) => {
1834
- const params = UpdateTaskToolSchema.parse(args);
1835
- const sessionId = ctx.session_id || "unknown";
1836
- try {
1837
- const task = await taskComponent.updateTask(params.task_id, {
1838
- title: params.title,
1839
- description: params.description,
1840
- status: params.status,
1841
- priority: params.priority,
1842
- progress: params.progress,
1843
- current_status: params.current_status,
1844
- goals_and_expected_deliverables: params.goals_and_expected_deliverables,
1845
- due_date: params.due_date,
1846
- tags: params.tags
1847
- });
1848
- if (!task) {
1849
- return {
1850
- success: false,
1851
- output: "",
1852
- error: `Task not found: ${params.task_id}`,
1853
- metadata: { execution_time_ms: 0 }
1854
- };
1855
- }
1856
- if (params.status || params.progress !== undefined || params.current_status) {
1857
- await taskComponent.createOperation({
1858
- taskId: params.task_id,
1859
- sessionId,
1860
- actionType: "progress",
1861
- actionTitle: params.current_status || `Updated: ${params.status || `${params.progress}%`}`,
1862
- actionDescription: JSON.stringify({
1863
- status: params.status,
1864
- progress: params.progress,
1865
- current_status: params.current_status
1866
- })
1867
- });
1868
- }
1869
- return {
1870
- success: true,
1871
- output: `Task updated: #${task.id} - ${task.title}`,
1872
- metadata: { execution_time_ms: 0, task }
1873
- };
1874
- } catch (error) {
1875
- return {
1876
- success: false,
1877
- output: "",
1878
- error: error instanceof Error ? error.message : String(error),
1879
- metadata: { execution_time_ms: 0 }
1880
- };
1881
- }
1882
- }
1883
- };
1884
- }
1885
- // packages/core/src/env/task/tools/delete-tool.ts
1886
- function deleteTaskTool(taskComponent) {
1887
- return {
1888
- name: "task_delete",
1889
- description: "Delete a task and all its operation records.",
1890
- parameters: DeleteTaskToolSchema,
1891
- execute: async (args, ctx) => {
1892
- const params = DeleteTaskToolSchema.parse(args);
1893
- try {
1894
- const deleted = await taskComponent.deleteTask(params.task_id);
1895
- if (!deleted) {
1896
- return {
1897
- success: false,
1898
- output: "",
1899
- error: `Task not found: ${params.task_id}`,
1900
- metadata: { execution_time_ms: 0 }
1901
- };
1902
- }
1903
- return {
1904
- success: true,
1905
- output: `Task deleted: #${params.task_id}`,
1906
- metadata: { execution_time_ms: 0 }
1907
- };
1908
- } catch (error) {
1909
- return {
1910
- success: false,
1911
- output: "",
1912
- error: error instanceof Error ? error.message : String(error),
1913
- metadata: { execution_time_ms: 0 }
1914
- };
1915
- }
1916
- }
1917
- };
1918
- }
1919
- // packages/core/src/env/task/tools/complete-tool.ts
1920
- function completeTaskTool(taskComponent) {
1921
- return {
1922
- name: "task_complete",
1923
- description: "Mark a task as completed (progress=100, status=completed). Creates an operation record.",
1924
- parameters: DeleteTaskToolSchema,
1925
- execute: async (args, ctx) => {
1926
- const params = DeleteTaskToolSchema.parse(args);
1927
- const sessionId = ctx.session_id || "unknown";
1928
- try {
1929
- const task = await taskComponent.completeTask(params.task_id, sessionId);
1930
- if (!task) {
1931
- return {
1932
- success: false,
1933
- output: "",
1934
- error: `Task not found: ${params.task_id}`,
1935
- metadata: { execution_time_ms: 0 }
1936
- };
1937
- }
1938
- return {
1939
- success: true,
1940
- output: `Task completed: #${task.id} - ${task.title}`,
1941
- metadata: { execution_time_ms: 0, task }
1942
- };
1943
- } catch (error) {
1944
- return {
1945
- success: false,
1946
- output: "",
1947
- error: error instanceof Error ? error.message : String(error),
1948
- metadata: { execution_time_ms: 0 }
1949
- };
1950
- }
1951
- }
1952
- };
1953
- }
1954
- // packages/core/src/env/task/tools/operation/operation-types.ts
1955
- import { z as z2 } from "zod";
1956
- var ActionTypeEnum = z2.enum([
1957
- "create",
1958
- "progress",
1959
- "milestone",
1960
- "problem",
1961
- "solution",
1962
- "decision",
1963
- "review",
1964
- "completed"
1965
- ]);
1966
- var CreateOperationToolSchema = z2.object({
1967
- task_id: z2.number().describe("Task ID"),
1968
- action_type: ActionTypeEnum.describe("Type of action"),
1969
- action_title: z2.string().describe("Title of the action"),
1970
- action_description: z2.string().optional().describe("Detailed description"),
1971
- md_path: z2.string().optional().describe("Path to detailed markdown documentation")
1972
- });
1973
- var GetOperationToolSchema = z2.object({
1974
- operation_id: z2.number().describe("Operation ID")
1975
- });
1976
- var ListOperationsToolSchema = z2.object({
1977
- task_id: z2.number().describe("Task ID"),
1978
- action_type: ActionTypeEnum.optional(),
1979
- limit: z2.number().optional().default(20),
1980
- offset: z2.number().optional().default(0)
1981
- });
1982
- var UpdateOperationToolSchema = z2.object({
1983
- operation_id: z2.number().describe("Operation ID"),
1984
- action_title: z2.string().optional(),
1985
- action_description: z2.string().optional()
1986
- });
1987
- var DeleteOperationToolSchema = z2.object({
1988
- operation_id: z2.number().describe("Operation ID")
1989
- });
1990
-
1991
- // packages/core/src/env/task/tools/operation/create-tool.ts
1992
- function createOperationTool(taskComponent) {
1993
- return {
1994
- name: "task_operation_create",
1995
- description: "Create an operation record for a task. Tracks progress, milestones, problems, etc.",
1996
- parameters: CreateOperationToolSchema,
1997
- execute: async (args, ctx) => {
1998
- const params = CreateOperationToolSchema.parse(args);
1999
- const sessionId = ctx.session_id || "unknown";
2000
- try {
2001
- const operation = await taskComponent.createOperation({
2002
- taskId: params.task_id,
2003
- sessionId,
2004
- actionType: params.action_type,
2005
- actionTitle: params.action_title,
2006
- actionDescription: params.action_description,
2007
- mdPath: params.md_path
2008
- });
2009
- return {
2010
- success: true,
2011
- output: `Operation created: #${operation.id} for task #${operation.taskId}`,
2012
- metadata: {
2013
- execution_time_ms: 0,
2014
- operation_id: operation.id,
2015
- task_id: operation.taskId,
2016
- session_id: operation.sessionId
2017
- }
2018
- };
2019
- } catch (error) {
2020
- return {
2021
- success: false,
2022
- output: "",
2023
- error: error instanceof Error ? error.message : String(error),
2024
- metadata: { execution_time_ms: 0 }
2025
- };
2026
- }
2027
- }
2028
- };
2029
- }
2030
- // packages/core/src/env/task/tools/operation/get-tool.ts
2031
- function getOperationTool(taskComponent) {
2032
- return {
2033
- name: "task_operation_get",
2034
- description: "Get a single operation record by ID.",
2035
- parameters: GetOperationToolSchema,
2036
- execute: async (args, ctx) => {
2037
- const params = GetOperationToolSchema.parse(args);
2038
- try {
2039
- const operation = await taskComponent.getOperation(params.operation_id);
2040
- if (!operation) {
2041
- return {
2042
- success: false,
2043
- output: "",
2044
- error: `Operation not found: ${params.operation_id}`,
2045
- metadata: { execution_time_ms: 0 }
2046
- };
2047
- }
2048
- return {
2049
- success: true,
2050
- output: JSON.stringify(operation, null, 2),
2051
- metadata: { execution_time_ms: 0 }
2052
- };
2053
- } catch (error) {
2054
- return {
2055
- success: false,
2056
- output: "",
2057
- error: error instanceof Error ? error.message : String(error),
2058
- metadata: { execution_time_ms: 0 }
2059
- };
2060
- }
2061
- }
2062
- };
2063
- }
2064
- // packages/core/src/env/task/tools/operation/list-tool.ts
2065
- function listOperationsTool(taskComponent) {
2066
- return {
2067
- name: "task_operation_list",
2068
- description: "List operation records for a task with optional filters.",
2069
- parameters: ListOperationsToolSchema,
2070
- execute: async (args, ctx) => {
2071
- const params = ListOperationsToolSchema.parse(args);
2072
- try {
2073
- const operations = await taskComponent.listOperations({
2074
- taskId: params.task_id,
2075
- actionType: params.action_type,
2076
- limit: params.limit,
2077
- offset: params.offset
2078
- });
2079
- return {
2080
- success: true,
2081
- output: JSON.stringify({ operations, count: operations.length }),
2082
- metadata: { execution_time_ms: 0 }
2083
- };
2084
- } catch (error) {
2085
- return {
2086
- success: false,
2087
- output: "",
2088
- error: error instanceof Error ? error.message : String(error),
2089
- metadata: { execution_time_ms: 0 }
2090
- };
2091
- }
2092
- }
2093
- };
2094
- }
2095
- // packages/core/src/env/task/tools/operation/update-tool.ts
2096
- function updateOperationTool(taskComponent) {
2097
- return {
2098
- name: "task_operation_update",
2099
- description: "Update an operation record's title or description.",
2100
- parameters: UpdateOperationToolSchema,
2101
- execute: async (args, ctx) => {
2102
- const params = UpdateOperationToolSchema.parse(args);
2103
- try {
2104
- const operation = await taskComponent.updateOperation(params.operation_id, {
2105
- actionTitle: params.action_title,
2106
- actionDescription: params.action_description
2107
- });
2108
- if (!operation) {
2109
- return {
2110
- success: false,
2111
- output: "",
2112
- error: `Operation not found: ${params.operation_id}`,
2113
- metadata: { execution_time_ms: 0 }
2114
- };
2115
- }
2116
- return {
2117
- success: true,
2118
- output: `Operation updated: #${operation.id}`,
2119
- metadata: { execution_time_ms: 0, operation }
2120
- };
2121
- } catch (error) {
2122
- return {
2123
- success: false,
2124
- output: "",
2125
- error: error instanceof Error ? error.message : String(error),
2126
- metadata: { execution_time_ms: 0 }
2127
- };
2128
- }
2129
- }
2130
- };
2131
- }
2132
- // packages/core/src/env/task/tools/operation/delete-tool.ts
2133
- function deleteOperationTool(taskComponent) {
2134
- return {
2135
- name: "task_operation_delete",
2136
- description: "Delete an operation record.",
2137
- parameters: DeleteOperationToolSchema,
2138
- execute: async (args, ctx) => {
2139
- const params = DeleteOperationToolSchema.parse(args);
2140
- try {
2141
- const deleted = await taskComponent.deleteOperation(params.operation_id);
2142
- if (!deleted) {
2143
- return {
2144
- success: false,
2145
- output: "",
2146
- error: `Operation not found: ${params.operation_id}`,
2147
- metadata: { execution_time_ms: 0 }
2148
- };
2149
- }
2150
- return {
2151
- success: true,
2152
- output: `Operation deleted: #${params.operation_id}`,
2153
- metadata: { execution_time_ms: 0 }
2154
- };
2155
- } catch (error) {
2156
- return {
2157
- success: false,
2158
- output: "",
2159
- error: error instanceof Error ? error.message : String(error),
2160
- metadata: { execution_time_ms: 0 }
2161
- };
2162
- }
2163
- }
2164
- };
2165
- }
2166
- // packages/core/src/env/task/hooks/task-hook-points.ts
2167
- var TaskHookPoints = {
2168
- BEFORE_CREATE: "task:before.create",
2169
- AFTER_CREATE: "task:after.create",
2170
- BEFORE_UPDATE: "task:before.update",
2171
- AFTER_UPDATE: "task:after.update",
2172
- BEFORE_DELETE: "task:before.delete",
2173
- AFTER_DELETE: "task:after.delete",
2174
- DELEGATE_BEFORE: "task:delegate:before",
2175
- DELEGATE_AFTER: "task:delegate:after",
2176
- OPERATION_BEFORE_CREATE: "task:operation:before.create",
2177
- OPERATION_AFTER_CREATE: "task:operation:after.create"
2178
- };
2179
- // packages/core/src/env/task/delegate/delegate-tool.ts
2180
- init_logger();
2181
- import { z as z3 } from "zod";
2182
-
2183
- // packages/core/src/env/task/delegate/task-events.ts
2184
- var TaskEventTypes = {
2185
- TASK_STARTED: "task.started",
2186
- TASK_PROGRESS: "task.progress",
2187
- TASK_COMPLETED: "task.completed",
2188
- TASK_FAILED: "task.failed",
2189
- TASK_TIMEOUT: "task.timeout",
2190
- TASK_STOPPED: "task.stopped"
2191
- };
2192
- function createTaskStartedPayload(task, parentSessionId) {
2193
- return {
2194
- taskId: task.id,
2195
- subSessionId: task.subSessionId,
2196
- parentSessionId,
2197
- description: task.description,
2198
- subagentType: task.subagentType,
2199
- associatedTaskId: task.taskId
2200
- };
2201
- }
2202
- function createTaskProgressPayload(task, parentSessionId) {
2203
- return {
2204
- taskId: task.id,
2205
- subSessionId: task.subSessionId,
2206
- parentSessionId,
2207
- status: task.status,
2208
- progress: task.progress,
2209
- progressMessage: task.progressMessage,
2210
- description: task.description,
2211
- subagentType: task.subagentType
2212
- };
2213
- }
2214
- function createTaskCompletedPayload(task, parentSessionId, executionTimeMs) {
2215
- return {
2216
- taskId: task.id,
2217
- subSessionId: task.subSessionId,
2218
- parentSessionId,
2219
- status: task.status,
2220
- result: task.result,
2221
- error: task.error,
2222
- executionTimeMs,
2223
- associatedTaskId: task.taskId,
2224
- description: task.description,
2225
- subagentType: task.subagentType
2226
- };
2227
- }
2228
-
2229
- // packages/core/src/env/task/delegate/delegate-tool.ts
2230
- var logger2 = createLogger("task:delegate");
2231
- var builtInSubAgents = [
2232
- {
2233
- id: "general",
2234
- name: "general",
2235
- mode: "subagent",
2236
- description: "General-purpose agent for researching complex questions and executing multi-step tasks.",
2237
- promptOverride: `You are a subagent created by the main agent to handle a specific task.
2238
-
2239
- ## Your Role
2240
- - You were created to handle: {task_description}
2241
- - Complete this task. That's your entire purpose.
2242
- - You are NOT the main agent. Don't try to be.
2243
-
2244
- ## Task Context Awareness (Required Behavior)
2245
-
2246
- **IMPORTANT: Before starting any work, you MUST gather task context to avoid working with outdated or missing information.**
2247
-
2248
- 1. **Read task details first**: Use \`task_get\` to read the task's:
2249
- - \`description\`: Detailed description of what needs to be done
2250
- - \`goals_and_expected_deliverables\`: Clear success criteria and expected outputs
2251
- - \`current_status\`: Current work progress
2252
- - \`parent_task_id\`: If exists, this is a sub-task
2253
-
2254
- 2. **Read recent operations**: Use \`task_operation_list\` to get the last ~15 operation records
2255
- - These provide history, progress, decisions, and context from previous work
2256
-
2257
- 3. **Read parent task context** (if \`parent_task_id\` exists):
2258
- - Use \`task_get\` to read the parent task's description and goals
2259
- - Use \`task_operation_list\` to get parent's recent operations
2260
- - This forms the overall task background and ensures alignment
2261
-
2262
- **Why this matters**:
2263
- - The main agent may have made critical decisions recorded in operations
2264
- - Parent task goals provide the broader context for your sub-task
2265
- - Without this context, you risk working on wrong/outdated goals
2266
-
2267
- ## Rules
2268
- 1. **Gather context first** - Always read task details and operations before starting
2269
- 2. **Stay focused** - Do your assigned task, nothing else
2270
- 3. **Complete the task** - Your final message will be automatically reported to the main agent
2271
- 4. **Don't initiate** - No heartbeats, no proactive actions, no side quests
2272
- 5. **Be ephemeral** - You may be terminated after task completion. That's fine.
2273
- 6. **No nested delegation** - Do NOT use delegate_task or stop_task tools. Complete the task yourself.
2274
-
2275
- ## Execution
2276
- - Use the available tools to complete the task
2277
- - If you need more information, ask the main agent through the result
2278
- - Return a clear summary of what you did and the results`,
2279
- deniedTools: ["delegate_task", "stop_task"]
2280
- },
2281
- {
2282
- id: "explore",
2283
- name: "explore",
2284
- mode: "subagent",
2285
- description: "Fast agent specialized for exploring codebases, finding files, and searching for patterns.",
2286
- allowedTools: ["glob", "grep", "read", "bash"],
2287
- deniedTools: ["delegate_task", "stop_task"]
2288
- },
2289
- {
2290
- id: "file_agent",
2291
- name: "file_agent",
2292
- mode: "subagent",
2293
- description: "File operation expert, skilled at reading, writing, searching and organizing files.",
2294
- allowedTools: ["file_read", "file_write", "file_glob", "grep", "glob", "read"],
2295
- deniedTools: ["delegate_task", "stop_task"]
2296
- },
2297
- {
2298
- id: "web_search_agent",
2299
- name: "web_search_agent",
2300
- mode: "subagent",
2301
- description: "Web search expert, using Exa search engine to get latest information.",
2302
- allowedTools: ["exa_web_search_exa"],
2303
- deniedTools: ["delegate_task", "stop_task"]
2304
- }
2305
- ];
2306
- function getSubAgentSpec(id) {
2307
- return builtInSubAgents.find((agent) => agent.id === id);
2308
- }
2309
- function getSubAgentToolDescription() {
2310
- return builtInSubAgents.map((agent) => `- ${agent.id}: ${agent.description}`).join(`
2311
- `);
2312
- }
2313
- function ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools) {
2314
- let agentInstance = agentComponent.getAgent(subagentType);
2315
- if (!agentInstance) {
2316
- const agentConfig = {
2317
- type: "sub",
2318
- systemPrompt: basePrompt
2319
- };
2320
- if (subAgent?.allowedTools && subAgent.allowedTools.length > 0) {
2321
- agentConfig.allowedTools = subAgent.allowedTools;
2322
- }
2323
- if (deniedTools.length > 0) {
2324
- agentConfig.deniedTools = deniedTools;
2325
- }
2326
- agentInstance = agentComponent.registerAgent(subagentType, agentConfig);
2327
- logger2.debug(`[delegate] Registered subagent: ${subagentType}`);
2328
- }
2329
- return agentInstance;
2330
- }
2331
- var DelegateToolParameters = z3.object({
2332
- description: z3.string().describe("A short (3-5 words) description of the task"),
2333
- prompt: z3.string().describe("The task for the agent to perform"),
2334
- subagent_type: z3.string().describe("The type of specialized agent to use for this task").default("general"),
2335
- background: z3.boolean().describe("Whether to run the task in background. If true, returns immediately and notifies when complete (default: false)").default(false),
2336
- timeout: z3.number().describe("Task timeout in milliseconds. If set, task will be terminated after timeout (optional)").optional(),
2337
- cleanup: z3.enum(["delete", "keep"]).describe("Whether to delete sub session after completion. 'delete' removes the session, 'keep' retains it (default: keep)").default("keep").optional(),
2338
- task_id: z3.number().describe("Optional task ID to associate with this delegate task, for tracking in operation records").optional(),
2339
- reason: z3.string().describe("Brief reason for calling this tool (max 30 chars, e.g., 'Delegate refactor task')").optional()
2340
- });
2341
- var DEFAULT_TIMEOUT = 900000;
2342
- var PROGRESS_INTERVAL = 120000;
2343
-
2344
- class BackgroundTaskManager {
2345
- env;
2346
- tasks = new Map;
2347
- progressTimers = new Map;
2348
- abortControllers = new Map;
2349
- constructor(env) {
2350
- this.env = env;
2351
- }
2352
- getSessionComponent() {
2353
- return this.env?.getComponent?.("session");
2354
- }
2355
- async createTask(options) {
2356
- const { parentSessionId, description, prompt, subagentType, timeout, cleanup, taskId } = options;
2357
- const taskIdGen = `task_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
2358
- const sessionComponent = this.getSessionComponent();
2359
- if (!sessionComponent) {
2360
- throw new Error("SessionComponent not found");
2361
- }
2362
- const parentSession = await sessionComponent.get(parentSessionId);
2363
- if (!parentSession) {
2364
- throw new Error(`Parent session not found: ${parentSessionId}`);
2365
- }
2366
- const metadata = {
2367
- subagent_type: subagentType,
2368
- created_by: "subagent",
2369
- task_description: description
2370
- };
2371
- if (taskId) {
2372
- metadata.task_id = taskId;
2373
- }
2374
- const subSession = await sessionComponent.create({
2375
- title: `${description} (@${subagentType} subagent)`,
2376
- metadata
2377
- });
2378
- if (!subSession) {
2379
- throw new Error("Failed to create sub-session");
2380
- }
2381
- const abortController = new AbortController;
2382
- const task = {
2383
- id: taskIdGen,
2384
- subSessionId: subSession.id,
2385
- parentSessionId,
2386
- description,
2387
- subagentType,
2388
- status: "pending",
2389
- createdAt: Date.now(),
2390
- abortController,
2391
- taskId
2392
- };
2393
- this.tasks.set(taskIdGen, task);
2394
- this.abortControllers.set(taskIdGen, abortController);
2395
- this.publishEvent(TaskEventTypes.TASK_STARTED, createTaskStartedPayload(task, parentSessionId), parentSessionId);
2396
- this.executeTask(taskIdGen, prompt, timeout, cleanup, parentSessionId).catch((err) => {
2397
- logger2.error(`[BackgroundTaskManager] executeTask unhandled rejection`, {
2398
- taskId: taskIdGen,
2399
- error: err instanceof Error ? err.message : String(err)
2400
- });
2401
- });
2402
- return { taskId: taskIdGen, subSessionId: subSession.id };
2403
- }
2404
- async executeTask(taskId, prompt, timeout, cleanup, parentSessionId) {
2405
- const task = this.tasks.get(taskId);
2406
- if (!task) {
2407
- logger2.warn(`[BackgroundTaskManager] executeTask: Task not found`, { taskId });
2408
- return;
2409
- }
2410
- task.status = "running";
2411
- task.startedAt = Date.now();
2412
- const timeoutMs = timeout || DEFAULT_TIMEOUT;
2413
- const abortController = this.abortControllers.get(taskId);
2414
- this.startProgressReporter(taskId, parentSessionId || task.parentSessionId);
2415
- try {
2416
- const sessionComponent = this.getSessionComponent();
2417
- const subSession = await sessionComponent.get(task.subSessionId);
2418
- if (!subSession) {
2419
- throw new Error(`Sub session not found: ${task.subSessionId}`);
2420
- }
2421
- const result = await this.executeWithAbort(subSession, prompt, timeoutMs, abortController?.signal);
2422
- if (abortController?.signal.aborted) {
2423
- logger2.info(`[BackgroundTaskManager] Task was aborted`, { taskId });
2424
- return;
2425
- }
2426
- task.status = "completed";
2427
- task.completedAt = Date.now();
2428
- task.result = result;
2429
- const executionTimeMs = task.completedAt - task.startedAt;
2430
- this.publishEvent(TaskEventTypes.TASK_COMPLETED, createTaskCompletedPayload(task, parentSessionId || task.parentSessionId, executionTimeMs), parentSessionId || task.parentSessionId);
2431
- logger2.info(`[BackgroundTaskManager] Task completed successfully`, {
2432
- taskId,
2433
- executionTimeMs
2434
- });
2435
- } catch (error) {
2436
- const errorMessage = error instanceof Error ? error.message : String(error);
2437
- const isStoppedError = errorMessage.toLowerCase().includes("stopped") || errorMessage.toLowerCase().includes("aborted");
2438
- if (isStoppedError) {
2439
- task.status = "stopped";
2440
- this.publishEvent(TaskEventTypes.TASK_STOPPED, createTaskCompletedPayload(task, parentSessionId || task.parentSessionId, task.completedAt - task.startedAt), parentSessionId || task.parentSessionId);
2441
- } else if (errorMessage.includes("timeout")) {
2442
- task.status = "timeout";
2443
- this.publishEvent(TaskEventTypes.TASK_TIMEOUT, createTaskCompletedPayload(task, parentSessionId || task.parentSessionId, task.completedAt - task.startedAt), parentSessionId || task.parentSessionId);
2444
- } else {
2445
- task.status = "failed";
2446
- this.publishEvent(TaskEventTypes.TASK_FAILED, createTaskCompletedPayload(task, parentSessionId || task.parentSessionId, task.completedAt - task.startedAt), parentSessionId || task.parentSessionId);
2447
- }
2448
- task.error = errorMessage;
2449
- task.completedAt = Date.now();
2450
- logger2.error(`[BackgroundTaskManager] Task execution error`, {
2451
- taskId,
2452
- status: task.status,
2453
- error: errorMessage
2454
- });
2455
- } finally {
2456
- this.stopProgressReporter(taskId);
2457
- }
2458
- }
2459
- async executeWithAbort(subSession, prompt, timeoutMs, signal) {
2460
- return new Promise((resolve, reject) => {
2461
- const timer = setTimeout(() => {
2462
- reject(new Error(`Task execution timeout after ${timeoutMs}ms`));
2463
- }, timeoutMs);
2464
- signal?.addEventListener("abort", () => {
2465
- clearTimeout(timer);
2466
- reject(new Error("Task execution stopped"));
2467
- });
2468
- const metadata = subSession.info?.metadata || {};
2469
- const taskId = metadata.task_id;
2470
- const taskDescription = metadata.task_description || "";
2471
- const sessionId = subSession.id;
2472
- const subagentType = metadata.subagent_type || "general";
2473
- const subAgent = getSubAgentSpec(subagentType);
2474
- let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
2475
- const deniedTools = subAgent?.deniedTools || [];
2476
- let fullPrompt = basePrompt.replace(/{task_description}/g, taskDescription || "N/A");
2477
- fullPrompt += `
2478
-
2479
- ---
2480
-
2481
- # Session Info
2482
- - task_id: ${taskId || "N/A"}
2483
- - session_id: ${sessionId}
2484
-
2485
- ---
2486
-
2487
- ## \u7528\u6237\u6307\u4EE4
2488
- ${prompt}
2489
-
2490
- ---
2491
-
2492
- ## \u6267\u884C\u89C4\u8303
2493
- - \u4F7F\u7528\u53EF\u7528\u5DE5\u5177\u5B8C\u6210\u4EFB\u52A1
2494
- - \u8FD4\u56DE\u6E05\u6670\u7684\u4EFB\u52A1\u6267\u884C\u7ED3\u679C\u6458\u8981
2495
- - \u9002\u65F6\u8C03\u7528 task_operation_create \u8BB0\u5F55\u8FDB\u5C55`;
2496
- const agentComponent = this.env?.getComponent?.("agent");
2497
- if (!agentComponent) {
2498
- clearTimeout(timer);
2499
- reject(new Error("AgentComponent not found"));
2500
- return;
2501
- }
2502
- ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
2503
- this.env.handle_query?.(fullPrompt, {
2504
- sessionId,
2505
- deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
2506
- agentType: subagentType
2507
- }).then((result) => {
2508
- clearTimeout(timer);
2509
- resolve(result);
2510
- }).catch((error) => {
2511
- clearTimeout(timer);
2512
- reject(error);
2513
- });
2514
- });
2515
- }
2516
- startProgressReporter(taskId, parentSessionId) {
2517
- const timer = setInterval(() => {
2518
- const task = this.tasks.get(taskId);
2519
- if (!task || task.status !== "running") {
2520
- this.stopProgressReporter(taskId);
2521
- return;
2522
- }
2523
- if (task.startedAt) {
2524
- const elapsedMs = Date.now() - task.startedAt;
2525
- task.progress = Math.min(95, Math.floor(elapsedMs / PROGRESS_INTERVAL * 100));
2526
- }
2527
- this.publishEvent(TaskEventTypes.TASK_PROGRESS, createTaskProgressPayload(task, parentSessionId), parentSessionId);
2528
- }, PROGRESS_INTERVAL);
2529
- this.progressTimers.set(taskId, timer);
2530
- }
2531
- stopProgressReporter(taskId) {
2532
- const timer = this.progressTimers.get(taskId);
2533
- if (timer) {
2534
- clearInterval(timer);
2535
- this.progressTimers.delete(taskId);
2536
- }
2537
- }
2538
- publishEvent(type, payload, triggerSessionId) {
2539
- if (this.env?.pushEnvEvent) {
2540
- this.env.pushEnvEvent({
2541
- type,
2542
- metadata: {
2543
- trigger_session_id: triggerSessionId,
2544
- source: "task.delegate"
2545
- },
2546
- payload
2547
- });
2548
- logger2.info(`[BackgroundTaskManager] Event published: ${type}`, { payload });
2549
- }
2550
- }
2551
- stopTask(taskId) {
2552
- const task = this.tasks.get(taskId);
2553
- if (!task) {
2554
- return { success: false, message: "Task not found" };
2555
- }
2556
- if (task.status === "completed" || task.status === "failed" || task.status === "stopped" || task.status === "timeout") {
2557
- return {
2558
- success: false,
2559
- task,
2560
- message: `Cannot stop task with status: ${task.status}`
2561
- };
2562
- }
2563
- task.status = "stopped";
2564
- task.abortController?.abort();
2565
- task.completedAt = Date.now();
2566
- this.publishEvent(TaskEventTypes.TASK_STOPPED, createTaskCompletedPayload(task, task.parentSessionId, task.completedAt - task.startedAt), task.parentSessionId);
2567
- return { success: true, task, message: "Task has been stopped" };
2568
- }
2569
- getTask(taskId) {
2570
- return this.tasks.get(taskId);
2571
- }
2572
- listTasks() {
2573
- return Array.from(this.tasks.values());
2574
- }
2575
- dispose() {
2576
- for (const [taskId, timer] of this.progressTimers) {
2577
- clearInterval(timer);
2578
- logger2.debug(`[BackgroundTaskManager] Cleared progress timer for task: ${taskId}`);
2579
- }
2580
- this.progressTimers.clear();
2581
- for (const [taskId, controller] of this.abortControllers) {
2582
- controller.abort();
2583
- logger2.debug(`[BackgroundTaskManager] Aborted task: ${taskId}`);
2584
- }
2585
- this.abortControllers.clear();
2586
- this.tasks.clear();
2587
- logger2.info(`[BackgroundTaskManager] Disposed`);
2588
- }
2589
- }
2590
- function createDelegateTool(taskComponent) {
2591
- const env = taskComponent.env;
2592
- const backgroundTaskManager = new BackgroundTaskManager(env);
2593
- const tool = {
2594
- name: "delegate_task",
2595
- description: `Launch a new sub-agent to handle complex, multistep tasks autonomously.
2596
-
2597
- Available agent types:
2598
- ${getSubAgentToolDescription()}
2599
-
2600
- When using the delegate_task tool, you must specify a subagent_type parameter to select which agent type to use.
2601
-
2602
- ## When to use delegate_task:
2603
- - When you need to perform complex, multi-step tasks that require independent execution
2604
- - When you need to explore a codebase thoroughly (use "explore" subagent)
2605
- - When you need to run long-running tasks without blocking the main agent (use background=true)
2606
-
2607
- ## Parameters:
2608
- - **description**: A short (3-5 words) description of the task
2609
- - **prompt**: The task for the agent to perform
2610
- - **subagent_type**: The type of specialized agent to use (e.g., "general", "explore")
2611
- - **background**: Whether to run in background (default: false)
2612
- - **timeout**: Task timeout in milliseconds (optional)
2613
- - **task_id**: Optional task ID to associate with this delegate task
2614
-
2615
- ## Synchronous vs Background mode:
2616
- **Synchronous mode (default)**: Waits for subagent to complete and returns result directly
2617
- **Background mode (background=true)**: Returns immediately with "accepted" status, runs independently`,
2618
- parameters: DelegateToolParameters,
2619
- execute: async (args, ctx) => {
2620
- const startTime = Date.now();
2621
- const params = DelegateToolParameters.parse(args);
2622
- const { description, prompt, subagent_type = "general", background = false, timeout, cleanup, task_id, reason } = params;
2623
- const parentSessionId = ctx.session_id || "default";
2624
- logger2.info(`[delegate_task] Called: description=${description}, subagent_type=${subagent_type}, background=${background}, task_id=${task_id}`);
2625
- const subAgent = getSubAgentSpec(subagent_type);
2626
- if (!subAgent) {
2627
- return {
2628
- success: false,
2629
- output: "",
2630
- error: `Unknown subagent type: ${subagent_type}`,
2631
- metadata: { execution_time_ms: Date.now() - startTime }
2632
- };
2633
- }
2634
- const tagService = taskComponent.getTagService();
2635
- let promptWithTaskInfo = prompt;
2636
- const delegateCtx = {
2637
- taskId: task_id,
2638
- prompt: promptWithTaskInfo,
2639
- subagentType: subagent_type,
2640
- background,
2641
- timeout,
2642
- cleanup,
2643
- reason,
2644
- tagService
2645
- };
2646
- const hookCtx = {
2647
- component: { name: "task", version: "1.0.0" },
2648
- data: delegateCtx,
2649
- metadata: { sessionId: parentSessionId },
2650
- phase: "before",
2651
- hookPoint: TaskHookPoints.DELEGATE_BEFORE
2652
- };
2653
- await globalHookManager.execute(TaskHookPoints.DELEGATE_BEFORE, hookCtx, { sessionId: parentSessionId });
2654
- promptWithTaskInfo = delegateCtx.prompt;
2655
- if (background) {
2656
- return await handleBackgroundTask(taskComponent, backgroundTaskManager, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout, delegateCtx.cleanup, delegateCtx.taskId);
2657
- } else {
2658
- return await handleSyncTask(taskComponent, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout, delegateCtx.taskId);
2659
- }
2660
- }
2661
- };
2662
- return tool;
2663
- }
2664
- async function handleSyncTask(taskComponent, parentSessionId, description, prompt, subagentType, timeout, taskId) {
2665
- const startTime = Date.now();
2666
- try {
2667
- const sessionComponent = taskComponent.env?.getComponent?.("session");
2668
- if (!sessionComponent) {
2669
- return {
2670
- success: false,
2671
- output: "",
2672
- error: "SessionComponent not found",
2673
- metadata: { execution_time_ms: Date.now() - startTime }
2674
- };
2675
- }
2676
- const parentSession = await sessionComponent.get(parentSessionId);
2677
- if (!parentSession) {
2678
- return {
2679
- success: false,
2680
- output: "",
2681
- error: `Parent session not found: ${parentSessionId}`,
2682
- metadata: { execution_time_ms: Date.now() - startTime }
2683
- };
2684
- }
2685
- const metadata = {
2686
- subagent_type: subagentType,
2687
- created_by: "subagent",
2688
- task_description: description
2689
- };
2690
- if (taskId) {
2691
- metadata.task_id = taskId;
2692
- }
2693
- const subSession = await sessionComponent.create({
2694
- parentID: parentSessionId,
2695
- title: `${description} (@${subagentType} subagent)`,
2696
- metadata
2697
- });
2698
- if (!subSession) {
2699
- return {
2700
- success: false,
2701
- output: "",
2702
- error: "Failed to create sub-session",
2703
- metadata: { execution_time_ms: Date.now() - startTime }
2704
- };
2705
- }
2706
- const subAgent = getSubAgentSpec(subagentType);
2707
- let basePrompt = subAgent?.promptOverride || `You are a subagent. Complete this task: {task_description}`;
2708
- const deniedTools = subAgent?.deniedTools || [];
2709
- let fullPrompt = basePrompt.replace(/{task_description}/g, description || "N/A");
2710
- fullPrompt += `
2711
-
2712
- ---
2713
-
2714
- # Session Info
2715
- - task_id: ${taskId || "N/A"}
2716
- - session_id: ${subSession.id}
2717
-
2718
- ---
2719
-
2720
- ## \u7528\u6237\u6307\u4EE4
2721
- ${prompt}
2722
-
2723
- ---
2724
-
2725
- ## \u6267\u884C\u89C4\u8303
2726
- - \u4F7F\u7528\u53EF\u7528\u5DE5\u5177\u5B8C\u6210\u4EFB\u52A1
2727
- - \u8FD4\u56DE\u6E05\u6670\u7684\u4EFB\u52A1\u6267\u884C\u7ED3\u679C\u6458\u8981
2728
- - \u9002\u65F6\u8C03\u7528 task_operation_create \u8BB0\u5F55\u8FDB\u5C55`;
2729
- const agentComponent = taskComponent.env?.getComponent?.("agent");
2730
- if (!agentComponent) {
2731
- return {
2732
- success: false,
2733
- output: "",
2734
- error: "AgentComponent not found",
2735
- metadata: { execution_time_ms: Date.now() - startTime }
2736
- };
2737
- }
2738
- ensureSubAgentRegistered(agentComponent, subagentType, basePrompt, subAgent, deniedTools);
2739
- const timeoutMs = timeout || DEFAULT_TIMEOUT;
2740
- let result;
2741
- try {
2742
- result = await Promise.race([
2743
- taskComponent.env?.handle_query?.(fullPrompt, {
2744
- sessionId: subSession.id,
2745
- deniedTools: deniedTools.length > 0 ? deniedTools : undefined,
2746
- agentType: subagentType
2747
- }),
2748
- new Promise((_, reject) => setTimeout(() => reject(new Error(`Task execution timeout after ${timeoutMs}ms`)), timeoutMs))
2749
- ]);
2750
- } catch (error) {
2751
- result = error instanceof Error ? error.message : String(error);
2752
- }
2753
- await sessionComponent.addMessage(subSession.id, {
2754
- role: "assistant",
2755
- content: result
2756
- });
2757
- return {
2758
- success: true,
2759
- output: result + `
2760
-
2761
- ` + [
2762
- "<task_metadata>",
2763
- `session_id: ${subSession.id}`,
2764
- `subagent_type: ${subagentType}`,
2765
- "</task_metadata>"
2766
- ].join(`
2767
- `),
2768
- metadata: {
2769
- execution_time_ms: Date.now() - startTime,
2770
- sessionId: subSession.id
2771
- }
2772
- };
2773
- } catch (error) {
2774
- return {
2775
- success: false,
2776
- output: "",
2777
- error: error instanceof Error ? error.message : String(error),
2778
- metadata: { execution_time_ms: Date.now() - startTime }
2779
- };
2780
- }
2781
- }
2782
- async function handleBackgroundTask(taskComponent, backgroundTaskManager, parentSessionId, description, prompt, subagentType, timeout, cleanup, taskId) {
2783
- const startTime = Date.now();
2784
- try {
2785
- let associatedTaskId = taskId;
2786
- if (!associatedTaskId) {
2787
- const newTask = await taskComponent.createTask({
2788
- title: description,
2789
- description: `Background task delegated to ${subagentType} subagent`,
2790
- priority: "medium",
2791
- goals_and_expected_deliverables: prompt,
2792
- sessionId: parentSessionId
2793
- });
2794
- associatedTaskId = newTask.id;
2795
- await taskComponent.createOperation({
2796
- taskId: associatedTaskId,
2797
- sessionId: parentSessionId,
2798
- actionType: "create",
2799
- actionTitle: `Delegated to ${subagentType} subagent`,
2800
- actionDescription: `Background task started: ${description}`
2801
- });
2802
- } else {
2803
- await taskComponent.updateTask(associatedTaskId, {
2804
- status: "active",
2805
- current_status: `Running ${subagentType} subagent`
2806
- });
2807
- await taskComponent.createOperation({
2808
- taskId: associatedTaskId,
2809
- sessionId: parentSessionId,
2810
- actionType: "progress",
2811
- actionTitle: `Started ${subagentType} subagent`,
2812
- actionDescription: `Background task: ${description}`
2813
- });
2814
- }
2815
- const { taskId: bgTaskId, subSessionId } = await backgroundTaskManager.createTask({
2816
- parentSessionId,
2817
- description,
2818
- prompt,
2819
- subagentType,
2820
- timeout,
2821
- cleanup,
2822
- taskId: associatedTaskId
2823
- });
2824
- const output = [
2825
- `\u2705 Background task accepted`,
2826
- "",
2827
- `\uD83D\uDCCB Task ID: ${bgTaskId}`,
2828
- `\uD83D\uDCDD Description: ${description}`,
2829
- `\uD83E\uDD16 Sub-agent: ${subagentType}`,
2830
- associatedTaskId ? `\uD83D\uDCCC Associated Task: #${associatedTaskId}` : "",
2831
- `\u23F1\uFE0F Timeout: ${(timeout || DEFAULT_TIMEOUT) / 1000}s`,
2832
- "",
2833
- `Use stop_task with task_id="${bgTaskId}" to cancel this task.`
2834
- ].filter(Boolean).join(`
2835
- `);
2836
- return {
2837
- success: true,
2838
- output,
2839
- metadata: {
2840
- execution_time_ms: Date.now() - startTime,
2841
- sessionId: subSessionId,
2842
- background: true,
2843
- status: "accepted",
2844
- task_id: associatedTaskId,
2845
- bgTaskId
2846
- }
2847
- };
2848
- } catch (error) {
2849
- return {
2850
- success: false,
2851
- output: "",
2852
- error: error instanceof Error ? error.message : String(error),
2853
- metadata: { execution_time_ms: Date.now() - startTime }
2854
- };
2855
- }
2856
- }
2857
- // packages/core/src/env/task/delegate/stop-tool.ts
2858
- import { z as z4 } from "zod";
2859
- var StopTaskToolParameters = z4.object({
2860
- task_id: z4.string().describe("The ID of the background task to stop")
2861
- });
2862
- var STOP_TASK_DESCRIPTION = `Stop a running background task.
2863
-
2864
- Use this tool to stop a background task that is currently running. This is useful when:
2865
- - The user wants to cancel a long-running task
2866
- - The task is taking too long and needs to be stopped
2867
- - The user wants to change direction and doesn't need the task result anymore
2868
-
2869
- When stopped, the task will be terminated immediately and you will receive a confirmation.
2870
-
2871
- Parameters:
2872
- - task_id: The ID of the background task to stop (obtained from the delegate_task response)`;
2873
- function formatDuration(ms) {
2874
- const seconds = Math.floor(ms / 1000);
2875
- const minutes = Math.floor(seconds / 60);
2876
- const hours = Math.floor(minutes / 60);
2877
- if (hours > 0) {
2878
- return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
2879
- } else if (minutes > 0) {
2880
- return `${minutes}m ${seconds % 60}s`;
2881
- } else {
2882
- return `${seconds}s`;
2883
- }
2884
- }
2885
- function createStopTool(taskManager) {
2886
- return {
2887
- name: "stop_task",
2888
- description: STOP_TASK_DESCRIPTION,
2889
- parameters: StopTaskToolParameters,
2890
- execute: async (args, ctx) => {
2891
- const startTime = Date.now();
2892
- const params = StopTaskToolParameters.parse(args);
2893
- const { task_id } = params;
2894
- const result = taskManager.stopTask(task_id);
2895
- if (result.success) {
2896
- const task = result.task;
2897
- const elapsedMs = task.startedAt ? Date.now() - task.startedAt : Date.now() - task.createdAt;
2898
- const output = [
2899
- `\u2705 Task stopped successfully`,
2900
- "",
2901
- `\uD83D\uDCCB Task ID: ${task_id}`,
2902
- `\uD83D\uDCDD Description: ${task.description}`,
2903
- `\uD83D\uDD04 Status: ${task.status} \u2192 stopped`,
2904
- `\u23F1\uFE0F Elapsed Time: ${formatDuration(elapsedMs)}`,
2905
- "",
2906
- result.message
2907
- ].join(`
2908
- `);
2909
- return {
2910
- success: true,
2911
- output,
2912
- metadata: {
2913
- execution_time_ms: Date.now() - startTime,
2914
- task_id,
2915
- previous_status: task.status
2916
- }
2917
- };
2918
- } else {
2919
- const task = result.task;
2920
- let output;
2921
- if (task) {
2922
- output = [
2923
- `\u26A0\uFE0F Cannot stop task`,
2924
- "",
2925
- `\uD83D\uDCCB Task ID: ${task_id}`,
2926
- `\uD83D\uDCDD Description: ${task.description}`,
2927
- `\uD83D\uDD04 Current Status: ${task.status}`,
2928
- "",
2929
- result.message
2930
- ].join(`
2931
- `);
2932
- } else {
2933
- output = [
2934
- `\u274C Task not found`,
2935
- "",
2936
- `\uD83D\uDCCB Task ID: ${task_id}`,
2937
- "",
2938
- result.message
2939
- ].join(`
2940
- `);
2941
- }
2942
- return {
2943
- success: false,
2944
- output,
2945
- error: result.message,
2946
- metadata: {
2947
- execution_time_ms: Date.now() - startTime,
2948
- task_id
2949
- }
2950
- };
2951
- }
2952
- }
2953
- };
2954
- }
2955
- // packages/core/src/env/component.ts
2956
- class BaseComponent {
2957
- _status = "created";
2958
- _enabled = true;
2959
- env;
2960
- hookManager;
2961
- constructor() {
2962
- this.hookManager = new HookManager;
2963
- }
2964
- getStatus() {
2965
- return this._status;
2966
- }
2967
- getConfig() {
2968
- return {
2969
- name: this.name,
2970
- version: this.version,
2971
- enabled: this._enabled,
2972
- env: this.env
2973
- };
2974
- }
2975
- isEnvInitialized() {
2976
- return this._status !== "created";
2977
- }
2978
- setStatus(status) {
2979
- this._status = status;
2980
- }
2981
- getEnv() {
2982
- return this.env;
2983
- }
2984
- async init(config) {
2985
- if (config?.env) {
2986
- this.env = config.env;
2987
- }
2988
- this.setStatus("initializing");
2989
- try {
2990
- if (config?.name)
2991
- Object.defineProperty(this, "name", { value: config.name, writable: false });
2992
- if (config?.version)
2993
- Object.defineProperty(this, "version", { value: config.version, writable: false });
2994
- } catch {}
2995
- if (config?.enabled !== undefined)
2996
- this._enabled = config.enabled;
2997
- this.hookManager.setComponentInfo(this.name, this.version);
2998
- await this.onInit();
2999
- this.setStatus("running");
3000
- }
3001
- async start() {
3002
- if (this._started)
3003
- return;
3004
- this._started = true;
3005
- await this.onStart();
3006
- this.setStatus("running");
3007
- }
3008
- async stop() {
3009
- this.setStatus("stopping");
3010
- this.hookManager.clear();
3011
- await this.onStop();
3012
- this.setStatus("stopped");
3013
- }
3014
- async onInit() {}
3015
- async onStart() {}
3016
- async onStop() {}
3017
- registerHook(hookPoint, hook) {
3018
- this.hookManager.register(hookPoint, hook);
3019
- }
3020
- addHook(hookPoint, name, fn, priority) {
3021
- this.hookManager.register(hookPoint, createHook({ name, priority }, fn));
3022
- }
3023
- removeHook(hookPoint, name) {
3024
- return this.hookManager.unregister(hookPoint, name);
3025
- }
3026
- async executeHooks(hookPoint, data, metadata) {
3027
- await this.hookManager.execute(hookPoint, data, metadata);
3028
- }
3029
- getConfigComponent() {
3030
- return this.env?.getComponent("config");
3031
- }
3032
- getRuntimeConfig(key, defaultValue) {
3033
- const configComponent = this.getConfigComponent();
3034
- if (configComponent) {
3035
- const value = configComponent.get(key);
3036
- if (value !== undefined) {
3037
- return value;
3038
- }
3039
- }
3040
- return defaultValue;
3041
- }
3042
- }
3043
-
3044
- // packages/core/src/env/task/task-component.ts
3045
- init_logger();
3046
-
3047
- // packages/core/src/env/task/task-config-registration.ts
3048
- var TASK_DEFAULTS = {
3049
- "task.storage.type": "sqlite",
3050
- "task.storage.dbPath": undefined
3051
- };
3052
- var TASK_CONFIG_REGISTRATION = {
3053
- name: "task",
3054
- sources: [
3055
- { type: "env", envPrefix: "TASK", priority: 20, watch: false }
3056
- ],
3057
- keys: [
3058
- { key: "task.storage.type", sources: ["env", "file"] },
3059
- { key: "task.storage.dbPath", sources: ["env", "file"] }
3060
- ]
3061
- };
3062
-
3063
- // packages/core/src/config/env-key.ts
3064
- function toEnvKey(key, prefix) {
3065
- let keyNormalized = key.replace(/[.-]/g, "_");
3066
- keyNormalized = keyNormalized.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/_+/g, "_").toUpperCase();
3067
- if (prefix) {
3068
- const separator = prefix.endsWith("_") ? "" : "_";
3069
- return `${prefix}${separator}${keyNormalized}`;
3070
- }
3071
- return keyNormalized;
3072
- }
3073
- function fromEnvKey(envKey, prefix) {
3074
- if (!prefix) {
3075
- return envKey;
3076
- }
3077
- if (envKey.startsWith(prefix)) {
3078
- const afterPrefix = envKey.slice(prefix.length);
3079
- if (afterPrefix.startsWith("_")) {
3080
- return afterPrefix.slice(1);
3081
- }
3082
- return afterPrefix;
3083
- }
3084
- return envKey;
3085
- }
3086
- function envKeyToConfigKey(envKey, prefix, componentName) {
3087
- const prefixUpper = prefix.toUpperCase();
3088
- if (!envKey.startsWith(prefixUpper)) {
3089
- return;
3090
- }
3091
- const componentUpperNormalized = componentName.replace(/-/g, "_").toUpperCase();
3092
- let keyPart = envKey.slice(prefixUpper.length);
3093
- if (keyPart.startsWith("_")) {
3094
- keyPart = keyPart.slice(1);
3095
- }
3096
- if (!keyPart) {
3097
- return;
3098
- }
3099
- const firstUnderscore = keyPart.indexOf("_");
3100
- let restPart;
3101
- if (firstUnderscore === -1) {
3102
- restPart = keyPart;
3103
- } else {
3104
- const firstPart = keyPart.slice(0, firstUnderscore);
3105
- const remaining = keyPart.slice(firstUnderscore + 1);
3106
- if (firstPart === componentUpperNormalized) {
3107
- restPart = remaining;
3108
- } else {
3109
- restPart = keyPart;
3110
- }
3111
- }
3112
- if (!restPart) {
3113
- return;
3114
- }
3115
- const restPartConverted = restPart.replace(/_/g, ".");
3116
- return `${componentName}.${restPartConverted.toLowerCase()}`;
3117
- }
3118
-
3119
- // packages/core/src/env/task/tag-service.ts
3120
- init_logger();
3121
- var logger3 = createLogger("task:tag");
3122
-
3123
- class DefaultTagService {
3124
- store;
3125
- constructor(store) {
3126
- this.store = store;
3127
- }
3128
- async createTag(name) {
3129
- const tag = await this.store.createTag(name);
3130
- logger3.debug(`[TagService] Created tag: ${tag.name} (id=${tag.id})`);
3131
- return tag;
3132
- }
3133
- async getTag(id) {
3134
- return this.store.getTag(id);
3135
- }
3136
- async getTagByName(name) {
3137
- return this.store.getTagByName(name);
3138
- }
3139
- async listTags(options) {
3140
- return this.store.listTags(options);
3141
- }
3142
- async searchTags(options) {
3143
- return this.store.searchTags(options);
3144
- }
3145
- async deleteTag(id) {
3146
- const result = await this.store.deleteTag(id);
3147
- if (result) {
3148
- logger3.debug(`[TagService] Deleted tag id=${id}`);
3149
- }
3150
- return result;
3151
- }
3152
- async addTagsToTask(taskId, tagIds) {
3153
- await this.store.addTagsToTask(taskId, tagIds);
3154
- logger3.debug(`[TagService] Added ${tagIds.length} tags to task ${taskId}`);
3155
- }
3156
- async removeTagsFromTask(taskId, tagIds) {
3157
- await this.store.removeTagsFromTask(taskId, tagIds);
3158
- logger3.debug(`[TagService] Removed ${tagIds.length} tags from task ${taskId}`);
3159
- }
3160
- async getTagsForTask(taskId) {
3161
- return this.store.getTagsForTask(taskId);
3162
- }
3163
- async getTaskIdsByTags(tagNames) {
3164
- return this.store.getTaskIdsByTags(tagNames);
3165
- }
3166
- async findSimilarTasks(taskId, limit = 5) {
3167
- return this.store.findSimilarTasks(taskId, limit);
3168
- }
3169
- async searchTasks(query, limit = 20) {
3170
- return this.store.searchTasks(query, limit);
3171
- }
3172
- async searchTasksByKeywords(keywords, options) {
3173
- return this.store.searchTasksByKeywords(keywords, options);
3174
- }
3175
- async findSimilarTasksByKeywords(keywords, options) {
3176
- return this.store.findSimilarTasksByKeywords(keywords, options);
3177
- }
3178
- async syncTagsToTask(taskId, tagNames) {
3179
- const tagIds = [];
3180
- for (const name of tagNames) {
3181
- let tag = await this.store.getTagByName(name);
3182
- if (!tag) {
3183
- tag = await this.store.createTag(name);
3184
- }
3185
- tagIds.push(tag.id);
3186
- }
3187
- const currentTags = await this.store.getTagsForTask(taskId);
3188
- const currentTagIds = new Set(currentTags.map((t) => t.id));
3189
- const newTagIds = new Set(tagIds);
3190
- const toAdd = tagIds.filter((id) => !currentTagIds.has(id));
3191
- const toRemove = currentTags.filter((t) => !newTagIds.has(t.id)).map((t) => t.id);
3192
- if (toRemove.length > 0) {
3193
- await this.store.removeTagsFromTask(taskId, toRemove);
3194
- }
3195
- if (toAdd.length > 0) {
3196
- await this.store.addTagsToTask(taskId, toAdd);
3197
- }
3198
- await this.store.updateTaskTags(taskId, tagNames);
3199
- logger3.info(`[TagService] Synced tags for task ${taskId}: ${tagNames.join(", ")}`);
3200
- }
3201
- }
3202
-
3203
- // packages/core/src/env/task/task-component.ts
3204
- var logger4 = createLogger("task");
3205
-
3206
- class TaskComponent extends BaseComponent {
3207
- name = "task";
3208
- version = "1.0.0";
3209
- store;
3210
- config;
3211
- toolComponent;
3212
- backgroundTaskManager;
3213
- configComponent;
3214
- tagService;
3215
- plugins = new Map;
3216
- constructor() {
3217
- super();
3218
- }
3219
- async init(config) {
3220
- await super.init(config);
3221
- const options = config?.options;
3222
- if (!options?.configComponent) {
3223
- throw new Error("ConfigComponent is required for TaskComponent initialization");
3224
- }
3225
- this.configComponent = options.configComponent;
3226
- await this.registerConfig(options);
3227
- this.setStatus("running");
3228
- logger4.info("[TaskComponent] Initialized");
3229
- }
3230
- async registerConfig(options) {
3231
- const configComponent = this.configComponent;
3232
- if (!configComponent)
3233
- return;
3234
- const { configPath, envPrefix, config } = options;
3235
- const prefix = envPrefix ?? "TASK";
3236
- configComponent.registerComponent(TASK_CONFIG_REGISTRATION);
3237
- if (configPath) {
3238
- configComponent.registerSource({
3239
- type: "file",
3240
- relativePath: configPath,
3241
- optional: true,
3242
- watch: false
3243
- });
3244
- }
3245
- configComponent.registerSource({
3246
- type: "env",
3247
- envPrefix: prefix,
3248
- priority: 20,
3249
- watch: false
3250
- });
3251
- await configComponent.load("task");
3252
- for (const envKey of Object.keys(process.env)) {
3253
- const configKey = envKeyToConfigKey(envKey, prefix, "task");
3254
- if (!configKey)
3255
- continue;
3256
- const value = process.env[envKey];
3257
- if (value !== undefined) {
3258
- await configComponent.set(configKey, value);
3259
- }
3260
- }
3261
- for (const [key, value] of Object.entries(TASK_DEFAULTS)) {
3262
- if (configComponent.get(key) === undefined) {
3263
- await configComponent.set(key, value);
3264
- }
3265
- }
3266
- if (configComponent.get("task.storage.dbPath") === undefined) {
3267
- await configComponent.set("task.storage.dbPath", getDefaultTaskDbPath());
3268
- }
3269
- if (config) {
3270
- const flatConfig = this.flattenConfig(config);
3271
- for (const [key, value] of Object.entries(flatConfig)) {
3272
- await configComponent.set(key, value);
3273
- }
3274
- }
3275
- this.registerConfigWatcher(configComponent);
3276
- await this.initStore();
3277
- this.tagService = new DefaultTagService(this.store);
3278
- }
3279
- async initStore() {
3280
- const configComponent = this.configComponent;
3281
- if (!configComponent)
3282
- return;
3283
- const storageType = configComponent.get("task.storage.type") ?? "sqlite";
3284
- const dbPath = configComponent.get("task.storage.dbPath");
3285
- if (storageType === "sqlite") {
3286
- this.store = new SQLiteTaskStore(dbPath);
3287
- logger4.info(`[TaskComponent] Using SQLite storage: ${dbPath || "default path"}`);
3288
- } else {
3289
- this.store = new SQLiteTaskStore;
3290
- logger4.info("[TaskComponent] Using SQLite storage (default)");
3291
- }
3292
- }
3293
- flattenConfig(obj, prefix = "task") {
3294
- const result = {};
3295
- for (const [key, value] of Object.entries(obj)) {
3296
- const fullKey = `${prefix}.${key}`;
3297
- if (value && typeof value === "object" && !Array.isArray(value)) {
3298
- Object.assign(result, this.flattenConfig(value, fullKey));
3299
- } else {
3300
- result[fullKey] = value;
3301
- }
3302
- }
3303
- return result;
3304
- }
3305
- registerConfigWatcher(configComponent) {
3306
- if (typeof configComponent.watch !== "function") {
3307
- return;
3308
- }
3309
- this.configWatcher = configComponent.watch("task.*", (event) => {
3310
- this.onConfigChange(event);
3311
- });
3312
- }
3313
- onConfigChange(event) {
3314
- logger4.info(`[TaskComponent] Config changed: ${event.key}`, {
3315
- oldValue: event.oldValue,
3316
- newValue: event.newValue
3317
- });
3318
- if (event.key === "task.storage.type" || event.key === "task.storage.dbPath") {
3319
- this.initStore();
3320
- }
3321
- }
3322
- configWatcher;
3323
- async start() {
3324
- await super.start();
3325
- this.backgroundTaskManager = new BackgroundTaskManager(this.env);
3326
- this.toolComponent = this.env?.getComponent("tool");
3327
- if (this.toolComponent) {
3328
- await this.registerTools();
3329
- } else {
3330
- logger4.warn("[TaskComponent] ToolComponent not found, skipping tool registration");
3331
- }
3332
- }
3333
- async stop() {
3334
- if (this.configWatcher) {
3335
- this.configWatcher();
3336
- this.configWatcher = undefined;
3337
- }
3338
- if (this.backgroundTaskManager) {
3339
- this.backgroundTaskManager.dispose();
3340
- }
3341
- if (this.store) {
3342
- await this.store.close();
3343
- }
3344
- await super.stop();
3345
- }
3346
- async registerTools() {
3347
- if (!this.toolComponent)
3348
- return;
3349
- const taskToolsList = [
3350
- createTaskTool(this),
3351
- getTaskTool(this),
3352
- listTasksTool(this),
3353
- updateTaskTool(this),
3354
- deleteTaskTool(this),
3355
- completeTaskTool(this)
3356
- ];
3357
- const operationToolsList = [
3358
- createOperationTool(this),
3359
- getOperationTool(this),
3360
- listOperationsTool(this),
3361
- updateOperationTool(this),
3362
- deleteOperationTool(this)
3363
- ];
3364
- const delegateTools = [
3365
- createDelegateTool(this),
3366
- createStopTool(this.backgroundTaskManager)
3367
- ];
3368
- for (const tool of [...taskToolsList, ...operationToolsList, ...delegateTools]) {
3369
- this.toolComponent.register(tool);
3370
- logger4.info(`[TaskComponent] Registered tool: ${tool.name}`);
3371
- }
3372
- }
3373
- async executeHook(hookPoint, data, metadata = {}) {
3374
- const ctx = {
3375
- component: { name: this.name, version: this.version },
3376
- data,
3377
- metadata,
3378
- phase: hookPoint.includes("before") ? "before" : "after",
3379
- hookPoint
3380
- };
3381
- await globalHookManager.execute(hookPoint, ctx, metadata);
3382
- }
3383
- async createTask(options) {
3384
- const sessionId = options.sessionId;
3385
- const createCtx = {
3386
- options: { ...options },
3387
- sessionId,
3388
- tagService: this.tagService
3389
- };
3390
- await this.executeHook(TaskHookPoints.BEFORE_CREATE, createCtx);
3391
- const task = await this.store.createTask(createCtx.options);
3392
- await this.store.createOperation({
3393
- taskId: task.id,
3394
- sessionId,
3395
- actionType: "create",
3396
- actionTitle: `Task created: ${task.title}`,
3397
- actionDescription: task.description || ""
3398
- });
3399
- const resultCtx = {
3400
- task,
3401
- sessionId,
3402
- tagService: this.tagService
3403
- };
3404
- await this.executeHook(TaskHookPoints.AFTER_CREATE, resultCtx);
3405
- logger4.info(`[TaskComponent] Task created: ${task.id} - ${task.title}`);
3406
- return task;
3407
- }
3408
- async getTask(id) {
3409
- return this.store.getTask(id);
3410
- }
3411
- async getTaskWithOperations(id) {
3412
- const task = await this.store.getTask(id);
3413
- if (!task)
3414
- return;
3415
- const operations = await this.store.listOperations({ taskId: id });
3416
- return { task, operations };
3417
- }
3418
- async updateTask(id, options) {
3419
- const updateCtx = {
3420
- id,
3421
- options: { ...options },
3422
- tagService: this.tagService
3423
- };
3424
- await this.executeHook(TaskHookPoints.BEFORE_UPDATE, updateCtx);
3425
- const task = await this.store.updateTask(id, updateCtx.options);
3426
- if (task) {
3427
- const resultCtx = {
3428
- task,
3429
- changes: options,
3430
- tagService: this.tagService
3431
- };
3432
- await this.executeHook(TaskHookPoints.AFTER_UPDATE, resultCtx);
3433
- logger4.info(`[TaskComponent] Task updated: ${id}`);
3434
- }
3435
- return task;
3436
- }
3437
- async deleteTask(id) {
3438
- const deleteCtx = { id };
3439
- await this.executeHook(TaskHookPoints.BEFORE_DELETE, deleteCtx);
3440
- const result = await this.store.deleteTask(id);
3441
- const resultCtx = { id, deleted: result };
3442
- await this.executeHook(TaskHookPoints.AFTER_DELETE, resultCtx);
3443
- if (result) {
3444
- logger4.info(`[TaskComponent] Task deleted: ${id}`);
3445
- }
3446
- return result;
3447
- }
3448
- async listTasks(options) {
3449
- return this.store.listTasks(options);
3450
- }
3451
- async completeTask(id, sessionId) {
3452
- const task = await this.store.updateTask(id, {
3453
- status: "completed",
3454
- progress: 100
3455
- });
3456
- if (task) {
3457
- await this.createOperation({
3458
- taskId: id,
3459
- sessionId,
3460
- actionType: "completed",
3461
- actionTitle: "Task completed"
3462
- });
3463
- logger4.info(`[TaskComponent] Task completed: ${id}`);
3464
- }
3465
- return task;
3466
- }
3467
- async createOperation(options) {
3468
- const createCtx = {
3469
- options: { ...options }
3470
- };
3471
- await this.executeHook(TaskHookPoints.OPERATION_BEFORE_CREATE, createCtx);
3472
- const op = await this.store.createOperation(createCtx.options);
3473
- const resultCtx = { operation: op };
3474
- await this.executeHook(TaskHookPoints.OPERATION_AFTER_CREATE, resultCtx);
3475
- logger4.info(`[TaskComponent] Operation created: ${op.id} for task ${op.taskId}`);
3476
- return op;
3477
- }
3478
- async getOperation(id) {
3479
- return this.store.getOperation(id);
3480
- }
3481
- async updateOperation(id, updates) {
3482
- return this.store.updateOperation(id, updates);
3483
- }
3484
- async deleteOperation(id) {
3485
- return this.store.deleteOperation(id);
3486
- }
3487
- async listOperations(options) {
3488
- return this.store.listOperations(options);
3489
- }
3490
- getTagService() {
3491
- return this.tagService;
3492
- }
3493
- registerPlugin(plugin) {
3494
- this.plugins.set(plugin.name, plugin);
3495
- const llmComponent = this.env?.getComponent("llm");
3496
- plugin.setComponents?.(llmComponent, this);
3497
- const getRequiredAgents = plugin.constructor.getRequiredAgents;
3498
- if (typeof getRequiredAgents === "function") {
3499
- const agentComponent = this.env?.getComponent("agent");
3500
- if (agentComponent) {
3501
- try {
3502
- const agents = getRequiredAgents();
3503
- for (const agentConfig of agents) {
3504
- agentComponent.registerAgent(agentConfig.name, agentConfig);
3505
- }
3506
- } catch (err) {
3507
- logger4.warn(`Failed to auto-register agents for plugin ${plugin.name}: ${err}`);
3508
- }
3509
- }
3510
- }
3511
- for (const hook of plugin.hooks) {
3512
- const pluginConfig = plugin.config;
3513
- const priority = hook.priority ?? pluginConfig?.priority ?? 0;
3514
- const hookName = `${this.name}:${plugin.name}:${hook.point}`;
3515
- const pluginRef = plugin;
3516
- globalHookManager.register(hook.point, {
3517
- name: hookName,
3518
- priority,
3519
- execute: async (ctx) => {
3520
- const pluginCtx = {
3521
- component: ctx.component,
3522
- data: ctx.data,
3523
- metadata: ctx.metadata,
3524
- phase: ctx.phase,
3525
- hookPoint: hook.point
3526
- };
3527
- await pluginRef.execute(pluginCtx);
3528
- }
3529
- });
3530
- }
3531
- logger4.info(`[TaskComponent] Registered plugin: ${plugin.name}`, {
3532
- hooks: plugin.hooks.map((h) => h.point)
3533
- });
3534
- }
3535
- unregisterPlugin(name) {
3536
- const plugin = this.plugins.get(name);
3537
- if (!plugin)
3538
- return false;
3539
- for (const hook of plugin.hooks) {
3540
- globalHookManager.unregister(hook.point, `${this.name}:${name}`);
3541
- }
3542
- this.plugins.delete(name);
3543
- logger4.info(`[TaskComponent] Unregistered plugin: ${name}`);
3544
- return true;
3545
- }
3546
- listPlugins() {
3547
- return Array.from(this.plugins.values());
3548
- }
3549
- }
3550
- // packages/core/src/env/task/types.ts
3551
- import { z as z5 } from "zod";
3552
- var TaskStatusEnum = z5.enum(["todo", "active", "completed", "paused", "cancelled"]);
3553
- var TaskPriorityEnum = z5.enum(["low", "medium", "high"]);
3554
- var ActionTypeEnum2 = z5.enum([
3555
- "create",
3556
- "progress",
3557
- "milestone",
3558
- "problem",
3559
- "solution",
3560
- "decision",
3561
- "review",
3562
- "completed",
3563
- "workflow_extracted"
3564
- ]);
3565
- var TaskConfigSchema = z5.object({
3566
- storage: z5.object({
3567
- type: z5.enum(["memory", "sqlite"]).default("sqlite"),
3568
- dbPath: z5.string().optional()
3569
- }).default({})
3570
- }).default({});
3571
- export {
3572
- TaskStatusEnum,
3573
- TaskPriorityEnum,
3574
- TaskConfigSchema,
3575
- TaskComponent,
3576
- SQLiteTaskStore,
3577
- ActionTypeEnum2 as ActionTypeEnum
3578
- };