@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,6 @@
|
|
|
1
|
+
// src/env/task/tools/completion-copy.ts
|
|
2
|
+
var TASK_COMPLETE_ITEM_BY_ITEM = "按子项逐条验收";
|
|
3
|
+
var TASK_COMPLETION_HINT_ANCHOR = "TASK_COMPLETION_HINT";
|
|
4
|
+
var TASK_COMPLETE_VERIFY_DUTY = "核实义务";
|
|
5
|
+
|
|
6
|
+
export { TASK_COMPLETE_ITEM_BY_ITEM, TASK_COMPLETION_HINT_ANCHOR, TASK_COMPLETE_VERIFY_DUTY };
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./roy-agent-core-1pg0fepg.js";
|
|
11
11
|
import {
|
|
12
12
|
builtInPrompts
|
|
13
|
-
} from "./roy-agent-core-
|
|
13
|
+
} from "./roy-agent-core-ma35jyd9.js";
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_SUBAGENT_PROMPT
|
|
16
16
|
} from "./roy-agent-core-07fvy74y.js";
|
|
@@ -1832,14 +1832,33 @@ ${reuseSection.markdown}`;
|
|
|
1832
1832
|
async forceStopAll() {
|
|
1833
1833
|
return this.forceStopAllAcrossParents();
|
|
1834
1834
|
}
|
|
1835
|
-
async dispose() {
|
|
1835
|
+
async dispose(options) {
|
|
1836
1836
|
for (const [, timer] of this.progressTimers) {
|
|
1837
1837
|
try {
|
|
1838
1838
|
clearInterval(timer);
|
|
1839
1839
|
} catch {}
|
|
1840
1840
|
}
|
|
1841
1841
|
this.progressTimers.clear();
|
|
1842
|
+
const skipAbortRunningTasks = options?.skipAbortRunningTasks === true;
|
|
1843
|
+
const waitForRunningTasks = options?.waitForRunningTasks === true;
|
|
1844
|
+
if (waitForRunningTasks && skipAbortRunningTasks) {
|
|
1845
|
+
const waitStart = Date.now();
|
|
1846
|
+
const WAIT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
1847
|
+
while (Date.now() - waitStart < WAIT_TIMEOUT_MS) {
|
|
1848
|
+
let running = 0;
|
|
1849
|
+
for (const [, t] of this.tasks) {
|
|
1850
|
+
if (t.status === "running" || t.status === "pending")
|
|
1851
|
+
running++;
|
|
1852
|
+
}
|
|
1853
|
+
if (running === 0)
|
|
1854
|
+
break;
|
|
1855
|
+
logger3.info(`[BackgroundTaskManager] dispose waiting for ${running} running task(s)`);
|
|
1856
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1842
1859
|
for (const [, controller] of this.abortControllers) {
|
|
1860
|
+
if (skipAbortRunningTasks)
|
|
1861
|
+
break;
|
|
1843
1862
|
try {
|
|
1844
1863
|
controller.abort();
|
|
1845
1864
|
} catch {}
|
|
@@ -2,6 +2,11 @@ import {
|
|
|
2
2
|
NEW_TASK_ID_HASH_PLACEHOLDER,
|
|
3
3
|
NEW_TASK_ID_PLACEHOLDER
|
|
4
4
|
} from "./roy-agent-core-tr3ep81v.js";
|
|
5
|
+
import {
|
|
6
|
+
TASK_COMPLETE_ITEM_BY_ITEM,
|
|
7
|
+
TASK_COMPLETE_VERIFY_DUTY,
|
|
8
|
+
TASK_COMPLETION_HINT_ANCHOR
|
|
9
|
+
} from "./roy-agent-core-6m4bw8jy.js";
|
|
5
10
|
import {
|
|
6
11
|
getEnvContextOrEmpty,
|
|
7
12
|
init_env_context,
|
|
@@ -38,7 +43,7 @@ var CreateTaskToolSchema = z.object({
|
|
|
38
43
|
description: z.string().optional().describe("Task description"),
|
|
39
44
|
priority: z.enum(["low", "medium", "high"]).optional().describe("Task priority"),
|
|
40
45
|
type: z.enum(["normal", "cycle", "longterm"]).optional().default("normal").describe("Task type. normal: 常规任务,需要跟踪完成. cycle: 周期任务(如每周发周报),无需 complete,定期执行. longterm: 长期任务/愿景目标(如提升公司影响力),难以一次性完成,持续跟进"),
|
|
41
|
-
goals_and_expected_deliverables: z.string().optional().describe("Goals and expected deliverables"),
|
|
46
|
+
goals_and_expected_deliverables: z.string().optional().describe("Goals and expected deliverables. " + "⚠️ 写成可逐条验收的编号子项(1. … 2. … 3. …),每条是一个可判定的交付/动作" + "(文件断言:文件存在/大小/内容;进程断言:命令 exit code/stdout;" + "测试断言:pass/fail 计数;状态断言:版本号/HTTP 200/状态字段)。" + "避免一句话模糊目标(如「做好 X」「完成调研」)——" + "任务完成时 completion hook 会按这些子项逐条对照操作记录验收。"),
|
|
42
47
|
due_date: z.string().optional().describe("Due date (ISO format)"),
|
|
43
48
|
tags: z.array(z.string()).optional().describe("Task tags (for search, stored in task.tags JSON field)"),
|
|
44
49
|
project_path: z.string().default("unknown").describe("Project root path for task positioning. " + "Used to locate the project space for this task. " + "Use 'unknown' if unknown. (Defaults to 'unknown'.)"),
|
|
@@ -84,7 +89,7 @@ var UpdateTaskToolSchema = withLegacyTaskId({
|
|
|
84
89
|
type: z.enum(["normal", "cycle", "longterm"]).optional().describe("Task type"),
|
|
85
90
|
progress: z.number().min(0).max(100).optional(),
|
|
86
91
|
current_status: z.string().optional(),
|
|
87
|
-
goals_and_expected_deliverables: z.string().optional(),
|
|
92
|
+
goals_and_expected_deliverables: z.string().optional().describe("Goals and expected deliverables. " + "⚠️ 追加/修改时同样写成可逐条验收的编号子项(1. … 2. … 3. …)," + "每条是一个可判定的交付/动作(文件断言:文件存在/大小/内容;" + "进程断言:命令 exit code/stdout;测试断言:pass/fail 计数;" + "状态断言:版本号/HTTP 200/状态字段)。" + "避免一句话模糊目标(如「做好 X」「完成调研」)——" + "任务完成时 completion hook 会按这些子项逐条对照操作记录验收。" + "(Task #4833 — 与 task_create 的 goals 规则同源)"),
|
|
88
93
|
due_date: z.string().optional(),
|
|
89
94
|
tags: z.array(z.string()).optional(),
|
|
90
95
|
project_path: z.string().optional().describe("Project path, identifies which project this task belongs to"),
|
|
@@ -316,6 +321,37 @@ function createTaskTool(taskComponent) {
|
|
|
316
321
|
- Same-theme tasks cluster under one parent
|
|
317
322
|
- Long-tail/stranded tasks should be archived or merged
|
|
318
323
|
|
|
324
|
+
## ⚠️ Goals 子项拆分规则 (Task #4791)
|
|
325
|
+
|
|
326
|
+
\`goals_and_expected_deliverables\` **MUST** be written as
|
|
327
|
+
**numbered sub-items** (编号子项) that can each be verified
|
|
328
|
+
one by one (逐条验收) — for \`type=normal\` tasks:
|
|
329
|
+
|
|
330
|
+
1. 实现 X(含文件路径)
|
|
331
|
+
2. 测试 Y 覆盖 Z 场景(pass/fail 计数)
|
|
332
|
+
3. 文档 W 落盘到 <path>
|
|
333
|
+
|
|
334
|
+
⚠️ For \`type=longterm\` / \`type=cycle\` tasks there is no
|
|
335
|
+
per-item completion acceptance(不走逐条 complete 验收), so the
|
|
336
|
+
MUST above does not apply; for those, it is **strongly recommended**
|
|
337
|
+
(建议) to split goals into staged, individually checkable sub-items
|
|
338
|
+
(阶段性可判子项) instead of one vague sentence.
|
|
339
|
+
|
|
340
|
+
Why: when the task is completed, the completion hook
|
|
341
|
+
(task:after.complete) judges the whole goal against the
|
|
342
|
+
operation-record chain, using each sub-item as fine-grained
|
|
343
|
+
evidence (逐条对照的依据). Vague one-line goals (一句话模糊目标,
|
|
344
|
+
如「做好 X」「完成调研」) give the judge nothing to check and
|
|
345
|
+
make a completion hint much more likely.
|
|
346
|
+
|
|
347
|
+
Reference the four atomic assertion forms (Task #4768
|
|
348
|
+
四原子形态) when writing each sub-item:
|
|
349
|
+
|
|
350
|
+
- 文件断言 (file assertion): file exists / size / content grep
|
|
351
|
+
- 进程断言 (process assertion): command exit code / stdout match
|
|
352
|
+
- 测试断言 (test assertion): pass/fail counts, no NEW fail
|
|
353
|
+
- 状态断言 (state assertion): version number / HTTP 200 / status field
|
|
354
|
+
|
|
319
355
|
## ⚠️ Spatial + Temporal Context (Task #2325)
|
|
320
356
|
|
|
321
357
|
A task MUST carry spatio-temporal context so it survives task-handoff
|
|
@@ -917,8 +953,28 @@ Mark a task as completed (progress=100, status=completed). Creates an operation
|
|
|
917
953
|
|
|
918
954
|
1. Read the task's \`goal\` (description) and \`delivery\` (goals_and_expected_deliverables) fields.
|
|
919
955
|
- Use \`task_get(task_id=<id>)\` to fetch the full task record.
|
|
920
|
-
2. **Validate
|
|
921
|
-
-
|
|
956
|
+
2. **Validate whether each goal sub-item was achieved** (${TASK_COMPLETE_ITEM_BY_ITEM}).
|
|
957
|
+
- Goals should be numbered sub-items (编号子项, see task_create rules). Check
|
|
958
|
+
each sub-item against the operation-record chain (操作记录链) and the
|
|
959
|
+
deliverable evidence (context.deliverable_storage_path).
|
|
960
|
+
- The completion hook (task:after.complete) judges the whole goal vs.
|
|
961
|
+
deliverables; numbered sub-items give it finer-grained evidence to
|
|
962
|
+
reason with (逐条对照的证据粒度). If it detects that the goal or
|
|
963
|
+
deliverables appear unmet, the task context will carry a
|
|
964
|
+
\`[${TASK_COMPLETION_HINT_ANCHOR}]\`.
|
|
965
|
+
- **If you receive a [${TASK_COMPLETION_HINT_ANCHOR}]**, you MUST verify it
|
|
966
|
+
(${TASK_COMPLETE_VERIFY_DUTY}): re-read the task via \`task_get\`, then do exactly one of:
|
|
967
|
+
(a) 确认未完成 → \`task_update(task_id=<id>, status=todo)\` reopen and continue; or
|
|
968
|
+
(b) 确认已完成 → \`task_operation_create\` (milestone_type=decision,
|
|
969
|
+
milestone_title=<一行结论>) state why the sub-items are actually
|
|
970
|
+
met (说明理由).
|
|
971
|
+
Never ignore it (不允许无视).
|
|
972
|
+
- If the goal and delivery mismatch **without** a hint, either:
|
|
973
|
+
(a) extend the task via \`task_update\`, or
|
|
974
|
+
(b) record the discrepancy via \`task_operation_create\`
|
|
975
|
+
(milestone_type=decision) — the reason **must** land in the
|
|
976
|
+
operation record (必须落到操作记录里), not merely a line in
|
|
977
|
+
your final report (不能只在报告里带一句).
|
|
922
978
|
3. **Provide \`deliverable_storage_path\`** parameter with the deliverable's address:
|
|
923
979
|
- Feishu doc URL (e.g., https://my.feishu.cn/docx/abc)
|
|
924
980
|
- Local file path (e.g., /tmp/report.md)
|
|
@@ -68,6 +68,8 @@ import {
|
|
|
68
68
|
|
|
69
69
|
// src/env/agent/agent-component.ts
|
|
70
70
|
init_logger();
|
|
71
|
+
import fs from "fs/promises";
|
|
72
|
+
import path from "path";
|
|
71
73
|
import { z } from "zod";
|
|
72
74
|
|
|
73
75
|
// src/env/task/plugins/max-iteration-reminder-plugin.ts
|
|
@@ -600,6 +602,7 @@ class AgentComponent extends BaseComponent {
|
|
|
600
602
|
doomLoopCaches = new Map;
|
|
601
603
|
fallbackState = new Map;
|
|
602
604
|
configComponent;
|
|
605
|
+
skipAbortRunningTasksOnStop = false;
|
|
603
606
|
configWatcher;
|
|
604
607
|
messageConverter = new SessionMessageConverter;
|
|
605
608
|
_constructorConfig;
|
|
@@ -622,6 +625,7 @@ class AgentComponent extends BaseComponent {
|
|
|
622
625
|
throw new Error("ConfigComponent is required for AgentComponent initialization");
|
|
623
626
|
}
|
|
624
627
|
this.configComponent = options.configComponent;
|
|
628
|
+
this.skipAbortRunningTasksOnStop = options.skipAbortRunningTasksOnStop === true;
|
|
625
629
|
await this.registerConfig(options);
|
|
626
630
|
await this.initRegistry(options.configComponent);
|
|
627
631
|
this.setStatus("running");
|
|
@@ -794,13 +798,19 @@ class AgentComponent extends BaseComponent {
|
|
|
794
798
|
}
|
|
795
799
|
async onStop() {
|
|
796
800
|
logger2.info("[AgentComponent] Stopping and cleaning up resources...");
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
+
const skipAbort = this.skipAbortRunningTasksOnStop === true;
|
|
802
|
+
if (!skipAbort) {
|
|
803
|
+
for (const [name, agent] of this.agents) {
|
|
804
|
+
if (agent.status === "running" || agent.status === "idle") {
|
|
805
|
+
this.abort(name);
|
|
806
|
+
logger2.debug(`[AgentComponent] Aborted agent: ${name}`);
|
|
807
|
+
}
|
|
801
808
|
}
|
|
809
|
+
} else {
|
|
810
|
+
logger2.info("[AgentComponent] skipAbortRunningTasksOnStop=true — keeping running agent runs alive");
|
|
802
811
|
}
|
|
803
812
|
this.abortControllers.clear();
|
|
813
|
+
this.aborted.clear();
|
|
804
814
|
this.doomLoopCaches.clear();
|
|
805
815
|
if (this.configWatcher) {
|
|
806
816
|
this.configWatcher();
|
|
@@ -1603,12 +1613,18 @@ class AgentComponent extends BaseComponent {
|
|
|
1603
1613
|
const session = await sessionComponent.get(sessionId);
|
|
1604
1614
|
const existingSnapshot = session?.metadata?.cacheSnapshot;
|
|
1605
1615
|
if (existingSnapshot && typeof existingSnapshot === "object" && existingSnapshot.systemPrompt) {
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1616
|
+
const stale = await this._isMemorySnapshotStale(existingSnapshot);
|
|
1617
|
+
if (stale) {
|
|
1618
|
+
logger2.info(`[AgentComponent._run] cacheSnapshot for session ${sessionId} is stale (${stale}); recreating`);
|
|
1619
|
+
} else {
|
|
1620
|
+
logger2.debug(`[AgentComponent._run] Reusing cacheSnapshot for session ${sessionId} (snapshotAt=${existingSnapshot.snapshotAt})`);
|
|
1621
|
+
return {
|
|
1622
|
+
snapshot: existingSnapshot,
|
|
1623
|
+
systemPromptOverride: existingSnapshot.systemPrompt
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1611
1626
|
}
|
|
1627
|
+
const memoryStat = await this._collectMemoryStat();
|
|
1612
1628
|
let resolvedSystemPrompt = initialSystemPrompt;
|
|
1613
1629
|
if (resolvedSystemPrompt && resolvedSystemPrompt.includes("{{memory}}")) {
|
|
1614
1630
|
try {
|
|
@@ -1627,7 +1643,8 @@ class AgentComponent extends BaseComponent {
|
|
|
1627
1643
|
const snapshot = {
|
|
1628
1644
|
systemPrompt: resolvedSystemPrompt ?? agentConfigSystemPrompt ?? "",
|
|
1629
1645
|
additionInfo: effectiveContext.additionInfo || "",
|
|
1630
|
-
snapshotAt: Date.now()
|
|
1646
|
+
snapshotAt: Date.now(),
|
|
1647
|
+
memoryStat
|
|
1631
1648
|
};
|
|
1632
1649
|
try {
|
|
1633
1650
|
await sessionComponent.update(sessionId, {
|
|
@@ -1646,6 +1663,46 @@ class AgentComponent extends BaseComponent {
|
|
|
1646
1663
|
return { snapshot: null, systemPromptOverride: undefined };
|
|
1647
1664
|
}
|
|
1648
1665
|
}
|
|
1666
|
+
async _isMemorySnapshotStale(snapshot) {
|
|
1667
|
+
const stat = snapshot.memoryStat;
|
|
1668
|
+
if (!stat || typeof stat !== "object") {
|
|
1669
|
+
return "no-memoryStat (legacy snapshot)";
|
|
1670
|
+
}
|
|
1671
|
+
const current = await this._collectMemoryStat();
|
|
1672
|
+
if (current.globalMtime !== stat.globalMtime) {
|
|
1673
|
+
return `global memory.md mtime changed (${stat.globalMtime} -> ${current.globalMtime})`;
|
|
1674
|
+
}
|
|
1675
|
+
if (current.projectMtime !== stat.projectMtime) {
|
|
1676
|
+
return `project memory.md mtime changed (${stat.projectMtime} -> ${current.projectMtime})`;
|
|
1677
|
+
}
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
async _collectMemoryStat() {
|
|
1681
|
+
const empty = { globalMtime: 0, projectMtime: 0 };
|
|
1682
|
+
try {
|
|
1683
|
+
const memoryComponent = this.env?.getComponent?.("memory");
|
|
1684
|
+
if (!memoryComponent?.getMemoryPaths || !memoryComponent.getMemoryFile) {
|
|
1685
|
+
return empty;
|
|
1686
|
+
}
|
|
1687
|
+
const memoryFile = memoryComponent.getMemoryFile();
|
|
1688
|
+
const paths = memoryComponent.getMemoryPaths();
|
|
1689
|
+
const result = { globalMtime: 0, projectMtime: 0 };
|
|
1690
|
+
for (const p of paths) {
|
|
1691
|
+
const filePath = path.join(p.path, memoryFile);
|
|
1692
|
+
try {
|
|
1693
|
+
const st = await fs.stat(filePath);
|
|
1694
|
+
if (p.type === "global") {
|
|
1695
|
+
result.globalMtime = st.mtimeMs;
|
|
1696
|
+
} else if (p.type === "project") {
|
|
1697
|
+
result.projectMtime = st.mtimeMs;
|
|
1698
|
+
}
|
|
1699
|
+
} catch {}
|
|
1700
|
+
}
|
|
1701
|
+
return result;
|
|
1702
|
+
} catch {
|
|
1703
|
+
return empty;
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1649
1706
|
async _fallbackReplaceMemory(systemPrompt) {
|
|
1650
1707
|
if (!systemPrompt.includes("{{memory}}"))
|
|
1651
1708
|
return systemPrompt;
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./roy-agent-core-1pg0fepg.js";
|
|
11
11
|
import {
|
|
12
12
|
WORKFLOW_EXTRACT_PROMPT
|
|
13
|
-
} from "./roy-agent-core-
|
|
13
|
+
} from "./roy-agent-core-ma35jyd9.js";
|
|
14
14
|
import {
|
|
15
15
|
assertNoLeakage,
|
|
16
16
|
buildHintText,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
import {
|
|
25
25
|
LarkCardPatchNotifier,
|
|
26
26
|
humanizeValue
|
|
27
|
-
} from "./roy-agent-core-
|
|
27
|
+
} from "./roy-agent-core-tadj19vp.js";
|
|
28
28
|
import {
|
|
29
29
|
validateWorkflowDefinition
|
|
30
30
|
} from "./roy-agent-core-yr1mryb8.js";
|
|
@@ -929,6 +929,7 @@ function truncateSnippet(text) {
|
|
|
929
929
|
var DEFAULT_TIMEOUT_MS = 2000;
|
|
930
930
|
var DEFAULT_MAX_STRIKES = 3;
|
|
931
931
|
var DEFAULT_MODEL = "task-decision";
|
|
932
|
+
var DEFAULT_GOAL_MODEL = "task-completion";
|
|
932
933
|
var SYSTEMONE_PATH = "/v1/systemone";
|
|
933
934
|
|
|
934
935
|
class LayaDecisionPort {
|
|
@@ -1058,19 +1059,32 @@ function isTimeoutError(err) {
|
|
|
1058
1059
|
}
|
|
1059
1060
|
return false;
|
|
1060
1061
|
}
|
|
1062
|
+
var LAYA_DECISION_PROVIDER = "laya-decision";
|
|
1063
|
+
var LAYA_GOAL_DECISION_PROVIDER = "laya-goal-decision";
|
|
1064
|
+
function providerNameForPurpose(purpose) {
|
|
1065
|
+
return purpose === "goal" ? LAYA_GOAL_DECISION_PROVIDER : LAYA_DECISION_PROVIDER;
|
|
1066
|
+
}
|
|
1061
1067
|
async function loadLayaAuth(authPath = `${process.env.HOME ?? "~"}/.roy-agent/auth.json`) {
|
|
1068
|
+
return loadLayaAuthForPurpose(authPath, "create");
|
|
1069
|
+
}
|
|
1070
|
+
async function loadLayaAuthForPurpose(authPath = `${process.env.HOME ?? "~"}/.roy-agent/auth.json`, purpose = "create") {
|
|
1062
1071
|
try {
|
|
1063
1072
|
const fs = await import("fs/promises");
|
|
1064
1073
|
const raw = await fs.readFile(authPath, "utf-8");
|
|
1065
1074
|
const parsed = JSON.parse(raw);
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
baseURL
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1075
|
+
const primary = providerNameForPurpose(purpose);
|
|
1076
|
+
const candidates = purpose === "goal" ? [primary, LAYA_DECISION_PROVIDER] : [primary];
|
|
1077
|
+
for (const name of candidates) {
|
|
1078
|
+
const p = parsed.providers?.[name];
|
|
1079
|
+
if (p?.baseURL && p?.apiKey) {
|
|
1080
|
+
return {
|
|
1081
|
+
baseURL: p.baseURL,
|
|
1082
|
+
apiKey: p.apiKey,
|
|
1083
|
+
model: p.model ?? (name === LAYA_GOAL_DECISION_PROVIDER ? DEFAULT_GOAL_MODEL : DEFAULT_MODEL)
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return null;
|
|
1074
1088
|
} catch {
|
|
1075
1089
|
return null;
|
|
1076
1090
|
}
|
|
@@ -2162,6 +2176,7 @@ class LarkCliTaskNotifyHook {
|
|
|
2162
2176
|
status,
|
|
2163
2177
|
meta: this.buildTaskMeta(task),
|
|
2164
2178
|
finalStep: task.current_status || undefined,
|
|
2179
|
+
expandTimeline: rawStatus === "archived" ? true : undefined,
|
|
2165
2180
|
...rawStatus === "archived" ? { pausedMilestoneTitle: "Task 已归档" } : {}
|
|
2166
2181
|
});
|
|
2167
2182
|
if (isPaused) {
|
|
@@ -2937,4 +2952,4 @@ __legacyDecorateClassTS([
|
|
|
2937
2952
|
function createPerTaskGroupChatPlugin(config = {}) {
|
|
2938
2953
|
return new PerTaskGroupChatPlugin(config);
|
|
2939
2954
|
}
|
|
2940
|
-
export { createAutoTaskPlugin, LAYA_REUSE_THRESHOLD, LayaDecisionPlugin, createLayaDecisionPlugin, WORKFLOW_EXTRACTOR_PROMPT, formatExtractorInput, formatExtractorInputFromDescription, parseExtractorOutput, TaskTagPlugin, extractPerTaskChatId, extractPerTaskChatName, NotifyType, LarkCliTaskNotifyHook, createLarkCliTaskNotifyHook, PerTaskGroupChatPlugin, createPerTaskGroupChatPlugin };
|
|
2955
|
+
export { createAutoTaskPlugin, pickGateConfidence, LayaDecisionPort, loadLayaAuthForPurpose, LAYA_REUSE_THRESHOLD, LayaDecisionPlugin, createLayaDecisionPlugin, WORKFLOW_EXTRACTOR_PROMPT, formatExtractorInput, formatExtractorInputFromDescription, parseExtractorOutput, TaskTagPlugin, extractPerTaskChatId, extractPerTaskChatName, NotifyType, LarkCliTaskNotifyHook, createLarkCliTaskNotifyHook, PerTaskGroupChatPlugin, createPerTaskGroupChatPlugin };
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TASK_COMPLETE_ITEM_BY_ITEM,
|
|
3
|
+
TASK_COMPLETE_VERIFY_DUTY,
|
|
4
|
+
TASK_COMPLETION_HINT_ANCHOR
|
|
5
|
+
} from "./roy-agent-core-6m4bw8jy.js";
|
|
6
|
+
|
|
1
7
|
// src/env/prompt/prompts-index.ts
|
|
2
8
|
var builtInPrompts = {
|
|
3
9
|
default: `你是 {{agent_name}} 接待智能体(Receptionist Agent)—— {{agent_name}} 系统的智能入口。
|
|
@@ -125,7 +131,7 @@ var builtInPrompts = {
|
|
|
125
131
|
- ✅ 功能开发、bug 修复、重构、文档生成
|
|
126
132
|
- ✅ 网络搜索和研究
|
|
127
133
|
|
|
128
|
-
**roy** 的提示词中内置了任务生命周期——它知道如何使用 \`task_create\`、\`task_update\`、\`task_operation_create\` 和 \`task_complete\` 来跟踪每项工作。
|
|
134
|
+
**roy** 的提示词中内置了任务生命周期——它知道如何使用 \`task_create\`、\`task_update\`、\`task_operation_create\` 和 \`task_complete\` 来跟踪每项工作。task_complete 时会${TASK_COMPLETE_VERIFY_DUTY}:按子项逐条验收(${TASK_COMPLETE_ITEM_BY_ITEM}),若收到 [${TASK_COMPLETION_HINT_ANCHOR}] 必须核实并二选一(重开 / 落 decision 说明理由)。
|
|
129
135
|
|
|
130
136
|
推荐使用:
|
|
131
137
|
\`\`\`
|
|
@@ -893,8 +899,13 @@ Follow this lifecycle for every task:
|
|
|
893
899
|
┌─────────────────────────────────────────────────────────────────┐
|
|
894
900
|
│ 6. COMPLETE (task_complete) │
|
|
895
901
|
│ - Mark task as completed (progress=100%, status=completed) │
|
|
896
|
-
│ -
|
|
897
|
-
│
|
|
902
|
+
│ - ${TASK_COMPLETE_ITEM_BY_ITEM}: check each goal sub-item │
|
|
903
|
+
│ against the operation-record chain + deliverable evidence │
|
|
904
|
+
│ - If a [${TASK_COMPLETION_HINT_ANCHOR}] appears in task │
|
|
905
|
+
│ context, you MUST ${TASK_COMPLETE_VERIFY_DUTY}: reopen │
|
|
906
|
+
│ (task_update status=todo) or record why it is met │
|
|
907
|
+
│ (task_operation_create decision). Never ignore it. │
|
|
908
|
+
│ - Create completion operation record │
|
|
898
909
|
└─────────────────────────────────────────────────────────────────┘
|
|
899
910
|
\`\`\`
|
|
900
911
|
|
|
@@ -148,6 +148,33 @@ var CONTEXT_SKIP_KEYS = new Set([
|
|
|
148
148
|
"larkPerTaskChatTaskId",
|
|
149
149
|
"larkPerTaskChatCreatedAt"
|
|
150
150
|
]);
|
|
151
|
+
function isTerminalStatusForTimeline(status) {
|
|
152
|
+
return status === "completed" || status === "failed" || status === "cancelled" || status === "deleted";
|
|
153
|
+
}
|
|
154
|
+
function isTerminalStatusForWorkflowTimeline(status) {
|
|
155
|
+
return status !== "running";
|
|
156
|
+
}
|
|
157
|
+
function appendHr(elements) {
|
|
158
|
+
if (elements.length > 0 && elements[elements.length - 1].tag === "hr")
|
|
159
|
+
return;
|
|
160
|
+
elements.push({ tag: "hr" });
|
|
161
|
+
}
|
|
162
|
+
function buildCollapsiblePanel(opts) {
|
|
163
|
+
const panel = {
|
|
164
|
+
tag: "collapsible_panel",
|
|
165
|
+
expanded: opts.expanded ?? false,
|
|
166
|
+
header: {
|
|
167
|
+
title: {
|
|
168
|
+
tag: "markdown",
|
|
169
|
+
content: sanitizeInlineText(opts.title, 120)
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
elements: opts.elements
|
|
173
|
+
};
|
|
174
|
+
if (opts.elementId)
|
|
175
|
+
panel.element_id = opts.elementId;
|
|
176
|
+
return panel;
|
|
177
|
+
}
|
|
151
178
|
function renderTaskInfoLines(meta) {
|
|
152
179
|
const lines = [];
|
|
153
180
|
if (meta.id !== undefined)
|
|
@@ -274,20 +301,51 @@ function buildTaskCard(opts) {
|
|
|
274
301
|
tag: "markdown",
|
|
275
302
|
content: `[${label}](${link})`
|
|
276
303
|
});
|
|
277
|
-
elements
|
|
304
|
+
appendHr(elements);
|
|
278
305
|
}
|
|
279
306
|
const infoLines = renderTaskInfoLines(opts.meta);
|
|
280
307
|
if (infoLines.length > 0) {
|
|
281
|
-
elements.push({
|
|
282
|
-
|
|
283
|
-
|
|
308
|
+
elements.push(buildCollapsiblePanel({
|
|
309
|
+
title: "\uD83D\uDCCB 任务详情",
|
|
310
|
+
elementId: "task_detail",
|
|
311
|
+
elements: [{ tag: "markdown", content: infoLines.join(`
|
|
312
|
+
`) }]
|
|
313
|
+
}));
|
|
314
|
+
appendHr(elements);
|
|
284
315
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
316
|
+
const timelineElements = [];
|
|
317
|
+
if (milestones.length > 0) {
|
|
318
|
+
timelineElements.push({
|
|
319
|
+
tag: "markdown",
|
|
320
|
+
content: `## \uD83C\uDFAF 里程碑序列`
|
|
321
|
+
});
|
|
322
|
+
timelineElements.push({
|
|
323
|
+
tag: "markdown",
|
|
324
|
+
content: renderMilestones(milestones)
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
if (processSteps.length > 0) {
|
|
328
|
+
if (timelineElements.length > 0)
|
|
329
|
+
timelineElements.push({ tag: "hr" });
|
|
330
|
+
timelineElements.push({
|
|
331
|
+
tag: "markdown",
|
|
332
|
+
content: `## \uD83D\uDD27 过程信息`
|
|
333
|
+
});
|
|
334
|
+
timelineElements.push({
|
|
335
|
+
tag: "markdown",
|
|
336
|
+
content: renderProcessSteps(processSteps)
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (timelineElements.length > 0) {
|
|
340
|
+
const timelineTitle = `⏱️ 执行动态(${milestones.length} 里程碑 / ${processSteps.length} 过程)`;
|
|
341
|
+
elements.push(buildCollapsiblePanel({
|
|
342
|
+
title: timelineTitle,
|
|
343
|
+
elementId: "task_timeline",
|
|
344
|
+
expanded: opts.expandTimeline ?? isTerminalStatusForTimeline(status),
|
|
345
|
+
elements: timelineElements
|
|
346
|
+
}));
|
|
347
|
+
}
|
|
348
|
+
appendHr(elements);
|
|
291
349
|
const effectiveProgress = status === "completed" ? 100 : opts.progress;
|
|
292
350
|
const isTerminalStatus = status !== "running";
|
|
293
351
|
const terminalProgressText = status === "deleted" ? "任务已取消(删除),记录已归档" : status === "cancelled" ? "任务已取消" : status === "stopped" ? "任务已停止(可恢复)" : status === "failed" ? "任务失败" : "任务已完成";
|
|
@@ -402,21 +460,45 @@ function buildWorkflowCard(opts) {
|
|
|
402
460
|
error: opts.error
|
|
403
461
|
});
|
|
404
462
|
if (infoLines.length > 0) {
|
|
405
|
-
elements.push({
|
|
406
|
-
|
|
407
|
-
|
|
463
|
+
elements.push(buildCollapsiblePanel({
|
|
464
|
+
title: "\uD83D\uDCCB 运行详情",
|
|
465
|
+
elementId: "workflow_detail",
|
|
466
|
+
elements: [{ tag: "markdown", content: infoLines.join(`
|
|
467
|
+
`) }]
|
|
468
|
+
}));
|
|
469
|
+
appendHr(elements);
|
|
470
|
+
}
|
|
471
|
+
const timelineElements = [];
|
|
472
|
+
if (milestones.length > 0) {
|
|
473
|
+
timelineElements.push({ tag: "markdown", content: `## \uD83C\uDFAF 里程碑序列` });
|
|
474
|
+
timelineElements.push({
|
|
475
|
+
tag: "markdown",
|
|
476
|
+
content: renderMilestones(milestones)
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
if (processSteps.length > 0) {
|
|
480
|
+
if (timelineElements.length > 0)
|
|
481
|
+
timelineElements.push({ tag: "hr" });
|
|
482
|
+
timelineElements.push({ tag: "markdown", content: `## \uD83D\uDD27 过程信息` });
|
|
483
|
+
timelineElements.push({
|
|
484
|
+
tag: "markdown",
|
|
485
|
+
content: renderProcessSteps(processSteps)
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
if (timelineElements.length > 0) {
|
|
489
|
+
elements.push(buildCollapsiblePanel({
|
|
490
|
+
title: `⏱️ 执行动态(${milestones.length} 里程碑 / ${processSteps.length} 过程)`,
|
|
491
|
+
elementId: "workflow_timeline",
|
|
492
|
+
expanded: opts.expandTimeline ?? isTerminalStatusForWorkflowTimeline(status),
|
|
493
|
+
elements: timelineElements
|
|
494
|
+
}));
|
|
408
495
|
}
|
|
409
|
-
elements.push({ tag: "markdown", content: `## \uD83C\uDFAF 里程碑序列` });
|
|
410
|
-
elements.push({ tag: "markdown", content: renderMilestones(milestones) });
|
|
411
|
-
elements.push({ tag: "hr" });
|
|
412
|
-
elements.push({ tag: "markdown", content: `## \uD83D\uDD27 过程信息` });
|
|
413
|
-
elements.push({ tag: "markdown", content: renderProcessSteps(processSteps) });
|
|
414
496
|
const effectiveProgress = status === "completed" ? 100 : deriveProgress({
|
|
415
497
|
completedNodes: opts.completedNodes,
|
|
416
498
|
totalNodes: opts.totalNodes,
|
|
417
499
|
progress: opts.progress
|
|
418
500
|
});
|
|
419
|
-
elements
|
|
501
|
+
appendHr(elements);
|
|
420
502
|
elements.push({
|
|
421
503
|
tag: "markdown",
|
|
422
504
|
content: effectiveProgress !== undefined ? `**\uD83D\uDCCA 进度**:${renderProgressBar(effectiveProgress)}` : `**\uD83D\uDCCA 进度**:进行中(第 ${updateCount} 次更新,尚未上报百分比)`
|
|
@@ -598,7 +680,8 @@ class LarkCardPatchNotifier {
|
|
|
598
680
|
milestones: mergeUnique(state?.milestones ?? [], [pauseMilestone], milestoneKey),
|
|
599
681
|
processSteps: state?.processSteps ?? [],
|
|
600
682
|
updateCount,
|
|
601
|
-
spinner
|
|
683
|
+
spinner,
|
|
684
|
+
expandTimeline: opts.expandTimeline
|
|
602
685
|
});
|
|
603
686
|
await this.runLarkCli(this.buildPatchCardArgs({
|
|
604
687
|
messageId: opts.messageId,
|
|
@@ -653,7 +736,8 @@ class LarkCardPatchNotifier {
|
|
|
653
736
|
milestones: mergeUnique(state?.milestones ?? [], [finalMilestone], milestoneKey),
|
|
654
737
|
processSteps: state?.processSteps ?? [],
|
|
655
738
|
updateCount,
|
|
656
|
-
spinner
|
|
739
|
+
spinner,
|
|
740
|
+
expandTimeline: opts.expandTimeline
|
|
657
741
|
});
|
|
658
742
|
await this.runLarkCli(this.buildPatchCardArgs({
|
|
659
743
|
messageId: opts.messageId,
|
|
@@ -1167,4 +1251,4 @@ function sanitize(text) {
|
|
|
1167
1251
|
return `${trimmed.slice(0, 500)}…`;
|
|
1168
1252
|
}
|
|
1169
1253
|
|
|
1170
|
-
export { formatTimestampForDisplay, sanitizeInlineText, formatDateTimeForDisplay, renderProgressBar, resolveTaskTitleForDisplay, humanizeValue, renderTaskInfoLines, renderContextAsLines, renderMilestones, renderProcessSteps, buildTaskCard, buildChatAppLink, DEFAULT_APP_LINK_BASE, formatDurationMs, renderWorkflowInfoLines, buildWorkflowCard, LarkCardPatchNotifier };
|
|
1254
|
+
export { formatTimestampForDisplay, sanitizeInlineText, formatDateTimeForDisplay, renderProgressBar, resolveTaskTitleForDisplay, humanizeValue, isTerminalStatusForTimeline, isTerminalStatusForWorkflowTimeline, buildCollapsiblePanel, renderTaskInfoLines, renderContextAsLines, renderMilestones, renderProcessSteps, buildTaskCard, buildChatAppLink, DEFAULT_APP_LINK_BASE, formatDurationMs, renderWorkflowInfoLines, buildWorkflowCard, LarkCardPatchNotifier };
|