@ai-setting/roy-agent-core 1.7.66 → 1.7.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/env/agent/agent-component.d.ts +29 -0
- package/dist/env/agent/agent-component.js +1 -1
- package/dist/env/agent/index.js +1 -1
- package/dist/env/agent/types.d.ts +16 -0
- package/dist/env/environment.d.ts +13 -0
- package/dist/env/event-source/event-source-handlers.js +6 -5
- package/dist/env/event-source/index.js +7 -6
- package/dist/env/event-source/timer-handler.d.ts +93 -1
- package/dist/env/index.js +12 -11
- package/dist/env/prompt/index.js +3 -2
- package/dist/env/prompt/prompts-index.d.ts +2 -7
- package/dist/env/task/delegate/delegate-tool.d.ts +21 -1
- package/dist/env/task/delegate/delegate-tool.js +3 -2
- package/dist/env/task/delegate/index.js +3 -2
- package/dist/env/task/index.js +5 -4
- package/dist/env/task/mcp/index.js +2 -1
- package/dist/env/task/plugins/__e2e__/laya-completion-e2e.d.ts +16 -0
- package/dist/env/task/plugins/index.js +4 -3
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +77 -0
- package/dist/env/task/plugins/lark-card-patch-notifier.js +7 -1
- package/dist/env/task/plugins/laya-completion-plugin.d.ts +133 -0
- package/dist/env/task/plugins/laya-port.d.ts +23 -0
- package/dist/env/task/task-component.d.ts +43 -0
- package/dist/env/task/tools/completion-copy.d.ts +27 -0
- package/dist/env/task/tools/index.js +2 -1
- package/dist/env/workflow/plugins/index.js +2 -2
- package/dist/index.js +13 -12
- package/dist/shared/@ai-setting/{roy-agent-core-8nksrtnf.js → roy-agent-core-19na22cc.js} +203 -18
- package/dist/shared/@ai-setting/{roy-agent-core-nr2m4xw1.js → roy-agent-core-1k83dq3a.js} +13 -3
- package/dist/shared/@ai-setting/roy-agent-core-43r4bxey.js +1083 -0
- package/dist/shared/@ai-setting/roy-agent-core-6m4bw8jy.js +6 -0
- package/dist/shared/@ai-setting/{roy-agent-core-0ys85x46.js → roy-agent-core-8bjj3d1b.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-2wxbx36p.js → roy-agent-core-dnjm17sa.js} +21 -2
- package/dist/shared/@ai-setting/{roy-agent-core-t0ktaevq.js → roy-agent-core-h5vmff8w.js} +60 -4
- package/dist/shared/@ai-setting/{roy-agent-core-j1kksatb.js → roy-agent-core-hfr6bzts.js} +67 -10
- package/dist/shared/@ai-setting/{roy-agent-core-v8bz7d8x.js → roy-agent-core-keyb45z3.js} +26 -11
- package/dist/shared/@ai-setting/{roy-agent-core-vs5gxgwh.js → roy-agent-core-ma35jyd9.js} +14 -3
- package/dist/shared/@ai-setting/{roy-agent-core-zk2jg0v7.js → roy-agent-core-tadj19vp.js} +106 -22
- package/dist/shared/@ai-setting/{roy-agent-core-cvm1xgmg.js → roy-agent-core-wksgtqf9.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-4882qsjx.js → roy-agent-core-x0ddc2cr.js} +1 -1
- package/package.json +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-8mjnb7xc.js +0 -654
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4760 — task completion hook 的 Laya decision 判定
|
|
3
|
+
*
|
|
4
|
+
* 与 create 侧(`laya-decision-plugin.ts`,#4620)的关系:
|
|
5
|
+
* - create 侧挂在 `task:before.create`,判「新建 vs 复用」
|
|
6
|
+
* - 本插件挂在 `task:after.complete`(AFTER_COMPLETE),判
|
|
7
|
+
* 「目标 vs 交付物 match / 目标是否达成 / 交付物是否产出」
|
|
8
|
+
*
|
|
9
|
+
* 形态:**只提示,不拦截**(与 create 侧契约一致)。
|
|
10
|
+
* AFTER_COMPLETE 触发时任务**已经**是 completed —— hint 只能
|
|
11
|
+
* ① 追加写进 `task.context.completion_hint`(走 updateTask)
|
|
12
|
+
* ② 落一条 operation 记录
|
|
13
|
+
* 绝不能阻断已完成状态、绝不能抛错。
|
|
14
|
+
*
|
|
15
|
+
* ── fail-open 六场景(对齐 create 侧 #4620) ─────────────────────
|
|
16
|
+
* 1. 未配置 provider(auth.json 缺失 / 无 laya-goal-decision)→ 不调模型
|
|
17
|
+
* 2. auth 损坏 / port 抛错(网络、超时)→ 静默
|
|
18
|
+
* 3. 响应畸形(无 answers / 无 answer)→ 静默
|
|
19
|
+
* 4. 置信度 < 0.92 → 不写 hint
|
|
20
|
+
* 5. operation chain 空 → 不调模型
|
|
21
|
+
* 6. choice 无法识别 → 静默
|
|
22
|
+
*
|
|
23
|
+
* ── provider 分离(Task #4804) ────────────────────────────────
|
|
24
|
+
* completion hook 读 `providers["laya-goal-decision"]`
|
|
25
|
+
* (model=task-completion / v13e ckpt,判「目标 vs 交付物」);
|
|
26
|
+
* create hook 继续读 `providers["laya-decision"]`
|
|
27
|
+
* (model=task-decision / v3-tags,判「新建 vs 复用」)。
|
|
28
|
+
* goal 专用 provider 缺失时保守回退 laya-decision(fail-open 不变)。
|
|
29
|
+
*
|
|
30
|
+
* ── 泄漏断言 ─────────────────────────────────────────────────────
|
|
31
|
+
* deny-list 含 decision/hint/target/answer 等键名 →
|
|
32
|
+
* question key 必须命名 `completion_check`、criteria 用
|
|
33
|
+
* `PASS_COMPLETED/FAIL_INCOMPLETE`(已验证不命中);
|
|
34
|
+
* state 用中文文本形态(【】段)则天然无对象键。
|
|
35
|
+
*
|
|
36
|
+
* ── 时序关键(勘查结论) ─────────────────────────────────────────
|
|
37
|
+
* AFTER_COMPLETE 触发时 `completed` operation 尚未写入
|
|
38
|
+
* (completeTask 在 hook 之后才 createOperation)。
|
|
39
|
+
* 因此 operation chain 里看到的是「完成前的历史记录」——
|
|
40
|
+
* 这正是判定所需的证据链,无需等 completed 记录。
|
|
41
|
+
*/
|
|
42
|
+
import type { DecisionPort } from "./decision-port";
|
|
43
|
+
import type { TaskCompleteResultContext } from "../hooks/contexts";
|
|
44
|
+
import type { Task, TaskOperation } from "../types";
|
|
45
|
+
/** 完成判定的置信度门禁(对齐 create 侧 LAYA_REUSE_THRESHOLD = 0.92) */
|
|
46
|
+
export declare const LAYA_COMPLETION_THRESHOLD = 0.92;
|
|
47
|
+
/**
|
|
48
|
+
* 构造完成核验 hint。
|
|
49
|
+
*
|
|
50
|
+
* 核实义务 + 二选一:(a) 确认未完成 → 重开继续推进;
|
|
51
|
+
* (b) 确认已完成 → 落 operation 说明理由。不允许无视。
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildCompletionHint(task: Task, confidence: number): string;
|
|
54
|
+
/**
|
|
55
|
+
* 渲染 laya 训练格式的中文文本 state。
|
|
56
|
+
*
|
|
57
|
+
* ⚠️ 用【】段而非 JSON 对象 —— laya 模型在中文文本形态上训练;
|
|
58
|
+
* 且文本形态天然没有对象键,不会命中泄漏断言的 deny-list。
|
|
59
|
+
*
|
|
60
|
+
* Task #4804 — goals 为编号子项且交付物声明可比对时,插入
|
|
61
|
+
* 【逐条对照】段(见 renderCriteriaChecklist 注释)。
|
|
62
|
+
*/
|
|
63
|
+
export declare function renderCompletionState(task: Task, ops: TaskOperation[]): string;
|
|
64
|
+
/** 渲染 completion_check 二选一 question(key 不命中泄漏 deny-list) */
|
|
65
|
+
export declare function buildCompletionQuestion(): Record<string, unknown>;
|
|
66
|
+
export interface LayaCompletionPluginOptions {
|
|
67
|
+
/** auth.json 路径(默认 ~/.roy-agent/auth.json) */
|
|
68
|
+
authPath?: string;
|
|
69
|
+
/** 硬超时(默认 2000ms) */
|
|
70
|
+
timeoutMs?: number;
|
|
71
|
+
/** 连续超时多少次后自我禁用(默认 3) */
|
|
72
|
+
maxStrikes?: number;
|
|
73
|
+
/** 注入 port(测试用;给了就不读 auth.json) */
|
|
74
|
+
decisionPort?: DecisionPort;
|
|
75
|
+
/** 完成判定的置信度门禁(默认 0.92) */
|
|
76
|
+
completionThreshold?: number;
|
|
77
|
+
}
|
|
78
|
+
export declare class LayaCompletionPlugin {
|
|
79
|
+
readonly name = "laya-completion";
|
|
80
|
+
readonly version = "1.0.0";
|
|
81
|
+
readonly description = "Task #4760 \u2014 task:after.complete \u5B8C\u6210\u5224\u5B9A\uFF08\u76EE\u6807/\u4EA4\u4ED8\u7269 match\uFF0C\u53EA\u63D0\u793A\u4E0D\u62E6\u622A\uFF09";
|
|
82
|
+
private readonly options;
|
|
83
|
+
private port;
|
|
84
|
+
private portResolved;
|
|
85
|
+
constructor(options?: LayaCompletionPluginOptions);
|
|
86
|
+
/** 当前是否已自我禁用(熔断)—— 供观测 */
|
|
87
|
+
isDisabled(): boolean;
|
|
88
|
+
/** 懒加载 + 缓存 port(读 auth.json 只做一次) */
|
|
89
|
+
private resolvePort;
|
|
90
|
+
/**
|
|
91
|
+
* hook 入口 —— **永不抛**。
|
|
92
|
+
*
|
|
93
|
+
* @param ctx TaskCompleteResultContext(或框架 HookContext,载荷在 .data)
|
|
94
|
+
* @param taskComponent TaskComponent(只读用:listOperations / getTask;
|
|
95
|
+
* 写 hint 用 updateTask + createOperation)
|
|
96
|
+
*/
|
|
97
|
+
execute(ctx: TaskCompleteResultContext | {
|
|
98
|
+
data: TaskCompleteResultContext;
|
|
99
|
+
}, taskComponent: any): Promise<void>;
|
|
100
|
+
private run;
|
|
101
|
+
/** hint 回写:追加 context.completion_hint + 落 operation 记录(都不阻断) */
|
|
102
|
+
private writeHint;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Task #4760 — 把 LayaCompletionPlugin 包成可注册到 task hook 的形态。
|
|
106
|
+
*
|
|
107
|
+
* 注册方式仿 `registerLayaDecisionTaskHook`(environment.ts:87):
|
|
108
|
+
* - unregister + register 幂等(globalHookManager.register 是 push)
|
|
109
|
+
* - fail-open:注册失败绝不影响 agent 启动
|
|
110
|
+
* - hook-manager `safeExecute` 自带异常隔离(hook 抛错只记日志)
|
|
111
|
+
*/
|
|
112
|
+
export declare function createLayaCompletionPlugin(options?: LayaCompletionPluginOptions): {
|
|
113
|
+
/** Hook 唯一名称(用于幂等去重 / unregister) */
|
|
114
|
+
name: string;
|
|
115
|
+
/** 执行优先级 */
|
|
116
|
+
priority: number;
|
|
117
|
+
/** hook 执行体 —— 永不抛 */
|
|
118
|
+
execute: (ctx: unknown) => Promise<void>;
|
|
119
|
+
/** 内层插件实例(供观测 / 测试) */
|
|
120
|
+
plugin: LayaCompletionPlugin;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* 把 LayaCompletionPlugin 注册到 `task:after.complete`(AFTER_COMPLETE)。
|
|
124
|
+
*
|
|
125
|
+
* ⚠️ 幂等:先 unregister 再 register,保证全局恰好 1 份。
|
|
126
|
+
* ⚠️ fail-open:注册失败返回 false,不影响调用方。
|
|
127
|
+
*
|
|
128
|
+
* @param taskComponent TaskComponent(由 this.getComponent("task") 取得)
|
|
129
|
+
* @param options LayaCompletionPluginOptions(生产不传 → 读 auth.json;
|
|
130
|
+
* 测试可注入 decisionPort)
|
|
131
|
+
* @returns 是否成功注册
|
|
132
|
+
*/
|
|
133
|
+
export declare function registerLayaCompletionTaskHook(taskComponent: any | undefined | null, options?: LayaCompletionPluginOptions): boolean;
|
|
@@ -131,6 +131,17 @@ export interface LayaAuthConfig {
|
|
|
131
131
|
apiKey: string;
|
|
132
132
|
model: string;
|
|
133
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Task #4804 — provider 名常量(provider 分离):
|
|
136
|
+
* - create hook(task:before.create,判新建 vs 复用)→ laya-decision
|
|
137
|
+
* - completion hook(task:after.complete,判目标 vs 交付物)→ laya-goal-decision
|
|
138
|
+
* (缺失时保守回退 laya-decision —— fail-open 语义不变)
|
|
139
|
+
*/
|
|
140
|
+
export declare const LAYA_DECISION_PROVIDER = "laya-decision";
|
|
141
|
+
export declare const LAYA_GOAL_DECISION_PROVIDER = "laya-goal-decision";
|
|
142
|
+
/** hook 用途 → provider 名(Task #4804 provider 分离的唯一映射点) */
|
|
143
|
+
export type LayaHookPurpose = "create" | "goal";
|
|
144
|
+
export declare function providerNameForPurpose(purpose: LayaHookPurpose): string;
|
|
134
145
|
/**
|
|
135
146
|
* 从 `~/.roy-agent/auth.json` 的 `providers["laya-decision"]` 读取端点配置。
|
|
136
147
|
*
|
|
@@ -139,5 +150,17 @@ export interface LayaAuthConfig {
|
|
|
139
150
|
* → providers["laya-decision"].model(可选)
|
|
140
151
|
*
|
|
141
152
|
* ⚠️ 读不到就返回 null —— 调用方必须 fail-open(不提示、不报错)。
|
|
153
|
+
*
|
|
154
|
+
* Task #4804 — 向后兼容:默认仍读 laya-decision(create hook 语义)。
|
|
155
|
+
* completion hook 侧请用 `loadLayaAuthForPurpose(path, "goal")`。
|
|
142
156
|
*/
|
|
143
157
|
export declare function loadLayaAuth(authPath?: string): Promise<LayaAuthConfig | null>;
|
|
158
|
+
/**
|
|
159
|
+
* Task #4804 — 按用途读 provider:
|
|
160
|
+
* - "create" → providers["laya-decision"]
|
|
161
|
+
* - "goal" → providers["laya-goal-decision"],缺失时保守回退
|
|
162
|
+
* providers["laya-decision"](共享共享配置,fail-open 不变)
|
|
163
|
+
*
|
|
164
|
+
* ⚠️ 读不到就返回 null —— 调用方必须 fail-open(不提示、不报错)。
|
|
165
|
+
*/
|
|
166
|
+
export declare function loadLayaAuthForPurpose(authPath?: string, purpose?: LayaHookPurpose): Promise<LayaAuthConfig | null>;
|
|
@@ -41,6 +41,21 @@ export interface TaskComponentOptions {
|
|
|
41
41
|
envPrefix?: string;
|
|
42
42
|
/** 直接传入的配置对象(可选,优先级最高) */
|
|
43
43
|
config?: Partial<TaskConfig>;
|
|
44
|
+
/**
|
|
45
|
+
* Task #4794 — 组件 stop() 时 BackgroundTaskManager.dispose() 的收尾行为。
|
|
46
|
+
*
|
|
47
|
+
* CLI `act` 一次性命令收尾时传 true(主 run 已结束,后台子 agent
|
|
48
|
+
* 是有意留下继续跑的);REPL / ESC cascade 等用户主动退出场景
|
|
49
|
+
* 保持默认 false(abort 全部,语义不变)。
|
|
50
|
+
*/
|
|
51
|
+
skipAbortRunningTasksOnDispose?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Task #4794 — 与 skipAbortRunningTasksOnDispose 配套:
|
|
54
|
+
* stop() 时等待运行中的后台任务完成后再返回。
|
|
55
|
+
* 子 agent 是同进程异步 run,进程 exit 会直接杀死它们,
|
|
56
|
+
* 所以 act 收尾必须等待。默认 false。
|
|
57
|
+
*/
|
|
58
|
+
waitForRunningTasksOnDispose?: boolean;
|
|
44
59
|
}
|
|
45
60
|
export declare class TaskComponent extends BaseComponent {
|
|
46
61
|
name: string;
|
|
@@ -49,6 +64,17 @@ export declare class TaskComponent extends BaseComponent {
|
|
|
49
64
|
private config?;
|
|
50
65
|
private toolComponent?;
|
|
51
66
|
private backgroundTaskManager?;
|
|
67
|
+
/**
|
|
68
|
+
* Task #4794 — stop() 时是否跳过 abort 仍在运行的后台任务
|
|
69
|
+
* (act 一次性命令收尾 = true;用户主动退出 = false 默认)。
|
|
70
|
+
*/
|
|
71
|
+
private skipAbortRunningTasksOnDispose;
|
|
72
|
+
/**
|
|
73
|
+
* Task #4794 — stop() 时是否等待运行中任务完成
|
|
74
|
+
* (act 收尾配套:跳过 abort 后必须等子 agent 跑完,
|
|
75
|
+
* 否则 process.exit 仍会杀死同进程子 agent)。
|
|
76
|
+
*/
|
|
77
|
+
private waitForRunningTasksOnDispose;
|
|
52
78
|
private configComponent?;
|
|
53
79
|
private tagService;
|
|
54
80
|
private plugins;
|
|
@@ -235,6 +261,23 @@ export declare class TaskComponent extends BaseComponent {
|
|
|
235
261
|
* @returns 更新后的 Task 或 undefined
|
|
236
262
|
*/
|
|
237
263
|
completeTask(id: number, sessionId: string, deliverableStoragePath?: string): Promise<Task | undefined>;
|
|
264
|
+
/**
|
|
265
|
+
* 直接更新任务 context(不触发 BEFORE/AFTER_UPDATE hook、不发事件)
|
|
266
|
+
*
|
|
267
|
+
* ★ Task #4776 review MINOR-1:AFTER_COMPLETE hook 内的嵌套
|
|
268
|
+
* updateTask({context}) 会二次 fire AFTER_UPDATE,把订阅者
|
|
269
|
+
* (LarkCliTaskNotifyHook 等)无谓拉起 —— 终态任务被再次走
|
|
270
|
+
* cardStatusOf 终态路径。hint 回写这类「内部簿记」不应有通知副作用,
|
|
271
|
+
* 因此提供本方法绕过 hook 链,直接走 store 层。
|
|
272
|
+
*
|
|
273
|
+
* 语义与 updateTask({context}) 完全一致:整份覆盖 context 字段。
|
|
274
|
+
* 调用方负责自己 merge 既有字段(不要拿快照整份覆盖别人写的内容)。
|
|
275
|
+
*
|
|
276
|
+
* @param id 任务 ID
|
|
277
|
+
* @param context 新的 context JSON 字符串(整份覆盖)
|
|
278
|
+
* @returns 更新后的 Task,任务不存在时返回 undefined
|
|
279
|
+
*/
|
|
280
|
+
updateTaskContext(id: number, context: string): Promise<Task | undefined>;
|
|
238
281
|
/**
|
|
239
282
|
* Create operation record
|
|
240
283
|
*/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4834 — F3: task_complete 验收文案同源锚点
|
|
3
|
+
*
|
|
4
|
+
* 背景(reports/goals-criteria-rules-e2e-rebase.md §遗留 F3):
|
|
5
|
+
* prompts-index.ts 的 COMPLETE 生命周期步骤与工具描述
|
|
6
|
+
* (TASK_COMPLETE_DESCRIPTION)**不同源** —— 文案漂移会
|
|
7
|
+
* 稀释工具描述的遵循度。
|
|
8
|
+
*
|
|
9
|
+
* 方案:三个关键短语定义于此,complete-tool 与
|
|
10
|
+
* prompts-index(default prompt)都引用同一常量,
|
|
11
|
+
* 文案一致性由 completion-copy-consistency.test.ts 守住。
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ 本模块必须保持**零依赖**(不 import 任何其他模块),
|
|
14
|
+
* 以便 prompts-index(超大模板串)与 tools 层都能安全引用。
|
|
15
|
+
*/
|
|
16
|
+
/** 逐条验收短语(工具描述 / default prompt 共用) */
|
|
17
|
+
export declare const TASK_COMPLETE_ITEM_BY_ITEM = "\u6309\u5B50\u9879\u9010\u6761\u9A8C\u6536";
|
|
18
|
+
/** hint 锚点 token(completion hook 写入 task context 的标记) */
|
|
19
|
+
export declare const TASK_COMPLETION_HINT_ANCHOR = "TASK_COMPLETION_HINT";
|
|
20
|
+
/** 核实义务短语(收到 hint 后必须核实,二选一) */
|
|
21
|
+
export declare const TASK_COMPLETE_VERIFY_DUTY = "\u6838\u5B9E\u4E49\u52A1";
|
|
22
|
+
/** F3 同源文案集合(聚合导出,便于测试解构) */
|
|
23
|
+
export declare const TASK_COMPLETE_ACCEPTANCE: {
|
|
24
|
+
readonly itemByItem: "按子项逐条验收";
|
|
25
|
+
readonly hintAnchor: "TASK_COMPLETION_HINT";
|
|
26
|
+
readonly verifyDuty: "核实义务";
|
|
27
|
+
};
|
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
searchTasksTool,
|
|
10
10
|
treeTasksTool,
|
|
11
11
|
updateTaskTool
|
|
12
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
12
|
+
} from "../../../shared/@ai-setting/roy-agent-core-h5vmff8w.js";
|
|
13
13
|
import"../../../shared/@ai-setting/roy-agent-core-tr3ep81v.js";
|
|
14
|
+
import"../../../shared/@ai-setting/roy-agent-core-6m4bw8jy.js";
|
|
14
15
|
import"../../../shared/@ai-setting/roy-agent-core-7cbpmk4q.js";
|
|
15
16
|
import"../../../shared/@ai-setting/roy-agent-core-qq96p0tj.js";
|
|
16
17
|
import"../../../shared/@ai-setting/roy-agent-core-7f7t9wwp.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LarkCliWorkflowNotifyHook,
|
|
3
3
|
createLarkCliWorkflowNotifyHook
|
|
4
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
5
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
4
|
+
} from "../../../shared/@ai-setting/roy-agent-core-8bjj3d1b.js";
|
|
5
|
+
import"../../../shared/@ai-setting/roy-agent-core-tadj19vp.js";
|
|
6
6
|
import"../../../shared/@ai-setting/roy-agent-core-c2gbt68e.js";
|
|
7
7
|
import"../../../shared/@ai-setting/roy-agent-core-ax9e9szb.js";
|
|
8
8
|
import"../../../shared/@ai-setting/roy-agent-core-cpcd24n2.js";
|
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import"./shared/@ai-setting/roy-agent-core-adg9ghbt.js";
|
|
|
31
31
|
import {
|
|
32
32
|
PromptComponent,
|
|
33
33
|
PromptStore
|
|
34
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
34
|
+
} from "./shared/@ai-setting/roy-agent-core-wksgtqf9.js";
|
|
35
35
|
import {
|
|
36
36
|
MemoryComponent
|
|
37
37
|
} from "./shared/@ai-setting/roy-agent-core-nwbfepba.js";
|
|
@@ -61,21 +61,21 @@ import {
|
|
|
61
61
|
BaseEnvironment,
|
|
62
62
|
generateDescendingId,
|
|
63
63
|
generateId
|
|
64
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
64
|
+
} from "./shared/@ai-setting/roy-agent-core-43r4bxey.js";
|
|
65
65
|
import {
|
|
66
66
|
TaskComponent
|
|
67
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
67
|
+
} from "./shared/@ai-setting/roy-agent-core-1k83dq3a.js";
|
|
68
68
|
import"./shared/@ai-setting/roy-agent-core-58804s3j.js";
|
|
69
69
|
import"./shared/@ai-setting/roy-agent-core-jm136jzh.js";
|
|
70
|
-
import"./shared/@ai-setting/roy-agent-core-
|
|
70
|
+
import"./shared/@ai-setting/roy-agent-core-dnjm17sa.js";
|
|
71
71
|
import"./shared/@ai-setting/roy-agent-core-fttgm52a.js";
|
|
72
72
|
import"./shared/@ai-setting/roy-agent-core-ntq0gz7q.js";
|
|
73
73
|
import"./shared/@ai-setting/roy-agent-core-8gxth0eh.js";
|
|
74
|
-
import"./shared/@ai-setting/roy-agent-core-
|
|
74
|
+
import"./shared/@ai-setting/roy-agent-core-h5vmff8w.js";
|
|
75
75
|
import"./shared/@ai-setting/roy-agent-core-p5cz9m8v.js";
|
|
76
76
|
import {
|
|
77
77
|
EventSourceComponent
|
|
78
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
78
|
+
} from "./shared/@ai-setting/roy-agent-core-x0ddc2cr.js";
|
|
79
79
|
import {
|
|
80
80
|
BountyIMInstance,
|
|
81
81
|
COMMAND_PREFIX,
|
|
@@ -107,7 +107,7 @@ import {
|
|
|
107
107
|
timerHandler,
|
|
108
108
|
translateCardActionToCommand,
|
|
109
109
|
writeFallbackModelList
|
|
110
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
110
|
+
} from "./shared/@ai-setting/roy-agent-core-19na22cc.js";
|
|
111
111
|
import {
|
|
112
112
|
BUILT_IN_EVENT_SOURCE_TYPES,
|
|
113
113
|
BUILT_IN_EVENT_SOURCE_TYPE_LIST,
|
|
@@ -132,7 +132,7 @@ import {
|
|
|
132
132
|
import {
|
|
133
133
|
TaskTagPlugin,
|
|
134
134
|
createAutoTaskPlugin
|
|
135
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
135
|
+
} from "./shared/@ai-setting/roy-agent-core-keyb45z3.js";
|
|
136
136
|
import {
|
|
137
137
|
EventStoreImpl,
|
|
138
138
|
getSharedEventStore,
|
|
@@ -149,10 +149,11 @@ import {
|
|
|
149
149
|
import {
|
|
150
150
|
getBuiltInPrompt,
|
|
151
151
|
getBuiltInPromptNames
|
|
152
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
152
|
+
} from "./shared/@ai-setting/roy-agent-core-ma35jyd9.js";
|
|
153
153
|
import"./shared/@ai-setting/roy-agent-core-tr3ep81v.js";
|
|
154
|
-
import"./shared/@ai-setting/roy-agent-core-
|
|
155
|
-
import"./shared/@ai-setting/roy-agent-core-
|
|
154
|
+
import"./shared/@ai-setting/roy-agent-core-6m4bw8jy.js";
|
|
155
|
+
import"./shared/@ai-setting/roy-agent-core-8bjj3d1b.js";
|
|
156
|
+
import"./shared/@ai-setting/roy-agent-core-tadj19vp.js";
|
|
156
157
|
import {
|
|
157
158
|
WorkflowComponent
|
|
158
159
|
} from "./shared/@ai-setting/roy-agent-core-37tj4y6a.js";
|
|
@@ -199,7 +200,7 @@ import"./shared/@ai-setting/roy-agent-core-jagkferh.js";
|
|
|
199
200
|
import {
|
|
200
201
|
AgentComponent,
|
|
201
202
|
AgentComponentConfigSchema
|
|
202
|
-
} from "./shared/@ai-setting/roy-agent-core-
|
|
203
|
+
} from "./shared/@ai-setting/roy-agent-core-hfr6bzts.js";
|
|
203
204
|
import {
|
|
204
205
|
ToolComponent,
|
|
205
206
|
ToolRegistry,
|
|
@@ -13,17 +13,17 @@ import {
|
|
|
13
13
|
createPerTaskGroupChatPlugin,
|
|
14
14
|
extractPerTaskChatId,
|
|
15
15
|
extractPerTaskChatName
|
|
16
|
-
} from "./roy-agent-core-
|
|
16
|
+
} from "./roy-agent-core-keyb45z3.js";
|
|
17
17
|
import {
|
|
18
18
|
getSharedEventStore
|
|
19
19
|
} from "./roy-agent-core-na18zwj0.js";
|
|
20
20
|
import {
|
|
21
21
|
createLarkCliWorkflowNotifyHook
|
|
22
|
-
} from "./roy-agent-core-
|
|
22
|
+
} from "./roy-agent-core-8bjj3d1b.js";
|
|
23
23
|
import {
|
|
24
24
|
LarkCardPatchNotifier,
|
|
25
25
|
buildTaskCard
|
|
26
|
-
} from "./roy-agent-core-
|
|
26
|
+
} from "./roy-agent-core-tadj19vp.js";
|
|
27
27
|
import {
|
|
28
28
|
normalizeLarkAtMentions
|
|
29
29
|
} from "./roy-agent-core-m880qz3y.js";
|
|
@@ -311,6 +311,88 @@ var SELF_REMINDER_MESSAGE = `[Timer Self-Reminder]
|
|
|
311
311
|
|
|
312
312
|
请根据分析结果,创建 1-3 个有价值的任务并执行。`;
|
|
313
313
|
var TIMER_OPTIONS_KEY_GET_MANAGER = "getBackgroundTaskManager";
|
|
314
|
+
var SCHEDULE_TICK_INTERVAL_MS = 30 * 1000;
|
|
315
|
+
var TIMER_OPTIONS_KEY_SCHEDULE = "schedule";
|
|
316
|
+
var TIMER_OPTIONS_KEY_SESSION_ID = "sessionId";
|
|
317
|
+
var TIMER_OPTIONS_KEY_SKIP_WHEN_RUNNING = "skipWhenRunning";
|
|
318
|
+
var TIME_PATTERN = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
319
|
+
function isValidScheduleTime(time) {
|
|
320
|
+
return typeof time === "string" && TIME_PATTERN.test(time);
|
|
321
|
+
}
|
|
322
|
+
function parseSchedule(raw) {
|
|
323
|
+
if (!Array.isArray(raw))
|
|
324
|
+
return [];
|
|
325
|
+
const result = [];
|
|
326
|
+
for (const item of raw) {
|
|
327
|
+
if (!item || typeof item !== "object")
|
|
328
|
+
continue;
|
|
329
|
+
const obj = item;
|
|
330
|
+
if (!isValidScheduleTime(obj.time))
|
|
331
|
+
continue;
|
|
332
|
+
if (typeof obj.prompt !== "string" || obj.prompt.trim().length === 0)
|
|
333
|
+
continue;
|
|
334
|
+
const entry = {
|
|
335
|
+
time: obj.time,
|
|
336
|
+
prompt: obj.prompt
|
|
337
|
+
};
|
|
338
|
+
if (typeof obj.label === "string" && obj.label.length > 0) {
|
|
339
|
+
entry.label = obj.label;
|
|
340
|
+
}
|
|
341
|
+
if (typeof obj.sessionId === "string" && obj.sessionId.length > 0) {
|
|
342
|
+
entry.sessionId = obj.sessionId;
|
|
343
|
+
}
|
|
344
|
+
result.push(entry);
|
|
345
|
+
}
|
|
346
|
+
return result;
|
|
347
|
+
}
|
|
348
|
+
function validateScheduleConfig(config) {
|
|
349
|
+
const errors = [];
|
|
350
|
+
const options = config.options ?? {};
|
|
351
|
+
const raw = options[TIMER_OPTIONS_KEY_SCHEDULE];
|
|
352
|
+
if (raw === undefined || raw === null)
|
|
353
|
+
return errors;
|
|
354
|
+
if (!Array.isArray(raw)) {
|
|
355
|
+
errors.push("Timer schedule must be an array of { time, prompt } entries");
|
|
356
|
+
return errors;
|
|
357
|
+
}
|
|
358
|
+
if (raw.length === 0) {
|
|
359
|
+
errors.push("Timer schedule must not be empty");
|
|
360
|
+
return errors;
|
|
361
|
+
}
|
|
362
|
+
raw.forEach((item, index) => {
|
|
363
|
+
if (!item || typeof item !== "object") {
|
|
364
|
+
errors.push(`Timer schedule[${index}] must be an object`);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const obj = item;
|
|
368
|
+
if (!isValidScheduleTime(obj.time)) {
|
|
369
|
+
errors.push(`Timer schedule[${index}].time must be in HH:MM format (24-hour), got: ${String(obj.time)}`);
|
|
370
|
+
}
|
|
371
|
+
if (typeof obj.prompt !== "string" || obj.prompt.trim().length === 0) {
|
|
372
|
+
errors.push(`Timer schedule[${index}].prompt is required and must be a non-empty string`);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
const seenTimes = new Set;
|
|
376
|
+
const duplicatedTimes = new Set;
|
|
377
|
+
for (const item of raw) {
|
|
378
|
+
if (!item || typeof item !== "object")
|
|
379
|
+
continue;
|
|
380
|
+
const time = item.time;
|
|
381
|
+
if (!isValidScheduleTime(time))
|
|
382
|
+
continue;
|
|
383
|
+
if (seenTimes.has(time)) {
|
|
384
|
+
duplicatedTimes.add(time);
|
|
385
|
+
}
|
|
386
|
+
seenTimes.add(time);
|
|
387
|
+
}
|
|
388
|
+
if (duplicatedTimes.size > 0) {
|
|
389
|
+
errors.push(`Timer schedule contains duplicate time entries: ${Array.from(duplicatedTimes).join(", ")}`);
|
|
390
|
+
}
|
|
391
|
+
if (config.interval !== undefined && config.interval !== null) {
|
|
392
|
+
errors.push("Timer schedule and interval are mutually exclusive: use schedule for fixed daily times, or interval for periodic triggering");
|
|
393
|
+
}
|
|
394
|
+
return errors;
|
|
395
|
+
}
|
|
314
396
|
|
|
315
397
|
class TimerInstance {
|
|
316
398
|
config;
|
|
@@ -318,21 +400,38 @@ class TimerInstance {
|
|
|
318
400
|
sessionId;
|
|
319
401
|
getRunningTasks;
|
|
320
402
|
customPrompt;
|
|
403
|
+
schedule;
|
|
404
|
+
scheduleMode;
|
|
405
|
+
invalidScheduleWarned = false;
|
|
406
|
+
scheduleSessionId;
|
|
407
|
+
skipWhenRunning;
|
|
408
|
+
firedKeys = new Set;
|
|
409
|
+
now;
|
|
321
410
|
status = "created";
|
|
322
411
|
timerId;
|
|
323
412
|
eventHandler;
|
|
324
|
-
constructor(config, getRunningTasks) {
|
|
413
|
+
constructor(config, getRunningTasks, now) {
|
|
325
414
|
this.config = config;
|
|
326
|
-
this.
|
|
415
|
+
this.now = now ?? (() => Date.now());
|
|
416
|
+
const options = config.options ?? {};
|
|
417
|
+
const rawSchedule = options[TIMER_OPTIONS_KEY_SCHEDULE];
|
|
418
|
+
const scheduleConfigured = rawSchedule !== undefined && rawSchedule !== null;
|
|
419
|
+
this.schedule = parseSchedule(rawSchedule);
|
|
420
|
+
this.scheduleMode = scheduleConfigured;
|
|
421
|
+
const isScheduleMode = this.scheduleMode;
|
|
422
|
+
this.interval = isScheduleMode ? SCHEDULE_TICK_INTERVAL_MS : typeof config.interval === "number" && config.interval > 0 ? config.interval : DEFAULT_TIMER_INTERVAL_MS;
|
|
327
423
|
this.sessionId = `timer-${config.id}-${process.pid}`;
|
|
328
|
-
const
|
|
424
|
+
const explicitSessionId = options[TIMER_OPTIONS_KEY_SESSION_ID];
|
|
425
|
+
this.scheduleSessionId = typeof explicitSessionId === "string" && explicitSessionId.length > 0 ? explicitSessionId : `timer-${config.id}`;
|
|
426
|
+
this.skipWhenRunning = options[TIMER_OPTIONS_KEY_SKIP_WHEN_RUNNING] === true;
|
|
427
|
+
const optionsPrompt = options.prompt;
|
|
329
428
|
if (typeof optionsPrompt === "string" && optionsPrompt.trim().length > 0) {
|
|
330
429
|
this.customPrompt = optionsPrompt;
|
|
331
430
|
}
|
|
332
431
|
if (getRunningTasks) {
|
|
333
432
|
this.getRunningTasks = getRunningTasks;
|
|
334
433
|
} else {
|
|
335
|
-
const factory =
|
|
434
|
+
const factory = options[TIMER_OPTIONS_KEY_GET_MANAGER];
|
|
336
435
|
if (typeof factory === "function") {
|
|
337
436
|
const manager = factory();
|
|
338
437
|
this.getRunningTasks = () => manager.listTasks();
|
|
@@ -341,6 +440,9 @@ class TimerInstance {
|
|
|
341
440
|
}
|
|
342
441
|
}
|
|
343
442
|
}
|
|
443
|
+
get isScheduleMode() {
|
|
444
|
+
return this.scheduleMode;
|
|
445
|
+
}
|
|
344
446
|
async start() {
|
|
345
447
|
if (this.status === "running")
|
|
346
448
|
return;
|
|
@@ -366,6 +468,10 @@ class TimerInstance {
|
|
|
366
468
|
this.eventHandler = undefined;
|
|
367
469
|
}
|
|
368
470
|
tick() {
|
|
471
|
+
if (this.isScheduleMode) {
|
|
472
|
+
this.tickSchedule();
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
369
475
|
let allTasks;
|
|
370
476
|
try {
|
|
371
477
|
allTasks = this.getRunningTasks();
|
|
@@ -380,19 +486,81 @@ class TimerInstance {
|
|
|
380
486
|
const event = this.buildSelfReminderEvent();
|
|
381
487
|
this.eventHandler?.(event);
|
|
382
488
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
489
|
+
tickSchedule() {
|
|
490
|
+
if (this.schedule.length === 0) {
|
|
491
|
+
if (!this.invalidScheduleWarned) {
|
|
492
|
+
this.invalidScheduleWarned = true;
|
|
493
|
+
console.warn(`[TimerInstance] Timer ${this.config.id} has an invalid or empty schedule configuration; ` + `no events will be fired. Check options.schedule (expected [{ time: "HH:MM", prompt: "..." }]).`);
|
|
494
|
+
}
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
const now = new Date(this.now());
|
|
498
|
+
const hh = String(now.getHours()).padStart(2, "0");
|
|
499
|
+
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
500
|
+
const currentTime = `${hh}:${mm}`;
|
|
501
|
+
const dateKey = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
502
|
+
for (const entry of this.schedule) {
|
|
503
|
+
if (entry.time !== currentTime)
|
|
504
|
+
continue;
|
|
505
|
+
const firedKey = `${dateKey}#${entry.time}`;
|
|
506
|
+
if (this.firedKeys.has(firedKey)) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (this.skipWhenRunning) {
|
|
510
|
+
let hasRunning = false;
|
|
511
|
+
try {
|
|
512
|
+
const allTasks = this.getRunningTasks();
|
|
513
|
+
hasRunning = Array.isArray(allTasks) && allTasks.some((t) => t.status === "running");
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.warn(`[TimerInstance] Failed to get running tasks, skipping tick: ${error}`);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (hasRunning) {
|
|
519
|
+
continue;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
this.firedKeys.add(firedKey);
|
|
523
|
+
this.pruneFiredKeys(dateKey);
|
|
524
|
+
const event = this.buildSelfReminderEvent(entry);
|
|
525
|
+
this.eventHandler?.(event);
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
pruneFiredKeys(currentDateKey) {
|
|
530
|
+
if (this.firedKeys.size <= 32)
|
|
531
|
+
return;
|
|
532
|
+
for (const key of this.firedKeys) {
|
|
533
|
+
const datePart = key.split("#")[0];
|
|
534
|
+
if (datePart !== currentDateKey) {
|
|
535
|
+
this.firedKeys.delete(key);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
buildSelfReminderEvent(entry) {
|
|
540
|
+
const timestamp = this.now();
|
|
541
|
+
const message = entry?.prompt ?? this.customPrompt ?? SELF_REMINDER_MESSAGE;
|
|
542
|
+
const triggerSessionId = entry !== undefined ? entry.sessionId ?? this.scheduleSessionId : undefined;
|
|
543
|
+
const metadata = {
|
|
544
|
+
source: "event-source",
|
|
545
|
+
sourceId: this.config.id,
|
|
546
|
+
sourceMessageType: "timer.selfReminder",
|
|
547
|
+
sessionId: this.sessionId
|
|
548
|
+
};
|
|
549
|
+
if (triggerSessionId !== undefined) {
|
|
550
|
+
metadata.trigger_session_id = triggerSessionId;
|
|
551
|
+
metadata.createSessionIfMissing = true;
|
|
552
|
+
}
|
|
553
|
+
if (entry?.label !== undefined) {
|
|
554
|
+
metadata.scheduleLabel = entry.label;
|
|
555
|
+
}
|
|
556
|
+
if (entry !== undefined) {
|
|
557
|
+
metadata.scheduleTime = entry.time;
|
|
558
|
+
}
|
|
386
559
|
return {
|
|
387
560
|
id: `es-${this.config.id}-${timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
388
561
|
type: "event-source.event.timer",
|
|
389
562
|
timestamp,
|
|
390
|
-
metadata
|
|
391
|
-
source: "event-source",
|
|
392
|
-
sourceId: this.config.id,
|
|
393
|
-
sourceMessageType: "timer.selfReminder",
|
|
394
|
-
sessionId: this.sessionId
|
|
395
|
-
},
|
|
563
|
+
metadata,
|
|
396
564
|
payload: {
|
|
397
565
|
sourceId: this.config.id,
|
|
398
566
|
sourceType: "timer",
|
|
@@ -415,6 +583,9 @@ class TimerInstance {
|
|
|
415
583
|
__legacyDecorateClassTS([
|
|
416
584
|
TracedAs("timer.tick", { recordParams: false, log: false })
|
|
417
585
|
], TimerInstance.prototype, "tick", null);
|
|
586
|
+
__legacyDecorateClassTS([
|
|
587
|
+
TracedAs("timer.tickSchedule", { recordParams: false, log: false })
|
|
588
|
+
], TimerInstance.prototype, "tickSchedule", null);
|
|
418
589
|
__legacyDecorateClassTS([
|
|
419
590
|
TracedAs("timer.buildSelfReminderEvent", { recordParams: false, log: false })
|
|
420
591
|
], TimerInstance.prototype, "buildSelfReminderEvent", null);
|
|
@@ -423,7 +594,9 @@ var timerHandler = {
|
|
|
423
594
|
validateConfig(config) {
|
|
424
595
|
const errors = [];
|
|
425
596
|
const { interval } = config;
|
|
426
|
-
|
|
597
|
+
errors.push(...validateScheduleConfig(config));
|
|
598
|
+
const hasSchedule = config.options?.[TIMER_OPTIONS_KEY_SCHEDULE] !== undefined;
|
|
599
|
+
if (!hasSchedule && interval !== undefined && interval !== null) {
|
|
427
600
|
if (typeof interval !== "number" || !Number.isFinite(interval)) {
|
|
428
601
|
errors.push("Timer interval must be a finite number");
|
|
429
602
|
} else if (interval <= 0) {
|
|
@@ -439,7 +612,7 @@ var timerHandler = {
|
|
|
439
612
|
return [
|
|
440
613
|
{
|
|
441
614
|
name: "interval",
|
|
442
|
-
description: `Timer interval in milliseconds (default: ${DEFAULT_TIMER_INTERVAL_MS} = 10 minutes)
|
|
615
|
+
description: `Timer interval in milliseconds (default: ${DEFAULT_TIMER_INTERVAL_MS} = 10 minutes). Mutually exclusive with schedule.`,
|
|
443
616
|
required: false,
|
|
444
617
|
type: "number"
|
|
445
618
|
},
|
|
@@ -448,6 +621,18 @@ var timerHandler = {
|
|
|
448
621
|
description: "Custom prompt message for SelfReminder events (replaces default message)",
|
|
449
622
|
required: false,
|
|
450
623
|
type: "string"
|
|
624
|
+
},
|
|
625
|
+
{
|
|
626
|
+
name: TIMER_OPTIONS_KEY_SCHEDULE,
|
|
627
|
+
description: "JSON array of { time: 'HH:MM', prompt: string, label?: string, sessionId?: string } " + "for fixed daily trigger times (e.g. 10:00 / 17:00 / 20:00). Mutually exclusive with interval.",
|
|
628
|
+
required: false,
|
|
629
|
+
type: "string"
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
name: TIMER_OPTIONS_KEY_SESSION_ID,
|
|
633
|
+
description: "Explicit session ID for timer events (schedule mode). Events are routed to this " + "session instead of the main REPL session.",
|
|
634
|
+
required: false,
|
|
635
|
+
type: "string"
|
|
451
636
|
}
|
|
452
637
|
];
|
|
453
638
|
}
|