@ai-setting/roy-agent-core 1.7.64 → 1.7.65
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/environment.d.ts +27 -0
- package/dist/env/event-source/event-source-handlers.js +3 -2
- package/dist/env/event-source/index.js +4 -3
- package/dist/env/index.js +7 -6
- package/dist/env/task/delegate/delegate-tool.d.ts +2 -2
- package/dist/env/task/hooks/contexts.d.ts +34 -0
- package/dist/env/task/hooks/verdict.d.ts +170 -0
- package/dist/env/task/index.js +3 -2
- package/dist/env/task/mcp/index.js +2 -1
- package/dist/env/task/plugins/__e2e__/laya-chain-validate.d.ts +15 -0
- package/dist/env/task/plugins/__e2e__/laya-decision-branches.d.ts +18 -0
- package/dist/env/task/plugins/__e2e__/laya-decision-e2e-live.d.ts +27 -0
- package/dist/env/task/plugins/__e2e__/laya-e2e-verify.d.ts +17 -0
- package/dist/env/task/plugins/decision-hint-plugin.d.ts +144 -0
- package/dist/env/task/plugins/decision-port.d.ts +119 -0
- package/dist/env/task/plugins/decision-renderers.d.ts +33 -0
- package/dist/env/task/plugins/index.d.ts +1 -0
- package/dist/env/task/plugins/index.js +8 -1
- package/dist/env/task/plugins/laya-decision-plugin.d.ts +136 -0
- package/dist/env/task/plugins/laya-port.d.ts +143 -0
- package/dist/env/task/plugins/laya-render.d.ts +100 -0
- package/dist/env/task/tools/index.js +2 -1
- package/dist/index.js +7 -6
- package/dist/shared/@ai-setting/{roy-agent-core-1h5bbqcg.js → roy-agent-core-18am1h07.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-vncwfzw5.js → roy-agent-core-6z412atw.js} +39 -2
- package/dist/shared/@ai-setting/{roy-agent-core-vd9zak15.js → roy-agent-core-e42v9bcq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-ry2eztft.js → roy-agent-core-f6c0nadn.js} +958 -94
- package/dist/shared/@ai-setting/{roy-agent-core-e4hehcdr.js → roy-agent-core-hmdcz3g9.js} +3 -2
- package/dist/shared/@ai-setting/{roy-agent-core-xw4wsj38.js → roy-agent-core-t0ktaevq.js} +48 -2
- package/dist/shared/@ai-setting/roy-agent-core-tr3ep81v.js +397 -0
- package/package.json +1 -1
|
@@ -23,6 +23,33 @@ import type { Environment, ServiceConfig, ComponentConfigEntry, GeneratedCompone
|
|
|
23
23
|
import type { EnvironmentConfig, BaseEnvironmentConfig, EnvEvent, EnvEventInput, EnvEventHandler, Action, ToolResult, Context } from "./types";
|
|
24
24
|
import type { AgentContext } from "./agent/types";
|
|
25
25
|
import type { ContentPart } from "./llm/types";
|
|
26
|
+
import type { TaskComponent } from "./task/task-component";
|
|
27
|
+
import type { LayaDecisionPluginOptions } from "./task/plugins/laya-decision-plugin";
|
|
28
|
+
/**
|
|
29
|
+
* Task #4627 — 把 Laya 决策插件注册到 **task hook 通道**(`task:before.create`)。
|
|
30
|
+
*
|
|
31
|
+
* ⚠️ 为什么必须走 task hook 而不是 Agent Plugin(#4620 的 bug 1):
|
|
32
|
+
* `AgentComponent.registerPlugin()` 只把 plugin 放进 `agent.plugins` Map,
|
|
33
|
+
* **不写 globalHookManager**;而 `agent.plugins` 只在 agent 作用域 hook 点
|
|
34
|
+
* 被派发(`agent:before.start` / `agent:before.llm` / ...),**不含
|
|
35
|
+
* `task:before.create`**。`task:before.create` 的唯一派发路径是
|
|
36
|
+
* `TaskComponent.createTask()` → `globalHookManager.execute(...)`。
|
|
37
|
+
*
|
|
38
|
+
* ⚠️ 幂等保护:
|
|
39
|
+
* `globalHookManager.register()` 是 **push 到数组**(不覆盖同名),
|
|
40
|
+
* 而 `handle_query` 每次调用都会走一遍注册逻辑 → 不去重会导致:
|
|
41
|
+
* ① hook 被注册 N 次 → hint 重复执行
|
|
42
|
+
* ② 模型被重复调用 N 次(每次 task_create 都打 N 次 HTTP)
|
|
43
|
+
* 这里采用「先 unregister 再 register」保证**全局恰好 1 份**。
|
|
44
|
+
*
|
|
45
|
+
* ⚠️ fail-open:注册失败**绝不影响** agent 启动 / task_create 成功语义。
|
|
46
|
+
*
|
|
47
|
+
* @param taskComponent —— TaskComponent(由 `this.getComponent("task")` 取得)
|
|
48
|
+
* @param options —— LayaDecisionPluginOptions(生产不传 → 读 auth.json;
|
|
49
|
+
* 测试可注入 decisionPort / fetchImpl)
|
|
50
|
+
* @returns 是否成功注册
|
|
51
|
+
*/
|
|
52
|
+
export declare function registerLayaDecisionTaskHook(taskComponent: TaskComponent | undefined | null, options?: LayaDecisionPluginOptions): boolean;
|
|
26
53
|
/**
|
|
27
54
|
* 默认 agent 名字(向后兼容)
|
|
28
55
|
*/
|
|
@@ -10,18 +10,19 @@ import {
|
|
|
10
10
|
patchCardByLarkCli,
|
|
11
11
|
renderRuleNoticeSection,
|
|
12
12
|
timerHandler
|
|
13
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
13
|
+
} from "../../shared/@ai-setting/roy-agent-core-18am1h07.js";
|
|
14
14
|
import"../../shared/@ai-setting/roy-agent-core-bxkjk7zx.js";
|
|
15
15
|
import"../../shared/@ai-setting/roy-agent-core-add1zqsh.js";
|
|
16
16
|
import {
|
|
17
17
|
cliCommandHandler
|
|
18
18
|
} from "../../shared/@ai-setting/roy-agent-core-v0hf14bj.js";
|
|
19
19
|
import"../../shared/@ai-setting/roy-agent-core-tm1mxttk.js";
|
|
20
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
20
|
+
import"../../shared/@ai-setting/roy-agent-core-f6c0nadn.js";
|
|
21
21
|
import"../../shared/@ai-setting/roy-agent-core-na18zwj0.js";
|
|
22
22
|
import"../../shared/@ai-setting/roy-agent-core-9bs6xrav.js";
|
|
23
23
|
import"../../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
24
24
|
import"../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
25
|
+
import"../../shared/@ai-setting/roy-agent-core-tr3ep81v.js";
|
|
25
26
|
import"../../shared/@ai-setting/roy-agent-core-0ys85x46.js";
|
|
26
27
|
import"../../shared/@ai-setting/roy-agent-core-zk2jg0v7.js";
|
|
27
28
|
import"../../shared/@ai-setting/roy-agent-core-c2gbt68e.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import"../../shared/@ai-setting/roy-agent-core-5enxfga2.js";
|
|
2
2
|
import {
|
|
3
3
|
EventSourceComponent
|
|
4
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
4
|
+
} from "../../shared/@ai-setting/roy-agent-core-e42v9bcq.js";
|
|
5
5
|
import {
|
|
6
6
|
BountyIMInstance,
|
|
7
7
|
TimerInstance,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
larkCliHandler,
|
|
14
14
|
resolveBountyIMSystemPrompt,
|
|
15
15
|
timerHandler
|
|
16
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
16
|
+
} from "../../shared/@ai-setting/roy-agent-core-18am1h07.js";
|
|
17
17
|
import {
|
|
18
18
|
BUILT_IN_EVENT_SOURCE_TYPES,
|
|
19
19
|
BUILT_IN_EVENT_SOURCE_TYPE_LIST,
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
parseCliSessionChatId
|
|
33
33
|
} from "../../shared/@ai-setting/roy-agent-core-v0hf14bj.js";
|
|
34
34
|
import"../../shared/@ai-setting/roy-agent-core-tm1mxttk.js";
|
|
35
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
35
|
+
import"../../shared/@ai-setting/roy-agent-core-f6c0nadn.js";
|
|
36
36
|
import {
|
|
37
37
|
EventStoreImpl,
|
|
38
38
|
getSharedEventStore,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
import"../../shared/@ai-setting/roy-agent-core-9bs6xrav.js";
|
|
43
43
|
import"../../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
44
44
|
import"../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
45
|
+
import"../../shared/@ai-setting/roy-agent-core-tr3ep81v.js";
|
|
45
46
|
import"../../shared/@ai-setting/roy-agent-core-0ys85x46.js";
|
|
46
47
|
import"../../shared/@ai-setting/roy-agent-core-zk2jg0v7.js";
|
|
47
48
|
import"../../shared/@ai-setting/roy-agent-core-c2gbt68e.js";
|
package/dist/env/index.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BaseEnvironment
|
|
3
|
-
} from "../shared/@ai-setting/roy-agent-core-
|
|
3
|
+
} from "../shared/@ai-setting/roy-agent-core-6z412atw.js";
|
|
4
4
|
import {
|
|
5
5
|
TaskComponent
|
|
6
|
-
} from "../shared/@ai-setting/roy-agent-core-
|
|
6
|
+
} from "../shared/@ai-setting/roy-agent-core-hmdcz3g9.js";
|
|
7
7
|
import"../shared/@ai-setting/roy-agent-core-amkqnyzy.js";
|
|
8
8
|
import"../shared/@ai-setting/roy-agent-core-jm136jzh.js";
|
|
9
9
|
import"../shared/@ai-setting/roy-agent-core-hjejpcg5.js";
|
|
10
10
|
import"../shared/@ai-setting/roy-agent-core-fttgm52a.js";
|
|
11
11
|
import"../shared/@ai-setting/roy-agent-core-gxzxq1sf.js";
|
|
12
12
|
import"../shared/@ai-setting/roy-agent-core-8gxth0eh.js";
|
|
13
|
-
import"../shared/@ai-setting/roy-agent-core-
|
|
13
|
+
import"../shared/@ai-setting/roy-agent-core-t0ktaevq.js";
|
|
14
14
|
import"../shared/@ai-setting/roy-agent-core-rn57psp0.js";
|
|
15
15
|
import {
|
|
16
16
|
EventSourceComponent
|
|
17
|
-
} from "../shared/@ai-setting/roy-agent-core-
|
|
17
|
+
} from "../shared/@ai-setting/roy-agent-core-e42v9bcq.js";
|
|
18
18
|
import {
|
|
19
19
|
builtInHandlers,
|
|
20
20
|
larkCliHandler
|
|
21
|
-
} from "../shared/@ai-setting/roy-agent-core-
|
|
21
|
+
} from "../shared/@ai-setting/roy-agent-core-18am1h07.js";
|
|
22
22
|
import {
|
|
23
23
|
EventSourceInitHooks,
|
|
24
24
|
getDefaultConfigForType,
|
|
@@ -29,11 +29,12 @@ import {
|
|
|
29
29
|
import"../shared/@ai-setting/roy-agent-core-add1zqsh.js";
|
|
30
30
|
import"../shared/@ai-setting/roy-agent-core-v0hf14bj.js";
|
|
31
31
|
import"../shared/@ai-setting/roy-agent-core-tm1mxttk.js";
|
|
32
|
-
import"../shared/@ai-setting/roy-agent-core-
|
|
32
|
+
import"../shared/@ai-setting/roy-agent-core-f6c0nadn.js";
|
|
33
33
|
import"../shared/@ai-setting/roy-agent-core-na18zwj0.js";
|
|
34
34
|
import"../shared/@ai-setting/roy-agent-core-9bs6xrav.js";
|
|
35
35
|
import"../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
36
36
|
import"../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
37
|
+
import"../shared/@ai-setting/roy-agent-core-tr3ep81v.js";
|
|
37
38
|
import"../shared/@ai-setting/roy-agent-core-0ys85x46.js";
|
|
38
39
|
import"../shared/@ai-setting/roy-agent-core-zk2jg0v7.js";
|
|
39
40
|
import {
|
|
@@ -165,17 +165,17 @@ export declare const DelegateToolParameters: z.ZodObject<{
|
|
|
165
165
|
triggerEventId: z.ZodOptional<z.ZodString>;
|
|
166
166
|
}, "strip", z.ZodTypeAny, {
|
|
167
167
|
description: string;
|
|
168
|
+
similar_task_ids: number[];
|
|
168
169
|
prompt: string;
|
|
169
170
|
subagent_type: string;
|
|
170
|
-
similar_task_ids: number[];
|
|
171
171
|
reason?: string | undefined;
|
|
172
172
|
timeout?: number | undefined;
|
|
173
173
|
sub_session_id?: string | undefined;
|
|
174
174
|
triggerEventId?: string | undefined;
|
|
175
175
|
}, {
|
|
176
176
|
description: string;
|
|
177
|
-
prompt: string;
|
|
178
177
|
similar_task_ids: number[];
|
|
178
|
+
prompt: string;
|
|
179
179
|
reason?: string | undefined;
|
|
180
180
|
timeout?: number | undefined;
|
|
181
181
|
subagent_type?: string | undefined;
|
|
@@ -18,6 +18,40 @@ export interface TaskCreateContext {
|
|
|
18
18
|
sessionId: string;
|
|
19
19
|
/** Tag 服务引用 */
|
|
20
20
|
tagService: TagService;
|
|
21
|
+
/**
|
|
22
|
+
* TaskComponent 句柄(**只读能力**)。
|
|
23
|
+
*
|
|
24
|
+
* ⚠️ Task #4620:决策检测插件需要按 `similar_task_ids` 取候选任务详情,
|
|
25
|
+
* 而候选详情只有 TaskComponent 能给(store 是私有的)。这就是 #4467
|
|
26
|
+
* 契约里「实在需要就只加 1 行 `taskComponent: this`」的那一行。
|
|
27
|
+
*
|
|
28
|
+
* 插件**只读**它(getTask / listTasks / searchTasksByKeywords /
|
|
29
|
+
* getChildTasks),不写、不删、不改任何任务 —— 决策是**只提示不拦截**。
|
|
30
|
+
*
|
|
31
|
+
* 可选(`?`):老插件 / 测试里不注入时插件应自行跳过(fail-open)。
|
|
32
|
+
*/
|
|
33
|
+
taskComponent?: TaskComponentReadonlyHandle;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* TaskCreateContext.taskComponent 的最小只读能力面。
|
|
37
|
+
*
|
|
38
|
+
* 单独定义接口(而不是直接用 TaskComponent)是为了**避免类型循环依赖** ——
|
|
39
|
+
* TaskComponent 也引用 hook contexts。
|
|
40
|
+
*/
|
|
41
|
+
export interface TaskComponentReadonlyHandle {
|
|
42
|
+
getTask(id: number): Promise<any>;
|
|
43
|
+
listTasks(options?: any): Promise<{
|
|
44
|
+
tasks: any[];
|
|
45
|
+
total: number;
|
|
46
|
+
}>;
|
|
47
|
+
searchTasksByKeywords(keywords: string[], options?: any): Promise<{
|
|
48
|
+
tasks: any[];
|
|
49
|
+
total: number;
|
|
50
|
+
}>;
|
|
51
|
+
getChildTasks(taskId: number, options?: any): Promise<{
|
|
52
|
+
tasks: any[];
|
|
53
|
+
total: number;
|
|
54
|
+
}>;
|
|
21
55
|
}
|
|
22
56
|
/**
|
|
23
57
|
* Task Create Result Hook Context
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4467 — task_create 检测的纯函数层(verdict)
|
|
3
|
+
*
|
|
4
|
+
* 契约:/tmp/task-create-verdict-contract-v2.md
|
|
5
|
+
*
|
|
6
|
+
* 本文件只放**纯函数**(无 IO、无网络),便于单测:
|
|
7
|
+
* - parseSimilarTaskIds 解析 context.similar_task_ids
|
|
8
|
+
* - deriveActionFromStatus status → reopen / enhance
|
|
9
|
+
* - buildHintText 生成可执行的 hint 文本
|
|
10
|
+
* - assertNoLeakage 键名树泄漏断言(**不对值做正则**)
|
|
11
|
+
* - writeDecisionHint 写 context.decision_hint
|
|
12
|
+
* - renderCandidate* #4107 实测的 99 字符候选模板
|
|
13
|
+
*/
|
|
14
|
+
import type { CreateTaskOptions } from "../types";
|
|
15
|
+
/** `similar_task_ids` 元素上限(P16) */
|
|
16
|
+
export declare const MAX_SIMILAR_TASK_IDS = 20;
|
|
17
|
+
/** 候选渲染:key 的 title 截断长度(P13) */
|
|
18
|
+
export declare const CANDIDATE_TITLE_MAX = 40;
|
|
19
|
+
/** 候选渲染:value 的 description 截断长度(P14) */
|
|
20
|
+
export declare const CANDIDATE_DESC_MAX = 45;
|
|
21
|
+
/** 候选渲染:tags 展示上限(P15) */
|
|
22
|
+
export declare const CANDIDATE_TAGS_MAX = 4;
|
|
23
|
+
export type DecisionAction = "reopen" | "enhance" | "none";
|
|
24
|
+
export type HintScenario = "reuse" | "reopen" | "reopen_enhance" | "remount" | "soft_reuse";
|
|
25
|
+
export interface HintInput {
|
|
26
|
+
scenario: HintScenario;
|
|
27
|
+
/** 本次新建出来的任务 id(hint 里回指) */
|
|
28
|
+
newTaskId: number;
|
|
29
|
+
/** 建议复用 / 重开的目标任务 id */
|
|
30
|
+
targetTaskId?: number;
|
|
31
|
+
targetTask?: {
|
|
32
|
+
title: string;
|
|
33
|
+
status: string;
|
|
34
|
+
type: string;
|
|
35
|
+
};
|
|
36
|
+
/** remount 场景:推荐的 root id */
|
|
37
|
+
recommendedRootId?: number;
|
|
38
|
+
recommendedRootTitle?: string;
|
|
39
|
+
/** remount 场景:当前实际传入的 parent */
|
|
40
|
+
currentParentId?: number;
|
|
41
|
+
/** remount 场景:当前 parent 所属的 root 祖先 */
|
|
42
|
+
currentRootAncestorId?: number;
|
|
43
|
+
confidence?: number;
|
|
44
|
+
/** reopen_enhance 场景:是否额外带 goals 参数 */
|
|
45
|
+
includeGoals?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface CandidateRenderInput {
|
|
48
|
+
id: number;
|
|
49
|
+
type: string;
|
|
50
|
+
title: string;
|
|
51
|
+
}
|
|
52
|
+
/** 泄漏断言的 deny-list(键名匹配,前缀语义) */
|
|
53
|
+
export declare const LEAKAGE_DENY_KEYS: readonly ["expected_decision", "expected_root", "expected_", "case_id", "category", "suggested_", "recommended_", "best_match", "answer", "answer_key", "label", "should_", "target", "gold", "ground_truth", "hint", "solution", "duplicate_of", "similar_task_ids", "candidate_order", "verdict", "decision"];
|
|
54
|
+
/**
|
|
55
|
+
* 从 context JSON 里解析 `similar_task_ids`。
|
|
56
|
+
*
|
|
57
|
+
* 容错规则(契约 §2.3):
|
|
58
|
+
* - context 缺失 / 非 JSON / 非对象 → []
|
|
59
|
+
* - 字段缺失 / 非数组 → []
|
|
60
|
+
* - 逐元素校验 `Number.isInteger(id) && id > 0`,非法元素丢弃
|
|
61
|
+
* - 长度 > MAX_SIMILAR_TASK_IDS → 截断
|
|
62
|
+
* - 重复 id → 去重(保留首次出现顺序)
|
|
63
|
+
*/
|
|
64
|
+
declare function parseSimilarTaskIdsImpl(contextJson: string | undefined): number[];
|
|
65
|
+
/**
|
|
66
|
+
* status → 动作派生(纯规则,不需要模型)。
|
|
67
|
+
*
|
|
68
|
+
* completed / cancelled / paused / archived → reopen
|
|
69
|
+
* todo / active / 未知 → enhance
|
|
70
|
+
*/
|
|
71
|
+
declare function deriveActionFromStatusImpl(status: string): DecisionAction;
|
|
72
|
+
/**
|
|
73
|
+
* reopen 时目标 status 的派生(契约 §4.5)。
|
|
74
|
+
* paused → active(恢复即继续做)
|
|
75
|
+
* completed / cancelled / archived → todo(已终结的任务先回未开始)
|
|
76
|
+
*/
|
|
77
|
+
export declare function deriveReopenStatus(status: string): "todo" | "active";
|
|
78
|
+
/**
|
|
79
|
+
* 新任务 id 的占位符(**裸数字**形态)。
|
|
80
|
+
*
|
|
81
|
+
* ⚠️ hint 是在 `task:before.create` 阶段写入 `context.decision_hint` 的,
|
|
82
|
+
* 此时新任务**还没有 id**。create-tool 在 `:351` 拼 output 时用真实 id 替换本占位符。
|
|
83
|
+
*
|
|
84
|
+
* 形态选择:占位符是**裸数字**(`__NEW_TASK_ID__`),因为它主要出现在
|
|
85
|
+
* `task_update(task_id=__NEW_TASK_ID__, ...)` 这种参数位置;
|
|
86
|
+
* 需要 `#id` 形态的地方(散文里的「本次已创建新任务 #__NEW_TASK_ID__」)由调用方加 `#`。
|
|
87
|
+
*/
|
|
88
|
+
export declare const NEW_TASK_ID_PLACEHOLDER = "__NEW_TASK_ID__";
|
|
89
|
+
/**
|
|
90
|
+
* 新任务 id 的**带 # 形态**占位符(用于散文语境,如「本次已创建新任务 #__NEW_TASK_ID__」)。
|
|
91
|
+
*
|
|
92
|
+
* 与 {@link NEW_TASK_ID_PLACEHOLDER} 分开的原因:参数位置需要裸数字
|
|
93
|
+
* (`task_update(task_id=__NEW_TASK_ID__)`),散文位置需要 `#id`。
|
|
94
|
+
* 两者由 create-tool 一起替换。
|
|
95
|
+
*/
|
|
96
|
+
export declare const NEW_TASK_ID_HASH_PLACEHOLDER = "#__NEW_TASK_ID__";
|
|
97
|
+
/**
|
|
98
|
+
* 生成 hint 文本。
|
|
99
|
+
*
|
|
100
|
+
* 每种场景都必须给出**可直接执行的 `task_update` 参数** ——
|
|
101
|
+
* 提示不可执行等于没说(这是 v1 的阻断级缺陷 B3)。
|
|
102
|
+
*/
|
|
103
|
+
declare function buildHintTextImpl(input: HintInput): string;
|
|
104
|
+
/**
|
|
105
|
+
* 泄漏断言:**只 walk 键名树**,绝不对值做正则。
|
|
106
|
+
*
|
|
107
|
+
* 原因(契约 §4.6 + 请求契约 v1 交叉验证第 8 项):值含用户自由文本
|
|
108
|
+
* (例如用户写「期望的 label 是 xxx」),正则会误杀用户正常输入。
|
|
109
|
+
*
|
|
110
|
+
* @throws Error 当键名树命中 deny-list 时
|
|
111
|
+
*/
|
|
112
|
+
declare function assertNoLeakageImpl(state: unknown, questions: unknown): void;
|
|
113
|
+
/**
|
|
114
|
+
* 把 hint 写进 `options.context.decision_hint`(JSON 内字段)。
|
|
115
|
+
*
|
|
116
|
+
* @returns true 写成功;false 写失败(context 不是合法 JSON 对象)——
|
|
117
|
+
* 失败时**不修改** context,绝不破坏用户数据。
|
|
118
|
+
*/
|
|
119
|
+
declare function writeDecisionHintImpl(options: CreateTaskOptions, hint: string): boolean;
|
|
120
|
+
/** key = `#<id> [<type>] <title 截断>` */
|
|
121
|
+
export declare function renderCandidateKey(c: CandidateRenderInput): string;
|
|
122
|
+
/** value = `<status 首字母>|<相对时间>|<description 截断45> [tags: 前4个]` */
|
|
123
|
+
export declare function renderCandidateValue(c: {
|
|
124
|
+
id: number;
|
|
125
|
+
status: string;
|
|
126
|
+
ago: string;
|
|
127
|
+
description: string;
|
|
128
|
+
tags?: string[];
|
|
129
|
+
}): string;
|
|
130
|
+
/**
|
|
131
|
+
* 相对时间格式化(P17):d / h / m;未来时间钳到 `0m`。
|
|
132
|
+
*/
|
|
133
|
+
export declare function formatRelativeAge(isoTimestamp: string, now?: number): string;
|
|
134
|
+
/**
|
|
135
|
+
* 解析 `context.similar_task_ids`。
|
|
136
|
+
*
|
|
137
|
+
* recordParams: 只记 `contextLen` + 原始片段前 80 字(避免整段 context JSON 进 trace)
|
|
138
|
+
* recordResult: 记 id 数组(数量小,可直接看)
|
|
139
|
+
*/
|
|
140
|
+
export declare const parseSimilarTaskIds: typeof parseSimilarTaskIdsImpl;
|
|
141
|
+
/**
|
|
142
|
+
* status → 动作派生(纯规则)。
|
|
143
|
+
*
|
|
144
|
+
* 入参是单个 status 字符串,出参是 reopen/enhance/none —— 体积小,全记。
|
|
145
|
+
*/
|
|
146
|
+
export declare const deriveActionFromStatus: typeof deriveActionFromStatusImpl;
|
|
147
|
+
/**
|
|
148
|
+
* 生成可执行 hint 文本。
|
|
149
|
+
*
|
|
150
|
+
* ⚠️ result 是**多行长文本**(含 `task_update({...})` 模板),必须截断:
|
|
151
|
+
* 契约 §6 的 5 种模板最长约 800 字符,这里只留前 240 字符 + 总长度,
|
|
152
|
+
* 完整文本可通过 `debug span` 的 attributes.params 拿到 HintInput 反推。
|
|
153
|
+
*/
|
|
154
|
+
export declare const buildHintText: typeof buildHintTextImpl;
|
|
155
|
+
/**
|
|
156
|
+
* 泄漏断言 —— **最关键的一条 trace**。
|
|
157
|
+
*
|
|
158
|
+
* 为什么必须可观测:泄漏断言是「请求体永不含答案」的唯一守门人。
|
|
159
|
+
* 如果它静默跳过/静默失败,trace 里会完全看不出来(无 span = 无证据)。
|
|
160
|
+
* 这里用 `errorIf` 让 span 在抛错时显式标 ERROR。
|
|
161
|
+
*/
|
|
162
|
+
export declare const assertNoLeakage: typeof assertNoLeakageImpl;
|
|
163
|
+
/**
|
|
164
|
+
* 写 `options.context.decision_hint`。
|
|
165
|
+
*
|
|
166
|
+
* 返回值是 boolean(写成功/失败),用 `errorIf` 把 false 标成 span ERROR ——
|
|
167
|
+
* 否则"写失败导致 hint 静默丢失"在 trace 里完全看不出来。
|
|
168
|
+
*/
|
|
169
|
+
export declare const writeDecisionHint: typeof writeDecisionHintImpl;
|
|
170
|
+
export {};
|
package/dist/env/task/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
TaskPriorityEnum,
|
|
6
6
|
TaskStatusEnum,
|
|
7
7
|
TaskTypeEnum
|
|
8
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
8
|
+
} from "../../shared/@ai-setting/roy-agent-core-hmdcz3g9.js";
|
|
9
9
|
import"../../shared/@ai-setting/roy-agent-core-amkqnyzy.js";
|
|
10
10
|
import"../../shared/@ai-setting/roy-agent-core-jm136jzh.js";
|
|
11
11
|
import"../../shared/@ai-setting/roy-agent-core-hjejpcg5.js";
|
|
@@ -14,7 +14,7 @@ import"../../shared/@ai-setting/roy-agent-core-gxzxq1sf.js";
|
|
|
14
14
|
import {
|
|
15
15
|
TaskEntityEventTypes
|
|
16
16
|
} from "../../shared/@ai-setting/roy-agent-core-8gxth0eh.js";
|
|
17
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
17
|
+
import"../../shared/@ai-setting/roy-agent-core-t0ktaevq.js";
|
|
18
18
|
import"../../shared/@ai-setting/roy-agent-core-rn57psp0.js";
|
|
19
19
|
import"../../shared/@ai-setting/roy-agent-core-na18zwj0.js";
|
|
20
20
|
import {
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "../../shared/@ai-setting/roy-agent-core-9bs6xrav.js";
|
|
24
24
|
import"../../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
25
25
|
import"../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
26
|
+
import"../../shared/@ai-setting/roy-agent-core-tr3ep81v.js";
|
|
26
27
|
import"../../shared/@ai-setting/roy-agent-core-07fvy74y.js";
|
|
27
28
|
import"../../shared/@ai-setting/roy-agent-core-qxnbvgwe.js";
|
|
28
29
|
import"../../shared/@ai-setting/roy-agent-core-c1v263jn.js";
|
|
@@ -6,11 +6,12 @@ import {
|
|
|
6
6
|
searchTasksTool,
|
|
7
7
|
treeTasksTool,
|
|
8
8
|
updateTaskTool
|
|
9
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
9
|
+
} from "../../../shared/@ai-setting/roy-agent-core-t0ktaevq.js";
|
|
10
10
|
import {
|
|
11
11
|
createOperationTool,
|
|
12
12
|
listOperationsTool
|
|
13
13
|
} from "../../../shared/@ai-setting/roy-agent-core-rn57psp0.js";
|
|
14
|
+
import"../../../shared/@ai-setting/roy-agent-core-tr3ep81v.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";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4620 — 全链路验证:真实 layaRenderer + 真实 LayaDecisionPort
|
|
3
|
+
*
|
|
4
|
+
* 目的:证明「roy-agent 侧渲染 + client + laya 服务」这条完整链路
|
|
5
|
+
* 在**有 ground truth 的 held-out 集**上能复现 #4614 报告的准确率。
|
|
6
|
+
*
|
|
7
|
+
* 这比单点验证强得多:
|
|
8
|
+
* - 只测 client → 只能证明协议通
|
|
9
|
+
* - 只测渲染 → 只能证明格式对
|
|
10
|
+
* - 全链路 → 证明「roy-agent 发的请求」与「训练分布」一致,且结果可复现
|
|
11
|
+
*
|
|
12
|
+
* 跑法(worktree 的 packages/core 下):
|
|
13
|
+
* bun run src/env/task/plugins/__e2e__/laya-chain-validate.ts
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4627 — Laya 决策插件 **全分支回归脚本**(可重跑)
|
|
3
|
+
*
|
|
4
|
+
* 用法:
|
|
5
|
+
* ```bash
|
|
6
|
+
* cd packages/core && bun run src/env/task/plugins/__e2e__/laya-decision-branches.ts
|
|
7
|
+
* # 或从仓库根
|
|
8
|
+
* bun run packages/core/src/env/task/plugins/__e2e__/laya-decision-branches.ts
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ 两种驱动模式:
|
|
12
|
+
* - **mock 模式**(默认):注入假 port,**确定性**,不依赖 Laya 服务 → 断言 7 个分支的判定逻辑
|
|
13
|
+
* - **live 模式**(`--live`):真调本机 Laya 服务(http://127.0.0.1:8901)
|
|
14
|
+
*
|
|
15
|
+
* 每个场景打印:场景名 / 实测值 / 断言结果 / 延迟(ms),最后给出汇总。
|
|
16
|
+
* 退出码 0 = 全部通过,1 = 有失败。
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4632 — Laya 决策插件 **真实端到端回归脚本**(真服务 + 真任务库)
|
|
3
|
+
*
|
|
4
|
+
* ⚠️⚠️⚠️ 与 `laya-decision-branches.ts` 的本质区别 ⚠️⚠️⚠️
|
|
5
|
+
*
|
|
6
|
+
* branches.ts → 场景 1a/1b/2/3/4/6/7 **全是 mock port**(直接返回构造好的答案),
|
|
7
|
+
* 只有场景 8 是 live 且只有 1 个 case、不强制断言 hint。
|
|
8
|
+
* 本脚本 → **全程真实**:真读 auth.json → 真 HTTP 打 Laya 服务 →
|
|
9
|
+
* 真走 task_create → 候选来自**真实 tasks.db 的真实任务**。
|
|
10
|
+
*
|
|
11
|
+
* 跑法:
|
|
12
|
+
* ```bash
|
|
13
|
+
* cd <worktree>/packages/core
|
|
14
|
+
* bun run src/env/task/plugins/__e2e__/laya-decision-e2e-live.ts
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* 前置:
|
|
18
|
+
* - Laya 服务在线(auth.json 的 providers['laya-decision'].baseURL,health 200)
|
|
19
|
+
* - 真实任务库 `~/.local/share/roy-agent/tasks.db` 存在(4188 个真实任务)
|
|
20
|
+
* - 金标准 `laya-train/data/gold-split.json`(unseen 25 个真实父子对)
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ 本脚本**只写临时 sqlite**(tmpdir),**不碰真实 tasks.db**;
|
|
23
|
+
* 只**读**真实 tasks.db 取候选内容。
|
|
24
|
+
*
|
|
25
|
+
* 退出码 0 = 全绿;1 = 有失败。
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4620 — 端到端验证脚本(真调本地 laya 服务 + 真 task_create)
|
|
3
|
+
*
|
|
4
|
+
* 目的:证明「task_create 带上 similar_task_ids → output 里真的出现 hint」这条链路
|
|
5
|
+
* 在**真实服务 + 真实 TaskComponent + 真实 create-tool** 下是通的。
|
|
6
|
+
*
|
|
7
|
+
* 跑法:
|
|
8
|
+
* cd <worktree>/packages/core
|
|
9
|
+
* bun run src/env/task/plugins/__e2e__/laya-e2e-verify.ts
|
|
10
|
+
*
|
|
11
|
+
* 前置:
|
|
12
|
+
* - laya-serve 已在 http://127.0.0.1:8901 跑着(scripts/serve_laya.sh)
|
|
13
|
+
* - ~/.roy-agent/auth.json 有 providers['laya-decision']
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ 本脚本**只写临时 sqlite**(tmpdir),不碰真实 tasks.db。
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Task #4467 — task:before.create 的 decision 检测插件
|
|
3
|
+
*
|
|
4
|
+
* 契约:/tmp/task-create-verdict-contract-v2.md
|
|
5
|
+
*
|
|
6
|
+
* 形态:**只提示,不拦截**。
|
|
7
|
+
* 创建照常发生,插件只把建议文本写进 `ctx.options.context.decision_hint`,
|
|
8
|
+
* 由调用方 agent 自己决定是否调 `task_update` 修正。
|
|
9
|
+
*
|
|
10
|
+
* 门槛(契约 §4.1):
|
|
11
|
+
* 候选 0 个 → 放行,不调模型
|
|
12
|
+
* 候选 1 个 → 不调模型,直接给「建议复用 #id」hint
|
|
13
|
+
* 候选 ≥2 个 → 调 decision model 做 Stage A 判定
|
|
14
|
+
*
|
|
15
|
+
* Stage A 判「新建 vs 复用」;Stage B(仅当新建)判「新建 root vs 挂到某 root」。
|
|
16
|
+
* status → 动作(reopen / enhance)是**纯规则**推导,不需要模型。
|
|
17
|
+
*/
|
|
18
|
+
import type { DecisionPort, DecisionRequest, DecisionAnswer } from "./decision-port";
|
|
19
|
+
import type { TaskCreateContext } from "../hooks/contexts";
|
|
20
|
+
import type { Task } from "../types";
|
|
21
|
+
/** 只读能力面 —— 避免与 TaskComponent 产生类型循环依赖(契约 §3.3) */
|
|
22
|
+
export interface TaskComponentReadonly {
|
|
23
|
+
getTask(id: number): Promise<Task | undefined>;
|
|
24
|
+
listTasks(options?: any): Promise<{
|
|
25
|
+
tasks: Task[];
|
|
26
|
+
total: number;
|
|
27
|
+
}>;
|
|
28
|
+
searchTasksByKeywords(keywords: string[], options?: any): Promise<{
|
|
29
|
+
tasks: Task[];
|
|
30
|
+
total: number;
|
|
31
|
+
}>;
|
|
32
|
+
getChildTasks(taskId: number, options?: any): Promise<{
|
|
33
|
+
tasks: Task[];
|
|
34
|
+
total: number;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
export interface DecisionHintPluginOptions {
|
|
38
|
+
/** 注入的决策端口(测试用假 port;生产用 SystemOneDecisionPort) */
|
|
39
|
+
decisionPort: DecisionPort;
|
|
40
|
+
/** 上下文读取(生产用 getEnvContextOrEmpty().parentTaskId) */
|
|
41
|
+
envParentTaskIdProvider?: () => number | undefined | null;
|
|
42
|
+
/**
|
|
43
|
+
* 渲染策略 —— 决定 state / criteria / choice 映射的形态。
|
|
44
|
+
*
|
|
45
|
+
* ⚠️ Task #4620:**不同载体的训练格式不同,必须显式选**。
|
|
46
|
+
* - `systemone`(默认):阿里百炼 systemone 的习惯 —— state 是 JSON 对象,
|
|
47
|
+
* criteria key = `#<id> [<type>] <title>`(#4107 模板)
|
|
48
|
+
* - `laya`:#4614 的 Laya 微调模型训练时的格式 —— state 是中文文本
|
|
49
|
+
* (【新任务标题】/【新任务描述】/【候选任务】),criteria key = `#<id> <title[:50]>`
|
|
50
|
+
*
|
|
51
|
+
* 实测(200 条 held-out,laya-train/scripts/format_probe.py):
|
|
52
|
+
* laya 格式 79.00% vs systemone 格式 46.50% → **用 laya 载体必须选 laya 渲染**。
|
|
53
|
+
*/
|
|
54
|
+
renderer?: DecisionRenderer;
|
|
55
|
+
/**
|
|
56
|
+
* 「建议复用」硬提示的置信度门禁(默认 0.6 = #4467 Q4 的 routing 档)。
|
|
57
|
+
*
|
|
58
|
+
* ⚠️ Task #4620:Laya 载体用 **0.85**(#4467 Q4 的「不新建」破坏性档)。
|
|
59
|
+
* 896 条实测:thr=0.85 → 提示精确率 80.5%(coverage 28.7%),
|
|
60
|
+
* thr=0.9 → 84.9%,thr=0.95 → 87.0%。
|
|
61
|
+
*/
|
|
62
|
+
reuseThreshold?: number;
|
|
63
|
+
/**
|
|
64
|
+
* 低于此置信度**完全不出提示**(默认 0.4)。
|
|
65
|
+
*
|
|
66
|
+
* ⚠️ Task #4620:Laya 载体把它设成与 `reuseThreshold` 同值(0.85),
|
|
67
|
+
* 语义就是「< 0.85 一律不出提示」(任务书的硬要求)。
|
|
68
|
+
*/
|
|
69
|
+
softHintThreshold?: number;
|
|
70
|
+
/**
|
|
71
|
+
* 「只有 1 个候选 → 不调模型,直接给建议复用 hint」的捷径。
|
|
72
|
+
*
|
|
73
|
+
* 默认 true(#4467 契约 §4.1)。Laya 载体设成 false —— 快捷路径**没有置信度**,
|
|
74
|
+
* 与「必须 confidence 门禁 ≥ 0.85」冲突,所以让它也走模型。
|
|
75
|
+
*/
|
|
76
|
+
singleCandidateShortcut?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 渲染策略接口 —— 把「候选 → state/questions」和「choice → task id」两件事
|
|
80
|
+
* 抽象出来,让同一套判定逻辑能服务不同载体的训练分布。
|
|
81
|
+
*/
|
|
82
|
+
export interface DecisionRenderer {
|
|
83
|
+
/** 渲染 Stage A 的请求 */
|
|
84
|
+
buildStageA(input: {
|
|
85
|
+
title: string;
|
|
86
|
+
description: string;
|
|
87
|
+
goals: string;
|
|
88
|
+
tags: string[];
|
|
89
|
+
projectPath: string;
|
|
90
|
+
candidates: Task[];
|
|
91
|
+
now: number;
|
|
92
|
+
}): DecisionRequest;
|
|
93
|
+
/** 把模型回的 choice 映射回候选 task id(映射不到返回 undefined) */
|
|
94
|
+
matchChoice(choice: string, candidates: Task[]): number | undefined;
|
|
95
|
+
}
|
|
96
|
+
export declare class DecisionHintPlugin {
|
|
97
|
+
readonly name = "decision-hint";
|
|
98
|
+
readonly version = "1.0.0";
|
|
99
|
+
readonly description = "Task #4467 \u2014 task:before.create \u7684 decision \u68C0\u6D4B\uFF1A\u5224\u5B9A\u65B0\u5EFA/\u590D\u7528 + root/\u5B50\u6302\u8F7D\uFF0C\u53EA\u63D0\u793A\u4E0D\u62E6\u622A";
|
|
100
|
+
private readonly decisionPort;
|
|
101
|
+
private readonly envParentTaskIdProvider;
|
|
102
|
+
private readonly renderer;
|
|
103
|
+
private readonly reuseThreshold;
|
|
104
|
+
private readonly softHintThreshold;
|
|
105
|
+
private readonly singleCandidateShortcut;
|
|
106
|
+
constructor(options: DecisionHintPluginOptions);
|
|
107
|
+
/**
|
|
108
|
+
* hook 入口 —— 任何异常都不得抛出(契约 §8 总原则)。
|
|
109
|
+
*
|
|
110
|
+
* ⚠️ 形状兼容(交叉验证 P1):框架 `HookManager` 派发的是 `HookContext`
|
|
111
|
+
* (载荷在 `ctx.data`,见 `hook/hook-manager.ts` createContext),而本插件
|
|
112
|
+
* 内部按裸 `TaskCreateContext` 工作。这里两种形状都接受,避免按标准
|
|
113
|
+
* `registerHook({ execute: (ctx) => plugin.execute(ctx) })` 接入时静默失效。
|
|
114
|
+
*/
|
|
115
|
+
execute(ctx: TaskCreateContext | {
|
|
116
|
+
data: TaskCreateContext;
|
|
117
|
+
}): Promise<void>;
|
|
118
|
+
private run;
|
|
119
|
+
private fallbackCandidates;
|
|
120
|
+
private runStageA;
|
|
121
|
+
private buildStageARequest;
|
|
122
|
+
private runStageB;
|
|
123
|
+
private collectRootCandidates;
|
|
124
|
+
/**
|
|
125
|
+
* 解析 root 祖先链(**防环** —— tasks.db 里存在手改 parent_task_id 造成的环)。
|
|
126
|
+
*/
|
|
127
|
+
private resolveRootAncestor;
|
|
128
|
+
private reuseHintInput;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Task #4627 — 选取**门禁用的置信度**(#302 的核心)。
|
|
132
|
+
*
|
|
133
|
+
* ⚠️ `confidence` 是**归一化熵**,**不是** Jev 公式置信度。
|
|
134
|
+
* laya 同时返回 `confidence`(熵)与 `x_jev_confidence`(Jev 公式),
|
|
135
|
+
* 60 条实测里 20 条差异 > 0.05 —— 读错字段会让门禁形同虚设。
|
|
136
|
+
*
|
|
137
|
+
* 选源顺序:`x_jev_confidence` → `answer_confidence` → `confidence`。
|
|
138
|
+
*
|
|
139
|
+
* ⚠️ 为什么不在载体侧做完就算:`LayaDecisionPort.normalize()` 已经把
|
|
140
|
+
* `confidence` 覆盖成选源后的值,但那是**载体专属**的归一化 —— 换载体
|
|
141
|
+
* (systemone 就没有 x_jev_confidence)就失效。判定层自己再选一次源,
|
|
142
|
+
* 保证「门禁永远读 Jev 公式置信度」这条不变量与载体解耦。
|
|
143
|
+
*/
|
|
144
|
+
export declare function pickGateConfidence(answer: DecisionAnswer | undefined): number;
|