@ai-setting/roy-agent-core 1.7.53 → 1.7.55
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/index.js +3 -3
- package/dist/env/error-reply.d.ts +184 -0
- package/dist/env/event-source/event-source-handlers.d.ts +9 -23
- package/dist/env/event-source/index.js +6 -6
- package/dist/env/index.js +18 -18
- package/dist/env/llm/adapter-pi-ai.d.ts +147 -2
- package/dist/env/llm/adapter.d.ts +21 -1
- package/dist/env/llm/index.js +2 -2
- package/dist/env/llm/invoke.d.ts +41 -1
- package/dist/env/llm/llm.d.ts +25 -0
- package/dist/env/llm/reasoning-defense.d.ts +104 -0
- package/dist/env/llm/types.d.ts +26 -0
- package/dist/env/prompt/index.js +2 -2
- package/dist/env/prompt/prompts-index.d.ts +1 -1
- package/dist/env/session/index.js +4 -4
- package/dist/env/session/storage/index.js +3 -3
- package/dist/env/task/backend/index.js +0 -2
- package/dist/env/task/backend/types.d.ts +0 -11
- package/dist/env/task/delegate/index.js +2 -2
- package/dist/env/task/index.js +3 -3
- package/dist/env/task/plugins/card-chat-routing.d.ts +42 -89
- package/dist/env/task/plugins/index.js +4 -4
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +0 -51
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +14 -31
- package/dist/env/task/plugins/per-task-group-chat-plugin.d.ts +4 -4
- package/dist/env/workflow/engine/engine.d.ts +65 -0
- package/dist/env/workflow/engine/index.js +2 -2
- package/dist/env/workflow/index.js +9 -9
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/env/workflow/nodes/tool-node.d.ts +6 -0
- package/dist/env/workflow/plugins/index.js +2 -2
- package/dist/env/workflow/tools/index.js +6 -6
- package/dist/env/workflow/tools/workflow-validate-tool.d.ts +11 -2
- package/dist/env/workflow/types/run.d.ts +19 -0
- package/dist/env/workflow/utils/agent-session-metadata.d.ts +13 -0
- package/dist/env/workflow/utils/index.js +1 -1
- package/dist/env/workflow/utils/redact-command-secrets.d.ts +70 -0
- package/dist/env/workflow/utils/shell-dialect-lint.d.ts +75 -0
- package/dist/env/workflow/utils/validate-workflow-definition.d.ts +22 -0
- package/dist/index.js +20 -20
- package/dist/shared/@ai-setting/{roy-agent-core-stnddvx9.js → roy-agent-core-12d2xap8.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-pk1b3kvf.js → roy-agent-core-2b8jtv7m.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-x8n1r7h4.js → roy-agent-core-2bscfrr1.js} +188 -7
- package/dist/shared/@ai-setting/{roy-agent-core-gdsqp6j8.js → roy-agent-core-6masakz4.js} +45 -0
- package/dist/shared/@ai-setting/{roy-agent-core-vvxb9522.js → roy-agent-core-6qxh4xrm.js} +67 -6
- package/dist/shared/@ai-setting/{roy-agent-core-h93v6p6y.js → roy-agent-core-7qy3nffr.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-4vpk40ss.js → roy-agent-core-8eqngasy.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-brwzs8wf.js → roy-agent-core-9h72sk1n.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-na73mym1.js → roy-agent-core-a4vzsn0g.js} +212 -1
- package/dist/shared/@ai-setting/{roy-agent-core-35s1w7tc.js → roy-agent-core-aer5kw1j.js} +142 -70
- package/dist/shared/@ai-setting/{roy-agent-core-j8e92gj8.js → roy-agent-core-b5ew8t0k.js} +0 -59
- package/dist/shared/@ai-setting/{roy-agent-core-4sx6sdb2.js → roy-agent-core-cd62e9p1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-39xejr39.js → roy-agent-core-e2z1etk4.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-hch2geta.js → roy-agent-core-g36jevrk.js} +14 -183
- package/dist/shared/@ai-setting/{roy-agent-core-ph5qbqcx.js → roy-agent-core-j2nvedt6.js} +465 -128
- package/dist/shared/@ai-setting/{roy-agent-core-p2r27era.js → roy-agent-core-mxdc756a.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-p8ak03s0.js → roy-agent-core-w527pcpe.js} +293 -42
- package/dist/shared/@ai-setting/{roy-agent-core-3tv1q6f2.js → roy-agent-core-ytr2w0vb.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-yd21n6c7.js → roy-agent-core-zvemdfx5.js} +1 -1
- package/dist/test-utils/child-process-mock.d.ts +73 -0
- package/package.json +2 -2
- /package/dist/shared/@ai-setting/{roy-agent-core-zy3hqfwg.js → roy-agent-core-0hq21px2.js} +0 -0
|
@@ -1,72 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview 任务卡片「该发到哪个群」的路由决策(Task #4230
|
|
2
|
+
* @fileoverview 任务卡片「该发到哪个群」的路由决策(Task #4230 / #4394)
|
|
3
3
|
*
|
|
4
|
-
* ##
|
|
4
|
+
* ## 现行规则(用户 2026-10-20 明令,Task #4394)
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* 根因链:
|
|
8
|
-
* 1. 触发消息来自 `oc_d083fc…`(= **task #3999 的跟进群**);
|
|
9
|
-
* 2. `LarkCliTaskNotifyHook` 的 `replyChannel.chatId` 优先(Task #4220 修复:
|
|
10
|
-
* 让 user 在触发群看到卡片)→ 卡片落到 `oc_d083fc…`;
|
|
11
|
-
* 3. #4226 是 sub-task(parent #2066),`PerTaskGroupChatPlugin` 默认跳过建群
|
|
12
|
-
* → #4226 从来没有自己的群。
|
|
6
|
+
* > 去掉专属群卡片逻辑,只保留**触发群的进度卡片**(可用户点击建群)
|
|
13
7
|
*
|
|
14
|
-
*
|
|
8
|
+
* 决策优先级:
|
|
9
|
+
* 1. **有触发群 → 就用触发群**。无条件,不判断它是不是"别的 task 的专属群"。
|
|
10
|
+
* 2. 没有触发群 → 用本 task(其次最近祖先)自己已有的专属群兜底(卡片不能丢)。
|
|
11
|
+
* 3. 两者都没有 → `none`(调用方静默 skip)。
|
|
15
12
|
*
|
|
16
|
-
* ##
|
|
13
|
+
* ## 已删除的历史逻辑(Task #4394)
|
|
17
14
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* - 改投时在触发群补一条**链接卡片**(不是普通消息),让 user 知道卡片去哪了
|
|
15
|
+
* 旧实现(Task #4230)会在"触发群被判定为别的 task 的专属群"时把卡片**改投**到
|
|
16
|
+
* 本 task / 祖先的 lineage 群,并在触发群补一张「📂 任务卡片已改投专属群 /
|
|
17
|
+
* 这里不是本任务的群,进展请看专属群」的指路卡。
|
|
22
18
|
*
|
|
23
|
-
*
|
|
19
|
+
* 用户实测(Task #4393)该行为是干扰:
|
|
20
|
+
* ```
|
|
21
|
+
* 触发群 oc_8947d9e2…(task 4377 的专属群)
|
|
22
|
+
* → 卡片被改投到 oc_d27157ac…(lineage 群)
|
|
23
|
+
* → 用户在触发群只看到一张"这里不是本任务的群"的灰卡
|
|
24
|
+
* ```
|
|
25
|
+
* 用户的诉求是「在哪聊就在哪看到进展」。**跨任务污染不再是需要解决的问题**,
|
|
26
|
+
* 因此整套「专属群归属判定 + 改投 + 指路卡」链路已彻底删除:
|
|
27
|
+
* - 删除 `ChatOwnership` / `mergeChatOwnership` / `analyzeContextOwnership`
|
|
28
|
+
* - 删除 `CardChatDecision.reroutedFrom`
|
|
29
|
+
* - 删除 `new-group` / `fallback-to-trigger` 两种 source(不再自动建群)
|
|
24
30
|
*
|
|
25
|
-
*
|
|
26
|
-
* - `larkPerTaskChatId`:task.context 里插件写入的专属群字段
|
|
27
|
-
* - `followup_chat`:`*followup_chat_id` / `*_group_chat_id` 之类字段(老任务手工建的跟进群)
|
|
28
|
-
* - `chat-name`:群名里的 `Task 3999` / `#3999` 模式(对没留字段的手工群兜底)
|
|
31
|
+
* ## 建群能力仍在(**用户主动点击**才建)
|
|
29
32
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
+
* 卡片顶部按钮 `create_group` / `disband_group` 由
|
|
34
|
+
* `lark-card-action-handler.ts` 处理,与本文档的路由决策**完全解耦**:
|
|
35
|
+
* ```
|
|
36
|
+
* 用户点「为这个任务建群」
|
|
37
|
+
* → card.action.trigger 事件
|
|
38
|
+
* → handleCardAction → ports.createGroupChat (lark-cli im +chat-create)
|
|
39
|
+
* → 回写 task.context.larkPerTaskChatId
|
|
40
|
+
* → patch 卡片(按钮翻成「解散该群」+ 出现「进入专属群」链接)
|
|
41
|
+
* ```
|
|
42
|
+
* 建群后下一张进度卡会走本文件的优先级 1(仍进触发群),
|
|
43
|
+
* 但卡片上多了「进入专属群」链接 —— 这是用户可选的入口,不是自动改投。
|
|
33
44
|
*
|
|
34
|
-
* 本模块是**纯函数**(不碰 IO
|
|
35
|
-
* (EventSource handler)注入,便于单测覆盖所有分支。
|
|
45
|
+
* 本模块是**纯函数**(不碰 IO),便于单测覆盖所有分支。
|
|
36
46
|
*/
|
|
37
47
|
/** 群名里隐含的 task id("Task 3999 - xxx" / "#3999 TMO 提取跟进") */
|
|
38
48
|
export declare const GROUP_NAME_TASK_ID_RE: RegExp;
|
|
39
49
|
/** 会把 chatId 记进 context 的字段名(用于 DB LIKE 反查) */
|
|
40
50
|
export declare const CTX_FIELD_LARK_PER_TASK_CHAT_ID = "larkPerTaskChatId";
|
|
41
|
-
|
|
42
|
-
export interface ChatOwnership {
|
|
43
|
-
chatId: string;
|
|
44
|
-
/**
|
|
45
|
-
* 该群归属的 task id(可能多个:历史脏数据 / 多个 task 共用过一个群)
|
|
46
|
-
*
|
|
47
|
-
* 空数组 = 没有证据表明它是任何 task 的专属群。
|
|
48
|
-
*/
|
|
49
|
-
ownerTaskIds: number[];
|
|
50
|
-
/** 证据来源(诊断用):chat-binding / larkPerTaskChatId / followup_chat_id / chat-name */
|
|
51
|
-
sources: string[];
|
|
52
|
-
/** 群名(DB 记录或实时查询;可能没有) */
|
|
53
|
-
chatName?: string;
|
|
54
|
-
/** 是否被判为"专属群"(至少有一条**专属**证据) */
|
|
55
|
-
dedicated: boolean;
|
|
56
|
-
}
|
|
57
|
-
export type CardChatSource = "trigger-chat" | "own-group" | "ancestor-group" | "new-group" | "fallback-to-trigger" | "none";
|
|
51
|
+
export type CardChatSource = "trigger-chat" | "own-group" | "ancestor-group" | "none";
|
|
58
52
|
export interface CardChatDecision {
|
|
59
53
|
chatId?: string;
|
|
60
54
|
profile?: string;
|
|
61
|
-
/**
|
|
55
|
+
/** 目标群名(诊断用) */
|
|
62
56
|
chatName?: string;
|
|
63
57
|
source: CardChatSource;
|
|
64
|
-
/** 因触发群是"别 task 的专属群"而改投时记录(用于回补链接卡片) */
|
|
65
|
-
reroutedFrom?: {
|
|
66
|
-
chatId: string;
|
|
67
|
-
ownerTaskIds: number[];
|
|
68
|
-
sources: string[];
|
|
69
|
-
};
|
|
70
58
|
/** 人类可读的决策原因(写进 span / debug 日志) */
|
|
71
59
|
reason: string;
|
|
72
60
|
}
|
|
@@ -79,41 +67,17 @@ export declare function extractPerTaskChatProfile(contextStr?: string): string |
|
|
|
79
67
|
/** 从 task.context JSON 解析记录下来的群名(含 `#3999` / `Task 3999` 模式) */
|
|
80
68
|
export declare function extractRecordedChatNames(contextStr?: string): string[];
|
|
81
69
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* 只认**专属**信号;`feishu_chat_id` / `chat_id` 这类会话群字段会被忽略
|
|
85
|
-
* (否则会把普通会话群误判成专属群)。
|
|
86
|
-
*/
|
|
87
|
-
export declare function analyzeContextOwnership(contextStr: string | undefined, chatId: string): {
|
|
88
|
-
owned: boolean;
|
|
89
|
-
sources: string[];
|
|
90
|
-
impliedTaskIds: number[];
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* 由多个 task(DB 反查命中)的 context 汇总出 `ChatOwnership`
|
|
70
|
+
* 决定卡片该发到哪个群(Task #4394 简化版)
|
|
94
71
|
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*/
|
|
99
|
-
export declare function mergeChatOwnership(chatId: string, candidates: Array<{
|
|
100
|
-
id: number;
|
|
101
|
-
context?: string;
|
|
102
|
-
}>, extra?: {
|
|
103
|
-
boundTaskId?: number | null;
|
|
104
|
-
/** 该群的真实群名(若调用方查到了) */
|
|
105
|
-
chatName?: string;
|
|
106
|
-
}): ChatOwnership;
|
|
107
|
-
/**
|
|
108
|
-
* 决定卡片该发到哪个群
|
|
72
|
+
* 规则只有两条:
|
|
73
|
+
* 1. **有触发群 → 触发群**(无条件,不做任何"是不是别人的群"判定)
|
|
74
|
+
* 2. 没触发群 → 用本 task / 祖先已有的专属群兜底
|
|
109
75
|
*
|
|
110
|
-
* @param input.lineageIds 本 task 的 lineage(自己 + 所有祖先)task id
|
|
111
76
|
* @param input.lineageChat lineage 上找到的专属群(自己优先,其次最近祖先)
|
|
112
|
-
* @param input.triggerOwnership 触发群的归属分析(未做分析时传 undefined)
|
|
113
77
|
*/
|
|
114
78
|
export declare function decideCardChatTarget(input: {
|
|
115
79
|
taskId?: number;
|
|
116
|
-
lineageIds
|
|
80
|
+
lineageIds?: number[];
|
|
117
81
|
lineageChat?: {
|
|
118
82
|
chatId: string;
|
|
119
83
|
profile?: string;
|
|
@@ -121,15 +85,4 @@ export declare function decideCardChatTarget(input: {
|
|
|
121
85
|
};
|
|
122
86
|
triggerChatId?: string;
|
|
123
87
|
triggerProfile?: string;
|
|
124
|
-
triggerOwnership?: ChatOwnership;
|
|
125
|
-
/**
|
|
126
|
-
* ★ Task #4331:是否允许"new-group"路径(即触发群是别人的群 + 本 task 无群时建专属群)
|
|
127
|
-
*
|
|
128
|
-
* 默认 false(用户新要求:默认不建群)
|
|
129
|
-
* - true:保留 #4230 的老行为(建专属群),用于向后兼容显式开启的场景
|
|
130
|
-
* - false:触发群是别人的群 + 本 task 无群 → 退回触发群(不建群)
|
|
131
|
-
*
|
|
132
|
-
* 不影响其他 source(trigger-chat / own-group / ancestor-group / none)的决策。
|
|
133
|
-
*/
|
|
134
|
-
allowNewGroup?: boolean;
|
|
135
88
|
}): CardChatDecision;
|
|
@@ -10,12 +10,12 @@ import {
|
|
|
10
10
|
formatExtractorInput,
|
|
11
11
|
formatExtractorInputFromDescription,
|
|
12
12
|
parseExtractorOutput
|
|
13
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
13
|
+
} from "../../../shared/@ai-setting/roy-agent-core-g36jevrk.js";
|
|
14
14
|
import"../../../shared/@ai-setting/roy-agent-core-yhsssn86.js";
|
|
15
15
|
import"../../../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
16
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
17
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
18
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
16
|
+
import"../../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
17
|
+
import"../../../shared/@ai-setting/roy-agent-core-b5ew8t0k.js";
|
|
18
|
+
import"../../../shared/@ai-setting/roy-agent-core-a4vzsn0g.js";
|
|
19
19
|
import"../../../shared/@ai-setting/roy-agent-core-8s9jd2qy.js";
|
|
20
20
|
import"../../../shared/@ai-setting/roy-agent-core-jrj30vq3.js";
|
|
21
21
|
import"../../../shared/@ai-setting/roy-agent-core-dv714bqh.js";
|
|
@@ -173,21 +173,6 @@ export interface FinishTaskOptions {
|
|
|
173
173
|
finalStep?: string;
|
|
174
174
|
progress?: number;
|
|
175
175
|
}
|
|
176
|
-
/** 改投链接卡片的入参(Task #4230 follow-up) */
|
|
177
|
-
export interface RedirectNoticeOptions {
|
|
178
|
-
/** 发到哪个群(通常是"触发群",即被判定为别 task 专属群的那个) */
|
|
179
|
-
chatId: string;
|
|
180
|
-
profile?: string;
|
|
181
|
-
/** 本 task */
|
|
182
|
-
taskId?: number | string;
|
|
183
|
-
taskTitle?: string;
|
|
184
|
-
/** 卡片实际落在哪个群 */
|
|
185
|
-
targetChatId: string;
|
|
186
|
-
/** 目标群名(渲染成可点击文本;缺省显示"专属群") */
|
|
187
|
-
targetChatName?: string;
|
|
188
|
-
/** 改投原因(诊断,写进卡片文案) */
|
|
189
|
-
reason?: string;
|
|
190
|
-
}
|
|
191
176
|
export interface StartTaskResult {
|
|
192
177
|
messageId: string;
|
|
193
178
|
/** pin 是否成功(失败不影响卡片可见性,但 trace 里可查) */
|
|
@@ -418,24 +403,6 @@ export declare function buildTaskCard(opts: {
|
|
|
418
403
|
export declare function buildChatAppLink(chatId: string, base?: string): string;
|
|
419
404
|
/** 默认 applink 基址(飞书) */
|
|
420
405
|
export declare const DEFAULT_APP_LINK_BASE = "https://applink.feishu.cn";
|
|
421
|
-
/**
|
|
422
|
-
* 构造"卡片已改投专属群"的链接卡片(Task #4230 follow-up)
|
|
423
|
-
*
|
|
424
|
-
* 为什么是卡片而不是普通消息:
|
|
425
|
-
* - 用户明确要求「旧逻辑的普通消息通知不要」;
|
|
426
|
-
* - 改投后触发群里需要一条**可点击**的入口,否则 user 不知道进展卡片去哪了。
|
|
427
|
-
*
|
|
428
|
-
* 注意:这张卡片**不携带任务进展内容**,只是一条"去哪看"的指路牌,避免把
|
|
429
|
-
* 别的 task 的进展细节塞进不属于它的群。
|
|
430
|
-
*/
|
|
431
|
-
export declare function buildRedirectCard(opts: {
|
|
432
|
-
taskId?: number | string;
|
|
433
|
-
taskTitle?: string;
|
|
434
|
-
targetChatId: string;
|
|
435
|
-
/** 目标群名(渲染成可点击文本;缺省显示"专属群") */
|
|
436
|
-
targetChatName?: string;
|
|
437
|
-
reason?: string;
|
|
438
|
-
}): CardPayload;
|
|
439
406
|
/**
|
|
440
407
|
* 格式化耗时为人类可读文本(毫秒 → ms / s / m)
|
|
441
408
|
*
|
|
@@ -496,14 +463,6 @@ export declare class LarkCardPatchNotifier {
|
|
|
496
463
|
* unpin 基础设施,只是渲染的卡片与自持的时间线不同。
|
|
497
464
|
*/
|
|
498
465
|
private readonly workflowStates;
|
|
499
|
-
/**
|
|
500
|
-
* ★ Task #4237 修复:改投链接卡片幂等表
|
|
501
|
-
*
|
|
502
|
-
* key = `${taskId}:${targetChatId}`;同一 (task, 目标群) 只允许发一张
|
|
503
|
-
* 「任务卡片已改投专属群」卡片 —— 旧实现里两条决策路径各发一次,
|
|
504
|
-
* 触发群收到两张文案不同的改投卡片。
|
|
505
|
-
*/
|
|
506
|
-
private readonly redirectsSent;
|
|
507
466
|
constructor(options?: LarkCardPatchNotifierOptions);
|
|
508
467
|
/** 取(或创建)某 messageId 的 mutex —— 不同卡片互不阻塞 */
|
|
509
468
|
private mutexFor;
|
|
@@ -514,16 +473,6 @@ export declare class LarkCardPatchNotifier {
|
|
|
514
473
|
* `--chat-id/--message-id` 是非法 flag,导致 pin 永远失败 → 用户"还是没有 pin")。
|
|
515
474
|
*/
|
|
516
475
|
startTask(opts: StartTaskOptions): Promise<StartTaskResult>;
|
|
517
|
-
/**
|
|
518
|
-
* 在"触发群"发一条**链接卡片**,告知任务进展卡片已改投本 task 的专属群
|
|
519
|
-
*
|
|
520
|
-
* Task #4230 follow-up:当触发群被判定为"别的 task 的专属群"时,卡片不会
|
|
521
|
-
* 再落在触发群(避免跨任务污染),但 user 需要知道去哪里看 → 这里补一张
|
|
522
|
-
* 不含任务进展内容的指路卡片。
|
|
523
|
-
*
|
|
524
|
-
* 失败非致命(触发群里发不出去不影响主流程)。
|
|
525
|
-
*/
|
|
526
|
-
sendRedirectNotice(opts: RedirectNoticeOptions): Promise<boolean>;
|
|
527
476
|
/**
|
|
528
477
|
* Patch 同一卡片(状态/进度/当前步骤 + 累积里程碑与过程时间线)
|
|
529
478
|
*
|
|
@@ -23,10 +23,8 @@
|
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
25
|
import type { Hook, HookContext } from "../../hook/types";
|
|
26
|
-
import type { Task } from "../types";
|
|
27
26
|
import { getEnvContextOrEmpty } from "../../context";
|
|
28
27
|
import { LarkCardPatchNotifier } from "./lark-card-patch-notifier";
|
|
29
|
-
import { type ChatOwnership } from "./card-chat-routing";
|
|
30
28
|
/**
|
|
31
29
|
* 从 EnvContext 提取 lark 专属字段
|
|
32
30
|
*
|
|
@@ -82,16 +80,6 @@ export interface TaskNotifyConfig {
|
|
|
82
80
|
* 不传 → plugin 自己 new 一个(messageId 由 plugin 的 Map 跟踪)。
|
|
83
81
|
*/
|
|
84
82
|
cardNotifier?: LarkCardPatchNotifier;
|
|
85
|
-
/**
|
|
86
|
-
* ★ Task #4331:是否允许路由决策走"new-group"路径(建专属群)
|
|
87
|
-
*
|
|
88
|
-
* 默认 false:触发群是别人的群 + 本 task 无群时,**不**建专属群,退回触发群
|
|
89
|
-
* 适用:默认行为(用户新要求:默认不建群)
|
|
90
|
-
*
|
|
91
|
-
* 设为 true:保留 #4230 老行为(建专属群并改投)
|
|
92
|
-
* 适用:显式开启(向后兼容)
|
|
93
|
-
*/
|
|
94
|
-
allowNewGroup?: boolean;
|
|
95
83
|
}
|
|
96
84
|
/**
|
|
97
85
|
* 卡片路由端口(Task #4230 follow-up)
|
|
@@ -101,25 +89,16 @@ export interface TaskNotifyConfig {
|
|
|
101
89
|
*/
|
|
102
90
|
export interface CardRoutingPorts {
|
|
103
91
|
/**
|
|
104
|
-
*
|
|
92
|
+
* task 查询(lineage 上溯:无触发群时找本 task / 祖先的专属群兜底)
|
|
105
93
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* -
|
|
109
|
-
* - 群名 "Task 3999" / "#3999"(DB 记录的群名,必要时实时查)
|
|
94
|
+
* ★ Task #4394:`lookupChatOwnership` / `ensureTaskGroupChat` 两个端口已删除
|
|
95
|
+
* —— 卡片不再做"触发群是不是别 task 专属群"的判定,也不再自动建群。
|
|
96
|
+
* 建群改由用户在卡片上点「为这个任务建群」按钮触发(见 lark-card-action-handler.ts)。
|
|
110
97
|
*/
|
|
111
|
-
lookupChatOwnership?: (chatId: string) => Promise<ChatOwnership | undefined>;
|
|
112
|
-
/** task 查询(lineage 上溯) */
|
|
113
98
|
getTask?: (id: number) => Promise<{
|
|
114
99
|
context?: string;
|
|
115
100
|
parent_task_id?: number | null;
|
|
116
101
|
} | undefined>;
|
|
117
|
-
/** 为 task 建/取专属群(lineage 无群且触发群是别人的群时用) */
|
|
118
|
-
ensureTaskGroupChat?: (task: Task) => Promise<{
|
|
119
|
-
chatId: string;
|
|
120
|
-
profile?: string;
|
|
121
|
-
name?: string;
|
|
122
|
-
} | undefined>;
|
|
123
102
|
}
|
|
124
103
|
export declare class LarkCliTaskNotifyHook implements Hook {
|
|
125
104
|
readonly name: string;
|
|
@@ -156,8 +135,8 @@ export declare class LarkCliTaskNotifyHook implements Hook {
|
|
|
156
135
|
*
|
|
157
136
|
* 根因:`sendCardStart` 里 `ensureTaskGroupChat` 会写 task.context → 同步触发
|
|
158
137
|
* `task:after.update` → 本 hook 重入 `sendCardUpdate`;此时首卡 messageId 还没写进
|
|
159
|
-
* `cardMessageIds` → 触发 fallback
|
|
160
|
-
*
|
|
138
|
+
* `cardMessageIds` → 触发 fallback 补一张重复卡(同一 task 多张卡)。
|
|
139
|
+
* (Task #4394 已删除"再发一张改投卡片"那条路径,哨兵仍用于防重复补卡。)
|
|
161
140
|
*
|
|
162
141
|
* 修法:进入 `sendCardStart` 前先占位;重入的 update 看到哨兵直接跳过。
|
|
163
142
|
*/
|
|
@@ -189,16 +168,20 @@ export declare class LarkCliTaskNotifyHook implements Hook {
|
|
|
189
168
|
/**
|
|
190
169
|
* 解析「卡片该发到哪个群」(Task #4230 follow-up)
|
|
191
170
|
*
|
|
192
|
-
* 规则见 card-chat-routing.ts
|
|
193
|
-
*
|
|
171
|
+
* 规则见 card-chat-routing.ts(Task #4394 简化版):
|
|
172
|
+
* - **有触发群 → 就用触发群**(无条件,不改投)
|
|
173
|
+
* - 没有触发群 → 用本 task(或祖先)已有的专属群兜底
|
|
174
|
+
* - 都没有 → none(caller skip)
|
|
175
|
+
*
|
|
176
|
+
* 已经不再"自动建群"——建群由用户在卡片上点按钮触发。
|
|
194
177
|
*
|
|
195
|
-
* @returns decision
|
|
178
|
+
* @returns decision(chatId / profile / source / reason)
|
|
196
179
|
*/
|
|
197
180
|
private resolveCardTarget;
|
|
198
181
|
/**
|
|
199
182
|
* 收集 task 的 lineage(自己 → 父 → 祖父…,最多 10 层)
|
|
200
183
|
*
|
|
201
|
-
*
|
|
184
|
+
* 用于:无触发群时找最近的专属群兜底(Task #4394:不再用于"是否别人的群"判定)。
|
|
202
185
|
*/
|
|
203
186
|
private collectLineage;
|
|
204
187
|
/** 发初始卡片(+ pin)并缓存 messageId */
|
|
@@ -193,10 +193,10 @@ export interface PerTaskGroupConfig {
|
|
|
193
193
|
* - 用户在卡片顶部点"为这个任务建群"按钮 → 走 ensureGroupChat 按需建群
|
|
194
194
|
* - 适用:减少群聊爆炸 / 集中讨论 / 减少噪音
|
|
195
195
|
*
|
|
196
|
-
* ★
|
|
197
|
-
* -
|
|
198
|
-
*
|
|
199
|
-
*
|
|
196
|
+
* ★ Task #4394:`LarkCliTaskNotifyPlugin.cardRoutingPorts.ensureTaskGroupChat`
|
|
197
|
+
* 及其 `new-group` / `fallback-to-trigger` 两条 source 已删除 —— 卡片路由
|
|
198
|
+
* **不再自动建群**,`ensureGroupChat` 现在只剩一个调用方:用户点卡片上
|
|
199
|
+
* 「为这个任务建群」按钮(见 lark-card-action-handler.ts)。
|
|
200
200
|
*/
|
|
201
201
|
autoCreateGroup?: boolean;
|
|
202
202
|
/**
|
|
@@ -217,12 +217,61 @@ export declare class WorkflowEngine extends EventEmitter {
|
|
|
217
217
|
* Main scheduling loop
|
|
218
218
|
*/
|
|
219
219
|
private scheduleAndExecute;
|
|
220
|
+
/**
|
|
221
|
+
* Dispatch a node without waiting for it to finish (Task #4392 P0-1).
|
|
222
|
+
*
|
|
223
|
+
* Registers the node's promise in `sessionState.inFlight` **synchronously**
|
|
224
|
+
* so the scheduler loop can (a) join it and (b) never mistake "no tracked
|
|
225
|
+
* work" for "done". The returned promise is intentionally swallowed: node
|
|
226
|
+
* outcomes propagate through `scheduler.markFailed` and the `node.failed`
|
|
227
|
+
* event, exactly as they did when the dispatch path awaited them.
|
|
228
|
+
*
|
|
229
|
+
* ## Claim guard — why this is not just "call startNode"
|
|
230
|
+
*
|
|
231
|
+
* A node can be reachable from **two** dispatch paths:
|
|
232
|
+
* 1. `scheduleAvailableNodes()` → `scheduler.getReadyNodes()` (DAG readiness)
|
|
233
|
+
* 2. `processConditionalEdgesAfterCompletion()` → `edgeResult.toStart`
|
|
234
|
+
*
|
|
235
|
+
* Under the old serial loop this never mattered: path 2 awaited each target
|
|
236
|
+
* to completion, so path 1 always found them `completed` already. Once
|
|
237
|
+
* dispatch became concurrent the two paths race and the *same* node was
|
|
238
|
+
* executed twice (proven by `engine-parallel-scheduling.test.ts`:
|
|
239
|
+
* `parallelLimit=2` produced peak concurrency 3 with 4 of 6 leaves run twice).
|
|
240
|
+
*
|
|
241
|
+
* `scheduler.running` is the tie-breaker. `startNode` calls
|
|
242
|
+
* `scheduler.markStarted()` before its first `await`, so the claim is visible
|
|
243
|
+
* synchronously to the next dispatcher on the same tick — no interleaving
|
|
244
|
+
* window. Returns `true` only for the caller that actually won the claim.
|
|
245
|
+
*
|
|
246
|
+
* ⚠️ The guard deliberately keys off `scheduler.running` and **not** off
|
|
247
|
+
* `inFlight`, even though both look equivalent. A self-loop back-edge
|
|
248
|
+
* (`implement → implement`) re-dispatches the node *from inside its own
|
|
249
|
+
* completion handler*, i.e. while its own promise is still in `inFlight` but
|
|
250
|
+
* after `resetNodeForReEntry()` cleared `running`. Guarding on `inFlight`
|
|
251
|
+
* deadlocks exactly that case: the node waits for itself forever.
|
|
252
|
+
*/
|
|
253
|
+
private dispatchNode;
|
|
220
254
|
/**
|
|
221
255
|
* Wait for next node event
|
|
222
256
|
*
|
|
223
257
|
* Optimization: When there are running nodes, use pure event-driven waiting
|
|
224
258
|
* (no polling). When there are only pending nodes (dependencies not yet met),
|
|
225
259
|
* use a small timeout to re-check scheduling conditions.
|
|
260
|
+
*
|
|
261
|
+
* Task #4392 P0-1 — two additions that concurrent dispatch makes necessary:
|
|
262
|
+
*
|
|
263
|
+
* 1. **`inFlight` also arms the timeout.** `scheduler.running` is cleared by
|
|
264
|
+
* `markCompleted` inside `validateAndExecute`, but the node's promise is
|
|
265
|
+
* still settling (AFTER_NODE hook, conditional edges, `checkAndFinalize`).
|
|
266
|
+
* In that window `hasRunningNodes` is false while real work continues, so
|
|
267
|
+
* we must keep a wakeup source armed or the loop could park forever.
|
|
268
|
+
*
|
|
269
|
+
* 2. **`node.scheduled` resolves the wait.** Concurrent dispatch publishes
|
|
270
|
+
* `node.scheduled` for sibling nodes (and for loop re-entries) *after* this
|
|
271
|
+
* waiter subscribed — with `node.completed`/`node.failed` as the only
|
|
272
|
+
* trigger, a round whose completion event fired during the synchronous
|
|
273
|
+
* dispatch section would leave the loop blocked until the 100ms poll.
|
|
274
|
+
* Subscribing to `node.scheduled` closes that lost-wakeup window.
|
|
226
275
|
*/
|
|
227
276
|
private waitForNextNodeEvent;
|
|
228
277
|
/**
|
|
@@ -368,6 +417,22 @@ export declare class WorkflowEngine extends EventEmitter {
|
|
|
368
417
|
* Get session metadata
|
|
369
418
|
*/
|
|
370
419
|
private getSessionMetadata;
|
|
420
|
+
/**
|
|
421
|
+
* Serialized session-metadata read-modify-write (Task #4392 P0-1).
|
|
422
|
+
*
|
|
423
|
+
* Every `node.completed` / `node.failed` handler and every terminal-state
|
|
424
|
+
* transition mutates metadata via `get → spread → update`. That is safe only
|
|
425
|
+
* if mutations never interleave. Now that nodes are dispatched concurrently,
|
|
426
|
+
* two completions can both `await get()` the same snapshot and the later
|
|
427
|
+
* `update()` silently drops the other's `agentSessions` marker.
|
|
428
|
+
*
|
|
429
|
+
* `mutate` receives the freshly-read metadata and must return the next
|
|
430
|
+
* metadata object. Mutations are chained onto `sessionState.sessionMetadataQueue`
|
|
431
|
+
* so they apply in a strict total order, and the queue never rejects (a
|
|
432
|
+
* failed mutation is logged and skipped) so one bad update cannot poison
|
|
433
|
+
* every later write.
|
|
434
|
+
*/
|
|
435
|
+
private updateSessionMetadata;
|
|
371
436
|
/**
|
|
372
437
|
* Find workflow definition from repository
|
|
373
438
|
*/
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
Scheduler,
|
|
6
6
|
WorkflowEngine,
|
|
7
7
|
init_engine
|
|
8
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
8
|
+
} from "../../../shared/@ai-setting/roy-agent-core-aer5kw1j.js";
|
|
9
9
|
import"../../../shared/@ai-setting/roy-agent-core-6atd905e.js";
|
|
10
10
|
import"../../../shared/@ai-setting/roy-agent-core-6167phd4.js";
|
|
11
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
11
|
+
import"../../../shared/@ai-setting/roy-agent-core-2bscfrr1.js";
|
|
12
12
|
import"../../../shared/@ai-setting/roy-agent-core-1db4vpc6.js";
|
|
13
13
|
import"../../../shared/@ai-setting/roy-agent-core-ze068vc9.js";
|
|
14
14
|
import"../../../shared/@ai-setting/roy-agent-core-fs36xgcs.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WorkflowComponent
|
|
3
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
3
|
+
} from "../../shared/@ai-setting/roy-agent-core-8eqngasy.js";
|
|
4
4
|
import"../../shared/@ai-setting/roy-agent-core-vrsxhw9e.js";
|
|
5
5
|
import {
|
|
6
6
|
Edge,
|
|
@@ -14,21 +14,21 @@ import {
|
|
|
14
14
|
DecoratorNode,
|
|
15
15
|
init_decorator_node
|
|
16
16
|
} from "../../shared/@ai-setting/roy-agent-core-1ce3fqrk.js";
|
|
17
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
18
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
19
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
17
|
+
import"../../shared/@ai-setting/roy-agent-core-6qxh4xrm.js";
|
|
18
|
+
import"../../shared/@ai-setting/roy-agent-core-zvemdfx5.js";
|
|
19
|
+
import"../../shared/@ai-setting/roy-agent-core-7qy3nffr.js";
|
|
20
20
|
import"../../shared/@ai-setting/roy-agent-core-hhrg314p.js";
|
|
21
21
|
import"../../shared/@ai-setting/roy-agent-core-7evvpfwc.js";
|
|
22
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
22
|
+
import"../../shared/@ai-setting/roy-agent-core-aer5kw1j.js";
|
|
23
23
|
import"../../shared/@ai-setting/roy-agent-core-6atd905e.js";
|
|
24
24
|
import"../../shared/@ai-setting/roy-agent-core-6167phd4.js";
|
|
25
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
25
|
+
import"../../shared/@ai-setting/roy-agent-core-2bscfrr1.js";
|
|
26
26
|
import"../../shared/@ai-setting/roy-agent-core-1db4vpc6.js";
|
|
27
27
|
import"../../shared/@ai-setting/roy-agent-core-ze068vc9.js";
|
|
28
28
|
import"../../shared/@ai-setting/roy-agent-core-fs36xgcs.js";
|
|
29
29
|
import"../../shared/@ai-setting/roy-agent-core-9csa89jx.js";
|
|
30
30
|
import"../../shared/@ai-setting/roy-agent-core-7exqwax1.js";
|
|
31
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
31
|
+
import"../../shared/@ai-setting/roy-agent-core-a4vzsn0g.js";
|
|
32
32
|
import"../../shared/@ai-setting/roy-agent-core-tjg71zqp.js";
|
|
33
33
|
import"../../shared/@ai-setting/roy-agent-core-ddwa0n6h.js";
|
|
34
34
|
import"../../shared/@ai-setting/roy-agent-core-8s9jd2qy.js";
|
|
@@ -85,8 +85,8 @@ import {
|
|
|
85
85
|
unresolvedVariable
|
|
86
86
|
} from "../../shared/@ai-setting/roy-agent-core-jrj30vq3.js";
|
|
87
87
|
import"../../shared/@ai-setting/roy-agent-core-rvxg1wps.js";
|
|
88
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
89
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
88
|
+
import"../../shared/@ai-setting/roy-agent-core-2b8jtv7m.js";
|
|
89
|
+
import"../../shared/@ai-setting/roy-agent-core-0hq21px2.js";
|
|
90
90
|
import"../../shared/@ai-setting/roy-agent-core-c1v263jn.js";
|
|
91
91
|
import {
|
|
92
92
|
AskUserError,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
init_skill_node,
|
|
8
8
|
init_tool_node,
|
|
9
9
|
init_workflow_node
|
|
10
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
10
|
+
} from "../../../shared/@ai-setting/roy-agent-core-2bscfrr1.js";
|
|
11
11
|
import"../../../shared/@ai-setting/roy-agent-core-dsevjbck.js";
|
|
12
12
|
import"../../../shared/@ai-setting/roy-agent-core-8seq65bp.js";
|
|
13
13
|
import"../../../shared/@ai-setting/roy-agent-core-jnszp0jq.js";
|
|
@@ -52,6 +52,12 @@ export declare class ToolNode implements Node {
|
|
|
52
52
|
* - value is not an object
|
|
53
53
|
* - success === true (or success field is missing)
|
|
54
54
|
* - wrapper has no error string
|
|
55
|
+
*
|
|
56
|
+
* Task #4392 P0-2: when the wrapper signals a non-zero `exit_code` but carries
|
|
57
|
+
* no stderr, the bare `Tool exited with code N` message is useless on its own
|
|
58
|
+
* (#4385 measured 27 such `exit 2` occurrences in the creator sessions, and
|
|
59
|
+
* 291 failed runs whose `session.metadata.error` was null). We therefore append
|
|
60
|
+
* the (redacted, single-line, truncated) command plus a stdout tail.
|
|
55
61
|
*/
|
|
56
62
|
private extractErrorFromWrapper;
|
|
57
63
|
}
|
|
@@ -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-9h72sk1n.js";
|
|
5
|
+
import"../../../shared/@ai-setting/roy-agent-core-b5ew8t0k.js";
|
|
6
6
|
import"../../../shared/@ai-setting/roy-agent-core-9csa89jx.js";
|
|
7
7
|
import"../../../shared/@ai-setting/roy-agent-core-qcspfszy.js";
|
|
8
8
|
import"../../../shared/@ai-setting/roy-agent-core-4z3rq5gw.js";
|
|
@@ -24,9 +24,9 @@ import {
|
|
|
24
24
|
getRunWorkflowTool,
|
|
25
25
|
initRunWorkflowTool,
|
|
26
26
|
resetRunWorkflowTool
|
|
27
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
28
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
29
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
27
|
+
} from "../../../shared/@ai-setting/roy-agent-core-6qxh4xrm.js";
|
|
28
|
+
import"../../../shared/@ai-setting/roy-agent-core-zvemdfx5.js";
|
|
29
|
+
import"../../../shared/@ai-setting/roy-agent-core-7qy3nffr.js";
|
|
30
30
|
import"../../../shared/@ai-setting/roy-agent-core-7evvpfwc.js";
|
|
31
31
|
import {
|
|
32
32
|
WORKFLOW_SUBMIT_OUTPUT_TOOL_NAME,
|
|
@@ -37,12 +37,12 @@ import {
|
|
|
37
37
|
} from "../../../shared/@ai-setting/roy-agent-core-1db4vpc6.js";
|
|
38
38
|
import"../../../shared/@ai-setting/roy-agent-core-ze068vc9.js";
|
|
39
39
|
import"../../../shared/@ai-setting/roy-agent-core-7exqwax1.js";
|
|
40
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
40
|
+
import"../../../shared/@ai-setting/roy-agent-core-a4vzsn0g.js";
|
|
41
41
|
import"../../../shared/@ai-setting/roy-agent-core-8s9jd2qy.js";
|
|
42
42
|
import"../../../shared/@ai-setting/roy-agent-core-jrj30vq3.js";
|
|
43
43
|
import"../../../shared/@ai-setting/roy-agent-core-rvxg1wps.js";
|
|
44
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
45
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
44
|
+
import"../../../shared/@ai-setting/roy-agent-core-2b8jtv7m.js";
|
|
45
|
+
import"../../../shared/@ai-setting/roy-agent-core-0hq21px2.js";
|
|
46
46
|
import"../../../shared/@ai-setting/roy-agent-core-c1v263jn.js";
|
|
47
47
|
import"../../../shared/@ai-setting/roy-agent-core-e25xkv53.js";
|
|
48
48
|
import"../../../shared/@ai-setting/roy-agent-core-7hh0brvs.js";
|
|
@@ -34,18 +34,27 @@ import type { WorkflowService } from "../service/workflow-service";
|
|
|
34
34
|
/**
|
|
35
35
|
* Input schema for workflow_validate tool.
|
|
36
36
|
*
|
|
37
|
-
* Accepts
|
|
38
|
-
*
|
|
37
|
+
* Accepts `file` (path), `yaml`/`definition_yaml` (string) or `definition`
|
|
38
|
+
* (object). Precedence: `definition` > `file` > `yaml` / `definition_yaml`.
|
|
39
|
+
*
|
|
40
|
+
* Task #4392 P0-4: `file` was added because the tool performs **no shell
|
|
41
|
+
* expansion**, yet LLMs kept passing `yaml: "$(cat /tmp/x.yaml)"`. That string
|
|
42
|
+
* is literal, YAML.parse returns a *string*, and the tool replied
|
|
43
|
+
* `Parsed definition is not an object` — 30 of the 31 measured validate
|
|
44
|
+
* failures in #4385 §2 C2.
|
|
39
45
|
*/
|
|
40
46
|
export declare const WorkflowValidateInputSchema: z.ZodObject<{
|
|
41
47
|
definition: z.ZodOptional<z.ZodAny>;
|
|
42
48
|
definition_yaml: z.ZodOptional<z.ZodString>;
|
|
43
49
|
yaml: z.ZodOptional<z.ZodString>;
|
|
50
|
+
file: z.ZodOptional<z.ZodString>;
|
|
44
51
|
}, "strip", z.ZodTypeAny, {
|
|
52
|
+
file?: string | undefined;
|
|
45
53
|
definition?: any;
|
|
46
54
|
definition_yaml?: string | undefined;
|
|
47
55
|
yaml?: string | undefined;
|
|
48
56
|
}, {
|
|
57
|
+
file?: string | undefined;
|
|
49
58
|
definition?: any;
|
|
50
59
|
definition_yaml?: string | undefined;
|
|
51
60
|
yaml?: string | undefined;
|