@ai-setting/roy-agent-core 1.5.58 → 1.5.60

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 (23) hide show
  1. package/dist/env/agent/index.js +2 -2
  2. package/dist/env/event-source/index.js +2 -2
  3. package/dist/env/index.js +9 -9
  4. package/dist/env/llm/index.js +2 -2
  5. package/dist/env/prompt/index.js +1 -1
  6. package/dist/env/task/delegate/index.js +1 -1
  7. package/dist/env/task/index.js +4 -4
  8. package/dist/env/task/plugins/index.js +1 -1
  9. package/dist/env/task/storage/index.js +1 -1
  10. package/dist/env/task/tools/index.js +8 -2
  11. package/dist/index.js +11 -11
  12. package/dist/shared/@ai-setting/{roy-agent-core-e1704378.js → roy-agent-core-3s9va046.js} +198 -8
  13. package/dist/shared/@ai-setting/{roy-agent-core-q16bh5e9.js → roy-agent-core-8am1xdvb.js} +21 -7
  14. package/dist/shared/@ai-setting/{roy-agent-core-w4f871e2.js → roy-agent-core-cgq7btak.js} +233 -34
  15. package/dist/shared/@ai-setting/{roy-agent-core-0hhxwz5f.js → roy-agent-core-dkevkmas.js} +1 -1
  16. package/dist/shared/@ai-setting/{roy-agent-core-6ph5va4n.js → roy-agent-core-hg3q4f82.js} +19 -9
  17. package/dist/shared/@ai-setting/{roy-agent-core-65yjzwv5.js → roy-agent-core-nd3amf4x.js} +5 -2
  18. package/dist/shared/@ai-setting/{roy-agent-core-6s3vec2y.js → roy-agent-core-qqhbxq56.js} +72 -5
  19. package/dist/shared/@ai-setting/{roy-agent-core-zkwe508t.js → roy-agent-core-s2zz85a9.js} +19 -2
  20. package/dist/shared/@ai-setting/{roy-agent-core-5c2mfq1q.js → roy-agent-core-t3367jkk.js} +2 -0
  21. package/dist/shared/@ai-setting/{roy-agent-core-skaha0yj.js → roy-agent-core-wqzkxab9.js} +32 -5
  22. package/dist/shared/@ai-setting/{roy-agent-core-sfqx98j6.js → roy-agent-core-xztzw1yb.js} +1 -1
  23. package/package.json +1 -1
@@ -184,6 +184,7 @@ class SQLiteTaskStore {
184
184
  )
185
185
  `);
186
186
  this.db.run("CREATE INDEX IF NOT EXISTS idx_task_tag_relation_tag_id ON task_tag_relation(tag_id)");
187
+ this.db.run("CREATE INDEX IF NOT EXISTS idx_task_parent_task_id ON task(parent_task_id)");
187
188
  if (this.dbPath !== ":memory:") {
188
189
  try {
189
190
  const { runMigration: runMigration001 } = (init_001_add_project_path_context(), __toCommonJS(exports_001_add_project_path_context));
@@ -308,24 +309,36 @@ class SQLiteTaskStore {
308
309
  }
309
310
  async listTasks(options) {
310
311
  await this.initialize();
311
- let sql = "SELECT * FROM task WHERE 1=1";
312
- const params = [];
312
+ if (options?.depth !== undefined && options.depth >= 0 && options.parent_task_id === undefined) {
313
+ return this.listTasksByDepth(options);
314
+ }
315
+ const whereClauses = ["1=1"];
316
+ const whereParams = [];
313
317
  if (options?.status) {
314
- sql += " AND status = ?";
315
- params.push(options.status);
318
+ whereClauses.push("status = ?");
319
+ whereParams.push(options.status);
316
320
  }
317
321
  if (options?.priority) {
318
- sql += " AND priority = ?";
319
- params.push(options.priority);
322
+ whereClauses.push("priority = ?");
323
+ whereParams.push(options.priority);
320
324
  }
321
325
  if (options?.type) {
322
- sql += " AND type = ?";
323
- params.push(options.type);
326
+ whereClauses.push("type = ?");
327
+ whereParams.push(options.type);
324
328
  }
325
329
  if (options?.parent_task_id !== undefined) {
326
- sql += " AND parent_task_id = ?";
327
- params.push(options.parent_task_id);
328
- }
330
+ whereClauses.push("parent_task_id = ?");
331
+ whereParams.push(options.parent_task_id);
332
+ }
333
+ if (!options?.include_archived && options?.status !== "archived") {
334
+ whereClauses.push("status != 'archived'");
335
+ }
336
+ const whereSql = whereClauses.join(" AND ");
337
+ const countSql = `SELECT COUNT(*) as total FROM task WHERE ${whereSql}`;
338
+ const countRow = this.db.prepare(countSql).get(...whereParams);
339
+ const total = countRow?.total ?? 0;
340
+ let sql = `SELECT * FROM task WHERE ${whereSql}`;
341
+ const params = [...whereParams];
329
342
  sql += " ORDER BY updated_at DESC";
330
343
  if (options?.limit) {
331
344
  sql += " LIMIT ?";
@@ -337,11 +350,96 @@ class SQLiteTaskStore {
337
350
  }
338
351
  const stmt = this.db.prepare(sql);
339
352
  const rows = stmt.all(...params);
340
- return rows.map((row) => {
353
+ const tasks = rows.map((row) => {
341
354
  const task = this.rowToTask(row);
342
355
  this.tasksCache.set(task.id, task);
343
356
  return task;
344
357
  });
358
+ return { tasks, total };
359
+ }
360
+ async listTasksByDepth(options) {
361
+ const depth = options.depth ?? 0;
362
+ const filterClauses = ["1=1"];
363
+ const filterParams = [];
364
+ if (options.status) {
365
+ filterClauses.push("status = ?");
366
+ filterParams.push(options.status);
367
+ }
368
+ if (options.priority) {
369
+ filterClauses.push("priority = ?");
370
+ filterParams.push(options.priority);
371
+ }
372
+ if (options.type) {
373
+ filterClauses.push("type = ?");
374
+ filterParams.push(options.type);
375
+ }
376
+ if (!options?.include_archived && options?.status !== "archived") {
377
+ filterClauses.push("status != 'archived'");
378
+ }
379
+ const filterSql = filterClauses.join(" AND ");
380
+ const collected = [];
381
+ if (depth === 0) {
382
+ const rootSql = `SELECT * FROM task WHERE parent_task_id IS NULL AND ${filterSql} ORDER BY updated_at DESC`;
383
+ const rows = this.db.prepare(rootSql).all(...filterParams);
384
+ for (const row of rows) {
385
+ const t = this.rowToTask(row);
386
+ this.tasksCache.set(t.id, t);
387
+ collected.push(t);
388
+ }
389
+ } else {
390
+ const rootRows = this.db.prepare(`SELECT * FROM task WHERE parent_task_id IS NULL AND ${filterSql} ORDER BY updated_at DESC`).all(...filterParams);
391
+ let currentLevel = rootRows.map((row) => {
392
+ const t = this.rowToTask(row);
393
+ this.tasksCache.set(t.id, t);
394
+ return t;
395
+ });
396
+ collected.push(...currentLevel);
397
+ for (let level = 1;level <= depth; level++) {
398
+ if (currentLevel.length === 0)
399
+ break;
400
+ const ids = currentLevel.map((t) => t.id);
401
+ const placeholders = ids.map(() => "?").join(",");
402
+ const childSql = `SELECT * FROM task WHERE parent_task_id IN (${placeholders}) AND ${filterSql} ORDER BY updated_at DESC`;
403
+ const childRows = this.db.prepare(childSql).all(...ids, ...filterParams);
404
+ const nextLevel = childRows.map((row) => {
405
+ const t = this.rowToTask(row);
406
+ this.tasksCache.set(t.id, t);
407
+ return t;
408
+ });
409
+ collected.push(...nextLevel);
410
+ currentLevel = nextLevel;
411
+ }
412
+ }
413
+ const total = collected.length;
414
+ const offset = options.offset ?? 0;
415
+ const limit = options.limit ?? total;
416
+ const sliced = collected.slice(offset, offset + limit);
417
+ return { tasks: sliced, total };
418
+ }
419
+ async getTaskTree(taskId, depth = -1) {
420
+ await this.initialize();
421
+ const result = [];
422
+ let currentLevel = [taskId];
423
+ let currentDepth = 0;
424
+ while (currentLevel.length > 0) {
425
+ if (depth !== -1 && currentDepth >= depth)
426
+ break;
427
+ const placeholders = currentLevel.map(() => "?").join(",");
428
+ const rows = this.db.prepare(`SELECT * FROM task WHERE parent_task_id IN (${placeholders}) ORDER BY updated_at DESC`).all(...currentLevel);
429
+ const nextLevel = [];
430
+ for (const row of rows) {
431
+ const t = this.rowToTask(row);
432
+ this.tasksCache.set(t.id, t);
433
+ result.push(t);
434
+ nextLevel.push(t.id);
435
+ }
436
+ currentLevel = nextLevel;
437
+ currentDepth++;
438
+ }
439
+ return result;
440
+ }
441
+ async getChildTasks(taskId, options = {}) {
442
+ return this.listTasks({ ...options, parent_task_id: taskId });
345
443
  }
346
444
  async createOperation(options) {
347
445
  await this.initialize();
@@ -599,9 +697,13 @@ class SQLiteTaskStore {
599
697
  async searchTasksByKeywords(keywords, options = {}) {
600
698
  await this.initialize();
601
699
  if (!keywords || keywords.length === 0) {
602
- return [];
700
+ return { tasks: [], total: 0 };
701
+ }
702
+ const { limit = 20, offset = 0, excludeTaskId, status, priority, type, depth } = options;
703
+ let allowedTaskIds = null;
704
+ if (depth !== undefined && depth >= 0) {
705
+ allowedTaskIds = await this.collectTaskIdsByDepth(depth);
603
706
  }
604
- const { limit = 20, excludeTaskId } = options;
605
707
  const tasks = new Map;
606
708
  let taskSql = "SELECT * FROM task WHERE 1=1";
607
709
  const taskParams = [];
@@ -609,17 +711,37 @@ class SQLiteTaskStore {
609
711
  taskSql += " AND id != ?";
610
712
  taskParams.push(excludeTaskId);
611
713
  }
714
+ if (status) {
715
+ taskSql += " AND status = ?";
716
+ taskParams.push(status);
717
+ }
718
+ if (priority) {
719
+ taskSql += " AND priority = ?";
720
+ taskParams.push(priority);
721
+ }
722
+ if (type) {
723
+ taskSql += " AND type = ?";
724
+ taskParams.push(type);
725
+ }
726
+ if (!options?.include_archived && options?.status !== "archived") {
727
+ taskSql += " AND status != 'archived'";
728
+ }
729
+ const scanLimit = Math.max(limit * 5, 200);
612
730
  taskSql += " ORDER BY updated_at DESC LIMIT ?";
613
- taskParams.push(limit * 2);
731
+ taskParams.push(scanLimit);
614
732
  const taskRows = this.db.prepare(taskSql).all(...taskParams);
615
733
  for (const row of taskRows) {
616
734
  const task = this.rowToTask(row);
735
+ const matchedKeywords = new Set;
617
736
  let matchCount = 0;
618
737
  if (task.title) {
619
738
  const lowerTitle = task.title.toLowerCase();
620
739
  for (const keyword of keywords) {
621
740
  if (lowerTitle.includes(keyword.toLowerCase())) {
622
- matchCount++;
741
+ {
742
+ matchCount++;
743
+ matchedKeywords.add(keyword);
744
+ }
623
745
  }
624
746
  }
625
747
  }
@@ -627,7 +749,10 @@ class SQLiteTaskStore {
627
749
  for (const keyword of keywords) {
628
750
  const lowerKeyword = keyword.toLowerCase();
629
751
  if (task.tags.some((tag) => tag.toLowerCase().includes(lowerKeyword))) {
630
- matchCount += 2;
752
+ {
753
+ matchCount += 2;
754
+ matchedKeywords.add(keyword);
755
+ }
631
756
  }
632
757
  }
633
758
  }
@@ -635,7 +760,10 @@ class SQLiteTaskStore {
635
760
  const lowerDesc = task.description.toLowerCase();
636
761
  for (const keyword of keywords) {
637
762
  if (lowerDesc.includes(keyword.toLowerCase())) {
638
- matchCount++;
763
+ {
764
+ matchCount++;
765
+ matchedKeywords.add(keyword);
766
+ }
639
767
  }
640
768
  }
641
769
  }
@@ -643,11 +771,14 @@ class SQLiteTaskStore {
643
771
  const lowerGoals = task.goals_and_expected_deliverables.toLowerCase();
644
772
  for (const keyword of keywords) {
645
773
  if (lowerGoals.includes(keyword.toLowerCase())) {
646
- matchCount++;
774
+ {
775
+ matchCount++;
776
+ matchedKeywords.add(keyword);
777
+ }
647
778
  }
648
779
  }
649
780
  }
650
- if (matchCount > 0) {
781
+ if (matchedKeywords.size === keywords.length) {
651
782
  tasks.set(task.id, { task, matchCount });
652
783
  }
653
784
  }
@@ -659,31 +790,99 @@ class SQLiteTaskStore {
659
790
  AND (action_title LIKE ? OR action_description LIKE ?)
660
791
  LIMIT 10
661
792
  `;
793
+ const opMatchedKeywords = new Set;
662
794
  for (const keyword of keywords) {
663
795
  const pattern = `%${keyword}%`;
664
796
  const ops = this.db.prepare(opSql).all(opRow.task_id, pattern, pattern);
665
797
  if (ops.length > 0) {
666
- const taskRow = this.db.prepare("SELECT * FROM task WHERE id = ?").get(opRow.task_id);
667
- if (taskRow) {
668
- const task = this.rowToTask(taskRow);
669
- if (excludeTaskId && task.id === excludeTaskId)
670
- continue;
671
- const existing = tasks.get(task.id);
672
- if (existing) {
673
- existing.matchCount += 2;
674
- } else {
675
- tasks.set(task.id, { task, matchCount: 2 });
676
- }
798
+ opMatchedKeywords.add(keyword);
799
+ }
800
+ }
801
+ if (opMatchedKeywords.size === 0)
802
+ continue;
803
+ const taskRow = this.db.prepare("SELECT * FROM task WHERE id = ?").get(opRow.task_id);
804
+ if (!taskRow)
805
+ continue;
806
+ const task = this.rowToTask(taskRow);
807
+ if (excludeTaskId && task.id === excludeTaskId)
808
+ continue;
809
+ if (status && task.status !== status)
810
+ continue;
811
+ if (priority && task.priority !== priority)
812
+ continue;
813
+ if (type && task.type !== type)
814
+ continue;
815
+ if (!options?.include_archived && task.status === "archived")
816
+ continue;
817
+ const existing = tasks.get(task.id);
818
+ if (existing) {
819
+ existing.matchCount += 2;
820
+ } else {
821
+ const combinedKeywords = new Set(opMatchedKeywords);
822
+ if (task.title) {
823
+ const lowerTitle = task.title.toLowerCase();
824
+ for (const kw of keywords) {
825
+ if (lowerTitle.includes(kw.toLowerCase()))
826
+ combinedKeywords.add(kw);
827
+ }
828
+ }
829
+ if (task.description) {
830
+ const lowerDesc = task.description.toLowerCase();
831
+ for (const kw of keywords) {
832
+ if (lowerDesc.includes(kw.toLowerCase()))
833
+ combinedKeywords.add(kw);
834
+ }
835
+ }
836
+ if (task.goals_and_expected_deliverables) {
837
+ const lowerGoals = task.goals_and_expected_deliverables.toLowerCase();
838
+ for (const kw of keywords) {
839
+ if (lowerGoals.includes(kw.toLowerCase()))
840
+ combinedKeywords.add(kw);
841
+ }
842
+ }
843
+ if (task.tags && Array.isArray(task.tags)) {
844
+ for (const kw of keywords) {
845
+ if (task.tags.some((tag) => tag.toLowerCase().includes(kw.toLowerCase())))
846
+ combinedKeywords.add(kw);
677
847
  }
678
848
  }
849
+ if (combinedKeywords.size === keywords.length) {
850
+ tasks.set(task.id, { task, matchCount: 2 });
851
+ }
679
852
  }
680
853
  }
681
- const results = Array.from(tasks.values()).sort((a, b) => b.matchCount - a.matchCount).slice(0, limit).map((item) => item.task);
682
- return results;
854
+ let sorted = Array.from(tasks.values()).sort((a, b) => b.matchCount - a.matchCount);
855
+ if (allowedTaskIds !== null) {
856
+ sorted = sorted.filter((item) => allowedTaskIds.has(item.task.id));
857
+ }
858
+ const total = sorted.length;
859
+ const sliced = sorted.slice(offset, offset + limit);
860
+ const resultTasks = sliced.map((item) => item.task);
861
+ return { tasks: resultTasks, total };
862
+ }
863
+ async collectTaskIdsByDepth(depth) {
864
+ const ids = new Set;
865
+ const rootRows = this.db.prepare("SELECT id FROM task WHERE parent_task_id IS NULL").all();
866
+ let currentLevel = rootRows.map((r) => r.id);
867
+ for (const id of currentLevel)
868
+ ids.add(id);
869
+ if (depth === 0)
870
+ return ids;
871
+ for (let level = 1;level <= depth; level++) {
872
+ if (currentLevel.length === 0)
873
+ break;
874
+ const placeholders = currentLevel.map(() => "?").join(",");
875
+ const rows = this.db.prepare(`SELECT id FROM task WHERE parent_task_id IN (${placeholders})`).all(...currentLevel);
876
+ currentLevel = rows.map((r) => r.id);
877
+ for (const id of currentLevel)
878
+ ids.add(id);
879
+ }
880
+ return ids;
683
881
  }
684
882
  async findSimilarTasksByKeywords(keywords, options = {}) {
685
883
  const mergedOptions = { ...options, limit: options.limit ?? 5 };
686
- return this.searchTasksByKeywords(keywords, mergedOptions);
884
+ const result = await this.searchTasksByKeywords(keywords, mergedOptions);
885
+ return result.tasks;
687
886
  }
688
887
  async findSimilarTasks(taskId, limit = 5) {
689
888
  await this.initialize();
@@ -642,7 +642,7 @@ No need to poll — just wait for the notification and use \`task_get\` with the
642
642
  phase: "before",
643
643
  hookPoint: TaskHookPoints.DELEGATE_BEFORE
644
644
  };
645
- await globalHookManager.execute(TaskHookPoints.DELEGATE_BEFORE, hookCtx, { sessionId: parentSessionId });
645
+ await globalHookManager.execute(TaskHookPoints.DELEGATE_BEFORE, delegateCtx, { sessionId: parentSessionId });
646
646
  promptWithTaskInfo = delegateCtx.prompt;
647
647
  return await handleBackgroundTask(backgroundTaskManager, parentSessionId, description, promptWithTaskInfo, delegateCtx.subagentType, delegateCtx.timeout);
648
648
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  withTimeout
3
- } from "./roy-agent-core-65yjzwv5.js";
3
+ } from "./roy-agent-core-nd3amf4x.js";
4
4
  import {
5
5
  AskUserError,
6
6
  init_workflow_hil
@@ -575,14 +575,14 @@ class AgentComponent extends BaseComponent {
575
575
  agentContext: parentEnvContext?.agentContext ?? {},
576
576
  traceId: effectiveContext.metadata?.traceId,
577
577
  sessionId: effectiveContext.sessionId,
578
- userId: effectiveContext.metadata?.userId ?? "",
578
+ userId: parentEnvContext?.userId ?? (effectiveContext.metadata?.userId ?? ""),
579
579
  messageId: effectiveContext.metadata?.messageId,
580
- pluginEnabled: effectiveContext.pluginEnabled,
580
+ pluginEnabled: { ...parentEnvContext?.pluginEnabled ?? {}, ...effectiveContext.pluginEnabled ?? {} },
581
581
  plugins: effectiveContext.plugins,
582
- envEvent: effectiveContext.envEvent,
583
- replyChannel: effectiveContext.envEvent?.metadata?.replyChannel,
584
- sourceId: effectiveContext.envEvent?.metadata?.sourceId,
585
- sourceType: effectiveContext.envEvent?.metadata?.sourceType,
582
+ envEvent: effectiveContext.envEvent ?? parentEnvContext?.envEvent,
583
+ replyChannel: parentEnvContext?.replyChannel ?? effectiveContext.envEvent?.metadata?.replyChannel,
584
+ sourceId: parentEnvContext?.sourceId ?? effectiveContext.envEvent?.metadata?.sourceId,
585
+ sourceType: parentEnvContext?.sourceType ?? effectiveContext.envEvent?.metadata?.sourceType,
586
586
  metadata: { ...effectiveContext.metadata }
587
587
  };
588
588
  return await runWithEnvContextAsync(envContext, async () => {
@@ -647,9 +647,19 @@ class AgentComponent extends BaseComponent {
647
647
  break;
648
648
  }
649
649
  finalText = llmOutput.content;
650
+ const assistantParts = [
651
+ { type: "text", text: llmOutput.content }
652
+ ];
653
+ if (llmOutput.reasoning) {
654
+ assistantParts.push({
655
+ type: "reasoning",
656
+ text: llmOutput.reasoning,
657
+ reasoningType: "core"
658
+ });
659
+ }
650
660
  this.pushMessage(hookCtx, {
651
661
  role: "assistant",
652
- content: llmOutput.content
662
+ content: assistantParts
653
663
  });
654
664
  break;
655
665
  }
@@ -1030,7 +1040,7 @@ ${additionInfo}`
1030
1040
  },
1031
1041
  abortSignal: ctx.context.abort
1032
1042
  });
1033
- const result = await withTimeout(llmPromise, 120000, "LLM invocation timeout after 120s");
1043
+ const result = await withTimeout(llmPromise, 300000, "LLM invocation timeout after 300s");
1034
1044
  logger.debug("[invokeLLM] LLMComponent.invoke returned successfully");
1035
1045
  return {
1036
1046
  content: result.output?.content || "",
@@ -384,6 +384,7 @@ async function invoke(config, options, ctx) {
384
384
  };
385
385
  const result = await streamText(streamTextOptions);
386
386
  let fullContent = "";
387
+ let rawFullContent = "";
387
388
  let reasoningContent = "";
388
389
  const toolCalls = [];
389
390
  let usageInfo;
@@ -405,6 +406,7 @@ async function invoke(config, options, ctx) {
405
406
  isThinkingTagOpen = thinkingResult.isThinkingTagOpen;
406
407
  currentThinkingContent = thinkingResult.currentThinkingContent;
407
408
  fullContent += thinkingResult.cleanedText;
409
+ rawFullContent += textDelta;
408
410
  for (const reasoningSnapshot of thinkingResult.reasoningEvents) {
409
411
  const delta = reasoningSnapshot.slice(reasoningContent.length);
410
412
  reasoningContent = reasoningSnapshot;
@@ -417,6 +419,7 @@ async function invoke(config, options, ctx) {
417
419
  }
418
420
  } else {
419
421
  fullContent += textDelta;
422
+ rawFullContent += textDelta;
420
423
  if (emitToEnv) {
421
424
  emitToEnv({ type: "text", content: fullContent, delta: textDelta });
422
425
  }
@@ -477,7 +480,7 @@ async function invoke(config, options, ctx) {
477
480
  return {
478
481
  toolCallId: firstToolCall.id,
479
482
  result: JSON.stringify({
480
- content: fullContent,
483
+ content: rawFullContent,
481
484
  reasoning: reasoningContent || undefined,
482
485
  tool_calls: toolCalls.map((tc) => ({
483
486
  id: tc.id,
@@ -492,7 +495,7 @@ async function invoke(config, options, ctx) {
492
495
  return {
493
496
  toolCallId: "invoke-" + Date.now(),
494
497
  result: JSON.stringify({
495
- content: fullContent,
498
+ content: rawFullContent,
496
499
  reasoning: reasoningContent || undefined,
497
500
  usage: usageInfo,
498
501
  model
@@ -402,6 +402,7 @@ var NotifyType;
402
402
  NotifyType2["TASK_COMPLETED"] = "task_completed";
403
403
  NotifyType2["TASK_UPDATED"] = "task_updated";
404
404
  NotifyType2["TASK_FAILED"] = "task_failed";
405
+ NotifyType2["OPERATION_CREATED"] = "operation_created";
405
406
  })(NotifyType ||= {});
406
407
 
407
408
  class LarkCliTaskNotifyHook {
@@ -411,6 +412,7 @@ class LarkCliTaskNotifyHook {
411
412
  pluginName;
412
413
  sourceId;
413
414
  config;
415
+ lastNotifyTimestamps = new Map;
414
416
  constructor(config = {}) {
415
417
  this.name = config.pluginName || "LarkCliTaskNotifyHook";
416
418
  this.priority = config.priority ?? 5;
@@ -420,7 +422,12 @@ class LarkCliTaskNotifyHook {
420
422
  this.config = {
421
423
  enabled: true,
422
424
  priority: 5,
423
- notifyTypes: ["task_completed" /* TASK_COMPLETED */],
425
+ notifyTypes: [
426
+ "task_created" /* TASK_CREATED */,
427
+ "task_updated" /* TASK_UPDATED */,
428
+ "task_completed" /* TASK_COMPLETED */,
429
+ "operation_created" /* OPERATION_CREATED */
430
+ ],
424
431
  ...config
425
432
  };
426
433
  }
@@ -443,6 +450,9 @@ class LarkCliTaskNotifyHook {
443
450
  case TaskHookPoints.AFTER_UPDATE:
444
451
  await this.onAfterUpdate(ctx);
445
452
  break;
453
+ case TaskHookPoints.OPERATION_AFTER_CREATE:
454
+ await this.onAfterOperationCreate(ctx);
455
+ break;
446
456
  }
447
457
  }
448
458
  async onAfterCreate(ctx) {
@@ -456,12 +466,11 @@ class LarkCliTaskNotifyHook {
456
466
  });
457
467
  }
458
468
  async onAfterUpdate(ctx) {
459
- const hookCtx = ctx.data;
460
- const innerData = hookCtx.data;
461
- if (!innerData) {
469
+ const data = ctx.data;
470
+ if (!data) {
462
471
  return;
463
472
  }
464
- const { task, changes } = innerData;
473
+ const { task, changes } = data;
465
474
  if (!task) {
466
475
  return;
467
476
  }
@@ -489,6 +498,25 @@ class LarkCliTaskNotifyHook {
489
498
  _hookContext: ctx
490
499
  });
491
500
  }
501
+ async onAfterOperationCreate(ctx) {
502
+ const { operation } = ctx.data;
503
+ if (!operation) {
504
+ logger2.debug("onAfterOperationCreate: operation is missing, skip");
505
+ return;
506
+ }
507
+ if (!this.shouldNotify("operation_created" /* OPERATION_CREATED */)) {
508
+ return;
509
+ }
510
+ if (this.shouldThrottleOperation(operation)) {
511
+ return;
512
+ }
513
+ await this.sendNotify({
514
+ type: "operation_created" /* OPERATION_CREATED */,
515
+ title: this.getNotifyTitle("operation_created" /* OPERATION_CREATED */),
516
+ content: this.formatOperationCreated(operation),
517
+ _hookContext: ctx
518
+ });
519
+ }
492
520
  async sendNotify(options) {
493
521
  const { type, title, content, _hookContext } = options;
494
522
  const env = getEnvContextOrEmpty();
@@ -594,6 +622,8 @@ ${content}`;
594
622
  return "\uD83D\uDCCB 任务已更新";
595
623
  case "task_failed" /* TASK_FAILED */:
596
624
  return "❌ 任务执行失败";
625
+ case "operation_created" /* OPERATION_CREATED */:
626
+ return "\uD83D\uDCCC 操作记录";
597
627
  default:
598
628
  return "\uD83D\uDCEC 任务通知";
599
629
  }
@@ -633,6 +663,43 @@ ${content}`;
633
663
  lines.push(`- **变更**: ${changeKeys.join(", ")}`);
634
664
  }
635
665
  return lines.join(`
666
+ `);
667
+ }
668
+ shouldThrottleOperation(operation) {
669
+ const throttleMs = this.config.operationThrottleMs ?? 5000;
670
+ if (throttleMs <= 0) {
671
+ return false;
672
+ }
673
+ const key = `op:${operation.taskId}`;
674
+ const now = Date.now();
675
+ const lastTime = this.lastNotifyTimestamps.get(key);
676
+ if (lastTime && now - lastTime < throttleMs) {
677
+ logger2.debug(`[throttle] Skipping OPERATION_CREATED notify for task #${operation.taskId}, last notified ${now - lastTime}ms ago`);
678
+ return true;
679
+ }
680
+ this.lastNotifyTimestamps.set(key, now);
681
+ return false;
682
+ }
683
+ formatOperationCreated(operation) {
684
+ const lines = [];
685
+ if (operation.taskId !== undefined && operation.taskId !== null) {
686
+ lines.push(`- **任务 ID**: #${operation.taskId}`);
687
+ }
688
+ if (operation.actionType) {
689
+ lines.push(`- **操作类型**: ${operation.actionType}`);
690
+ }
691
+ if (operation.actionTitle) {
692
+ lines.push(`- **标题**: ${operation.actionTitle}`);
693
+ }
694
+ if (operation.actionDescription) {
695
+ const desc = String(operation.actionDescription);
696
+ const truncated = desc.substring(0, 200) + (desc.length > 200 ? "..." : "");
697
+ lines.push(`- **描述**: ${truncated}`);
698
+ }
699
+ if (operation.sessionId) {
700
+ lines.push(`- **Session**: \`${operation.sessionId}\``);
701
+ }
702
+ return lines.join(`
636
703
  `);
637
704
  }
638
705
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TaskTagPlugin,
3
3
  createLarkCliTaskNotifyHook
4
- } from "./roy-agent-core-6s3vec2y.js";
4
+ } from "./roy-agent-core-qqhbxq56.js";
5
5
  import {
6
6
  envKeyToConfigKey
7
7
  } from "./roy-agent-core-qxhq8ven.js";
@@ -19,6 +19,9 @@ import {
19
19
  createEnvContext,
20
20
  runWithEnvContext
21
21
  } from "./roy-agent-core-y5d04fm3.js";
22
+ import {
23
+ TracedAs
24
+ } from "./roy-agent-core-k05v31rc.js";
22
25
  import {
23
26
  createLogger,
24
27
  init_logger
@@ -27,6 +30,7 @@ import {
27
30
  getTracerProvider
28
31
  } from "./roy-agent-core-7z9b1fm8.js";
29
32
  import {
33
+ __legacyDecorateClassTS,
30
34
  __require
31
35
  } from "./roy-agent-core-fs0mn2jk.js";
32
36
 
@@ -223,7 +227,11 @@ class LarkCliInstance {
223
227
  return [plugin.hookPoint];
224
228
  }
225
229
  if (plugin.name && typeof plugin.execute === "function") {
226
- return ["task:after.create", "task:after.update"];
230
+ return [
231
+ "task:after.create",
232
+ "task:after.update",
233
+ "task:operation:after.create"
234
+ ];
227
235
  }
228
236
  return [];
229
237
  }
@@ -510,6 +518,15 @@ class LarkCliInstance {
510
518
  });
511
519
  }
512
520
  }
521
+ __legacyDecorateClassTS([
522
+ TracedAs("lark-cli.loadPlugins", { recordParams: true, log: true })
523
+ ], LarkCliInstance.prototype, "loadPlugins", null);
524
+ __legacyDecorateClassTS([
525
+ TracedAs("lark-cli.registerPluginHooks", { recordParams: true, log: true })
526
+ ], LarkCliInstance.prototype, "registerPluginHooks", null);
527
+ __legacyDecorateClassTS([
528
+ TracedAs("lark-cli.handleEvent", { recordParams: true, log: true })
529
+ ], LarkCliInstance.prototype, "handleEvent", null);
513
530
  var larkCliHandler = {
514
531
  type: "lark-cli",
515
532
  validateConfig(config) {
@@ -98,6 +98,8 @@ class BaseEnvironment extends BaseComponent {
98
98
  envEvent: context || { type: "workflow" },
99
99
  sourceId: "workflow",
100
100
  userId: context?.metadata?.userId || "",
101
+ replyChannel: existingCtx?.replyChannel,
102
+ pluginEnabled: existingCtx?.pluginEnabled,
101
103
  agentContext: existingCtx?.agentContext ?? {}
102
104
  };
103
105
  return await runWithEnvContextAsync(workflowEnvContext, async () => {