odai-dsh-agent 0.2.5 → 0.2.7
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/README.md +3 -3
- package/build/bin/odai-dsh-agent.d.mts +3 -0
- package/build/bin/odai-dsh-agent.d.mts.map +1 -0
- package/build/bin/odai-dsh-agent.mjs +114 -0
- package/build/bin/odai-dsh-agent.mjs.map +1 -0
- package/build/src/dsh-version.d.mts +16 -0
- package/build/src/dsh-version.d.mts.map +1 -0
- package/build/src/dsh-version.mjs +20 -0
- package/build/src/dsh-version.mjs.map +1 -0
- package/build/src/installer.d.mts +46 -0
- package/build/src/installer.d.mts.map +1 -0
- package/build/src/installer.mjs +398 -0
- package/build/src/installer.mjs.map +1 -0
- package/package.json +13 -12
- package/preset/odai/runtime/compaction-config.d.mts +66 -0
- package/preset/odai/runtime/compaction-config.d.mts.map +1 -0
- package/preset/odai/runtime/compaction-config.mjs +320 -342
- package/preset/odai/runtime/compaction-config.mjs.map +1 -0
- package/preset/odai/runtime/compaction-runtime.d.mts +68 -0
- package/preset/odai/runtime/compaction-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/compaction-runtime.mjs +157 -0
- package/preset/odai/runtime/compaction-runtime.mjs.map +1 -0
- package/preset/odai/runtime/context-activation.d.mts +31 -0
- package/preset/odai/runtime/context-activation.d.mts.map +1 -0
- package/preset/odai/runtime/context-activation.mjs +55 -49
- package/preset/odai/runtime/context-activation.mjs.map +1 -0
- package/preset/odai/runtime/context-capability.d.mts +16 -0
- package/preset/odai/runtime/context-capability.d.mts.map +1 -0
- package/preset/odai/runtime/context-capability.mjs +79 -74
- package/preset/odai/runtime/context-capability.mjs.map +1 -0
- package/preset/odai/runtime/governance.d.mts +30 -0
- package/preset/odai/runtime/governance.d.mts.map +1 -0
- package/preset/odai/runtime/governance.mjs +126 -113
- package/preset/odai/runtime/governance.mjs.map +1 -0
- package/preset/odai/runtime/human-care.d.mts +13 -0
- package/preset/odai/runtime/human-care.d.mts.map +1 -0
- package/preset/odai/runtime/human-care.mjs +45 -42
- package/preset/odai/runtime/human-care.mjs.map +1 -0
- package/preset/odai/runtime/human-safety-continuity-store.d.mts +43 -0
- package/preset/odai/runtime/human-safety-continuity-store.d.mts.map +1 -0
- package/preset/odai/runtime/human-safety-continuity-store.mjs +193 -215
- package/preset/odai/runtime/human-safety-continuity-store.mjs.map +1 -0
- package/preset/odai/runtime/human-safety-continuity.d.mts +27 -0
- package/preset/odai/runtime/human-safety-continuity.d.mts.map +1 -0
- package/preset/odai/runtime/human-safety-continuity.mjs +205 -216
- package/preset/odai/runtime/human-safety-continuity.mjs.map +1 -0
- package/preset/odai/runtime/human-safety.d.mts +14 -0
- package/preset/odai/runtime/human-safety.d.mts.map +1 -0
- package/preset/odai/runtime/human-safety.mjs +50 -47
- package/preset/odai/runtime/human-safety.mjs.map +1 -0
- package/preset/odai/runtime/index.d.mts +8 -0
- package/preset/odai/runtime/index.d.mts.map +1 -0
- package/preset/odai/runtime/index.mjs +190 -2473
- package/preset/odai/runtime/index.mjs.map +1 -0
- package/preset/odai/runtime/lifecycle-runtime.d.mts +83 -0
- package/preset/odai/runtime/lifecycle-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/lifecycle-runtime.mjs +1140 -0
- package/preset/odai/runtime/lifecycle-runtime.mjs.map +1 -0
- package/preset/odai/runtime/model-route.d.mts +22 -0
- package/preset/odai/runtime/model-route.d.mts.map +1 -0
- package/preset/odai/runtime/model-route.mjs +68 -60
- package/preset/odai/runtime/model-route.mjs.map +1 -0
- package/preset/odai/runtime/output-config.d.mts +54 -0
- package/preset/odai/runtime/output-config.d.mts.map +1 -0
- package/preset/odai/runtime/output-config.mjs +289 -315
- package/preset/odai/runtime/output-config.mjs.map +1 -0
- package/preset/odai/runtime/output-policy-state.d.mts +3 -0
- package/preset/odai/runtime/output-policy-state.d.mts.map +1 -0
- package/preset/odai/runtime/output-policy-state.mjs +41 -29
- package/preset/odai/runtime/output-policy-state.mjs.map +1 -0
- package/preset/odai/runtime/prompt-runtime.d.mts +55 -0
- package/preset/odai/runtime/prompt-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/prompt-runtime.mjs +303 -0
- package/preset/odai/runtime/prompt-runtime.mjs.map +1 -0
- package/preset/odai/runtime/research-packet.d.mts +30 -0
- package/preset/odai/runtime/research-packet.d.mts.map +1 -0
- package/preset/odai/runtime/research-packet.mjs +116 -117
- package/preset/odai/runtime/research-packet.mjs.map +1 -0
- package/preset/odai/runtime/responsibility-gap.d.mts +26 -0
- package/preset/odai/runtime/responsibility-gap.d.mts.map +1 -0
- package/preset/odai/runtime/responsibility-gap.mjs +93 -85
- package/preset/odai/runtime/responsibility-gap.mjs.map +1 -0
- package/preset/odai/runtime/responsibility-scope.d.mts +69 -0
- package/preset/odai/runtime/responsibility-scope.d.mts.map +1 -0
- package/preset/odai/runtime/responsibility-scope.mjs +199 -171
- package/preset/odai/runtime/responsibility-scope.mjs.map +1 -0
- package/preset/odai/runtime/role-overlays.d.mts +5 -0
- package/preset/odai/runtime/role-overlays.d.mts.map +1 -0
- package/preset/odai/runtime/role-overlays.mjs +15 -14
- package/preset/odai/runtime/role-overlays.mjs.map +1 -0
- package/preset/odai/runtime/route-card.d.mts +42 -0
- package/preset/odai/runtime/route-card.d.mts.map +1 -0
- package/preset/odai/runtime/route-card.mjs +158 -146
- package/preset/odai/runtime/route-card.mjs.map +1 -0
- package/preset/odai/runtime/router.d.mts +80 -0
- package/preset/odai/runtime/router.d.mts.map +1 -0
- package/preset/odai/runtime/router.mjs +509 -559
- package/preset/odai/runtime/router.mjs.map +1 -0
- package/preset/odai/runtime/routing-config.d.mts +76 -0
- package/preset/odai/runtime/routing-config.d.mts.map +1 -0
- package/preset/odai/runtime/routing-config.mjs +373 -438
- package/preset/odai/runtime/routing-config.mjs.map +1 -0
- package/preset/odai/runtime/routing-context.d.mts +64 -0
- package/preset/odai/runtime/routing-context.d.mts.map +1 -0
- package/preset/odai/runtime/routing-context.mjs +398 -277
- package/preset/odai/runtime/routing-context.mjs.map +1 -0
- package/preset/odai/runtime/runtime-config.d.mts +24 -0
- package/preset/odai/runtime/runtime-config.d.mts.map +1 -0
- package/preset/odai/runtime/runtime-config.mjs +181 -0
- package/preset/odai/runtime/runtime-config.mjs.map +1 -0
- package/preset/odai/runtime/runtime-support.d.mts +91 -0
- package/preset/odai/runtime/runtime-support.d.mts.map +1 -0
- package/preset/odai/runtime/runtime-support.mjs +371 -0
- package/preset/odai/runtime/runtime-support.mjs.map +1 -0
- package/preset/odai/runtime/runtime-types.d.mts +237 -0
- package/preset/odai/runtime/runtime-types.d.mts.map +1 -0
- package/preset/odai/runtime/runtime-types.mjs +4 -0
- package/preset/odai/runtime/runtime-types.mjs.map +1 -0
- package/preset/odai/runtime/semantic-memory-store.d.mts +110 -0
- package/preset/odai/runtime/semantic-memory-store.d.mts.map +1 -0
- package/preset/odai/runtime/semantic-memory-store.mjs +271 -385
- package/preset/odai/runtime/semantic-memory-store.mjs.map +1 -0
- package/preset/odai/runtime/semantic-memory.d.mts +88 -0
- package/preset/odai/runtime/semantic-memory.d.mts.map +1 -0
- package/preset/odai/runtime/semantic-memory.mjs +790 -750
- package/preset/odai/runtime/semantic-memory.mjs.map +1 -0
- package/preset/odai/runtime/session-compat.d.mts +31 -0
- package/preset/odai/runtime/session-compat.d.mts.map +1 -0
- package/preset/odai/runtime/session-compat.mjs +301 -328
- package/preset/odai/runtime/session-compat.mjs.map +1 -0
- package/preset/odai/runtime/session-evidence.d.mts +25 -0
- package/preset/odai/runtime/session-evidence.d.mts.map +1 -0
- package/preset/odai/runtime/session-evidence.mjs +309 -287
- package/preset/odai/runtime/session-evidence.mjs.map +1 -0
- package/preset/odai/runtime/skill-bundle.d.mts +53 -0
- package/preset/odai/runtime/skill-bundle.d.mts.map +1 -0
- package/preset/odai/runtime/skill-bundle.mjs +286 -276
- package/preset/odai/runtime/skill-bundle.mjs.map +1 -0
- package/preset/odai/runtime/skill-evolution.d.mts +112 -0
- package/preset/odai/runtime/skill-evolution.d.mts.map +1 -0
- package/preset/odai/runtime/skill-evolution.mjs +1287 -1261
- package/preset/odai/runtime/skill-evolution.mjs.map +1 -0
- package/preset/odai/runtime/skill-selection-state.d.mts +5 -0
- package/preset/odai/runtime/skill-selection-state.d.mts.map +1 -0
- package/preset/odai/runtime/skill-selection-state.mjs +59 -43
- package/preset/odai/runtime/skill-selection-state.mjs.map +1 -0
- package/preset/odai/runtime/skill-selector.d.mts +28 -0
- package/preset/odai/runtime/skill-selector.d.mts.map +1 -0
- package/preset/odai/runtime/skill-selector.mjs +100 -109
- package/preset/odai/runtime/skill-selector.mjs.map +1 -0
- package/preset/odai/runtime/skill-source-config.d.mts +32 -0
- package/preset/odai/runtime/skill-source-config.d.mts.map +1 -0
- package/preset/odai/runtime/skill-source-config.mjs +200 -210
- package/preset/odai/runtime/skill-source-config.mjs.map +1 -0
- package/preset/odai/runtime/store-lock.d.mts +2 -0
- package/preset/odai/runtime/store-lock.d.mts.map +1 -0
- package/preset/odai/runtime/store-lock.mjs +92 -87
- package/preset/odai/runtime/store-lock.mjs.map +1 -0
- package/preset/odai/runtime/tool-runtime.d.mts +43 -0
- package/preset/odai/runtime/tool-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/tool-runtime.mjs +221 -0
- package/preset/odai/runtime/tool-runtime.mjs.map +1 -0
- package/bin/odai-dsh-agent.mjs +0 -108
- package/scripts/verify-agent-load.mjs +0 -260
- package/src/dsh-version.mjs +0 -24
- package/src/installer.mjs +0 -385
|
@@ -1,683 +1,633 @@
|
|
|
1
|
+
import { isUnknownRecord } from "./runtime-types.mjs";
|
|
2
|
+
function isContinuationRole(value) {
|
|
3
|
+
return value === "planner" || value === "executor" || value === "frontend";
|
|
4
|
+
}
|
|
1
5
|
export const HIGH_IMPACT_PLANNER_REASON = "PLANNER_UNVERIFIED_HIGH_IMPACT_CHANGE";
|
|
2
6
|
export const RESEARCHER_EVIDENCE_REASON = "RESEARCHER_MULTI_SOURCE_DECISION_EVIDENCE";
|
|
3
7
|
export const FRONTEND_SPECIALIST_REASON = "FRONTEND_SUBSTANTIAL_INTERFACE_WORK";
|
|
4
8
|
export const EXECUTOR_ROUTE_CARD_REASON = "EXECUTOR_FROZEN_ROUTE_NET_BENEFIT";
|
|
5
9
|
export const OUTPUT_LIMIT_CONTINUATION_REASON = "RESPONSIBILITY_OUTPUT_LIMIT_CONTINUATION";
|
|
6
|
-
|
|
7
10
|
const RESPONSIBILITY_LABELS = Object.freeze({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
researcher: "多源事实调查",
|
|
12
|
+
planner: "规划",
|
|
13
|
+
executor: "执行",
|
|
14
|
+
reviewer: "验收",
|
|
15
|
+
frontend: "前端设计与制作",
|
|
13
16
|
});
|
|
14
|
-
|
|
15
17
|
const PLANNER_PATTERNS = [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
];
|
|
25
|
-
|
|
18
|
+
/独立(?:判断|规划|分析|决定|决策)/iu,
|
|
19
|
+
/比较(?:一下)?(?:方案|路线|架构)/iu,
|
|
20
|
+
/架构选型/iu,
|
|
21
|
+
/先(?:判断|规划)(?:路线|方案)/iu,
|
|
22
|
+
/second opinion (?:on|for) (?:the )?(?:plan|approach|architecture)/iu,
|
|
23
|
+
/compare (?:the )?(?:approaches|options|architectures)/iu,
|
|
24
|
+
/architecture decision/iu,
|
|
25
|
+
/(?:independently decide|independent decision)/iu,
|
|
26
|
+
];
|
|
26
27
|
const PLANNER_META_PATTERNS = [
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
/(?:你|是否|有没有|有没).{0,12}(?:规划|计划)(?:了|过|吗|没有)/iu,
|
|
29
|
+
/(?:did you|have you).{0,24}\bplan(?:ned|ning)?\b/iu,
|
|
29
30
|
];
|
|
30
|
-
|
|
31
31
|
const REVIEWER_PATTERNS = [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
];
|
|
39
|
-
|
|
32
|
+
/独立(?:审查|复核|评审)/iu,
|
|
33
|
+
/(?:代码|安全|变更)(?:审查|复核|评审)/iu,
|
|
34
|
+
/code review/iu,
|
|
35
|
+
/security review/iu,
|
|
36
|
+
/independent review/iu,
|
|
37
|
+
/challenge (?:the )?(?:plan|implementation|result)/iu,
|
|
38
|
+
];
|
|
40
39
|
const RISK_PATTERNS = [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
/(?:高风险|安全|权限|删除|迁移|发布|生产环境)/iu,
|
|
41
|
+
/(?:支付|付款|结算|扣款|退款|订单)[^。!?\n]{0,60}(?:提供方|服务|接口|请求|结果|状态|超时|重试|金额|交易|配置|回调|不稳定)/iu,
|
|
42
|
+
/(?:high[- ]risk|security|permission|delete|migration|production)/iu,
|
|
43
|
+
/(?:checkout|payment|billing|charge|refund)[^.!?\n]{0,80}(?:provider|service|request|result|status|timeout|retry|transaction|configuration|unstable|fail|超时|重试|不稳定)/iu,
|
|
45
44
|
];
|
|
46
|
-
|
|
47
45
|
const UNVERIFIED_CAUSAL_PATTERNS = [
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
/(?:我看|看起来|看来|估计|大概|八成|明显|肯定)(?:就)?是/iu,
|
|
47
|
+
/(?:问题|原因|根因)(?:应该|可能|大概|估计)(?:就)?在/iu,
|
|
48
|
+
/\b(?:it\s+)?(?:looks?|seems)\s+like\b/iu,
|
|
49
|
+
/\b(?:i think|probably|apparently|clearly|obviously)\b[^.!?\n]{0,80}\b(?:is|are|because|caused by|comes from)\b/iu,
|
|
52
50
|
];
|
|
53
|
-
|
|
54
51
|
const CONCRETE_CHANGE_PATTERNS = [
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
/把[^。!?\n]{1,120}(?:降到|提到|提高到|改成|设为|设置为|切到|换成|开启|关闭|删除|清空|迁移到|发布到|上线)/iu,
|
|
53
|
+
/(?:降低|提高|增加|减少|修改|设置|开启|关闭|删除|清空|迁移|发布|上线)[^。!?\n]{0,80}(?:\d|配置|超时|重试|权限|数据|服务)/iu,
|
|
54
|
+
/\b(?:set|change|reduce|lower|increase|raise|disable|enable|delete|drop|clear|migrate|deploy|release)\b[^.!?\n]{0,100}\b(?:to|from|timeout|retries|permission|data|service|production)\b/iu,
|
|
58
55
|
];
|
|
59
|
-
|
|
60
56
|
const SPECIFIC_PARAMETER_PATTERNS = [
|
|
61
|
-
|
|
57
|
+
/\d+(?:\.\d+)?\s*(?:毫秒|秒|分钟|小时|次|%|%|ms|sec(?:ond)?s?|min(?:ute)?s?|hours?|retries?|mb|gb)/iu,
|
|
62
58
|
];
|
|
63
|
-
|
|
64
59
|
const URGENCY_PATTERNS = [
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
/(?:先止血|立即|马上|赶紧|紧急|热修)/iu,
|
|
61
|
+
/\b(?:hotfix|immediately|right away|stop the bleeding)\b/iu,
|
|
67
62
|
];
|
|
68
|
-
|
|
69
63
|
const IRREVERSIBLE_ACTION_PATTERNS = [
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
/(?:删除|清空|迁移|发布|上线|关闭)/iu,
|
|
65
|
+
/\b(?:delete|drop|clear|migrate|deploy|release|disable)\b/iu,
|
|
72
66
|
];
|
|
73
|
-
|
|
74
67
|
const CONTINUATION_PATTERNS = [
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
/(?:继续|接着|进一步|深入|再(?:判断|分析|评估|检查|处理)|按(?:照)?(?:刚才|上面|上述|前面|这个|该)|那就|就按|能做不|能不能做|可以做不|可以做吗)/iu,
|
|
69
|
+
/\b(?:continue|proceed|go ahead|follow up|dig deeper|based on (?:that|the previous|the above)|can you (?:do|handle|implement) (?:it|that))\b/iu,
|
|
77
70
|
];
|
|
78
|
-
|
|
79
71
|
const PURE_RESPONSIBILITY_CONTINUATION_PATTERNS = [
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
/^\s*(?:请)?(?:继续|接着|接下去|续上|恢复)(?:(?:执行|完成|处理|做|推进|设计|分析|规划))?(?:(?:刚才|之前|上次|这个|该|原来)的?)?(?:任务|工作|实现|方案|设计|分析|规划)?(?:下去|完成|吧)?[。!!]?\s*$/iu,
|
|
73
|
+
/^\s*(?:please\s+)?(?:continue|go on|resume|carry on|keep going)(?:\s+(?:the\s+)?(?:previous|interrupted|same)?\s*(?:task|work|implementation|plan|design|analysis))?[.!]?\s*$/iu,
|
|
82
74
|
];
|
|
83
75
|
const OUTPUT_LIMIT_DIAGNOSTIC_PATTERNS = [
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
/(?:截断|断掉|中断|输出[^。!?\n]{0,12}(?:上限|预算)|(?:上限|预算)[^。!?\n]{0,12}输出|max\s*[_-]?\s*tokens?)/iu,
|
|
77
|
+
/(?:token|令牌)[^。!?\n]{0,16}(?:limit|budget|上限|预算|截断)/iu,
|
|
78
|
+
/(?:为什么|为何|怎么)[^。!?\n]{0,20}(?:停|断|中断|没继续|不继续)/iu,
|
|
87
79
|
];
|
|
88
|
-
|
|
89
80
|
const LOW_RISK_TRANSFORM_PATTERNS = [
|
|
90
|
-
|
|
91
|
-
|
|
81
|
+
/(?:重述|总结|概括|压缩|翻译|改写|润色|格式化|解释(?:一下)?)/iu,
|
|
82
|
+
/\b(?:restate|summari[sz]e|translate|shorten|rewrite|format|explain)\b/iu,
|
|
92
83
|
];
|
|
93
|
-
|
|
94
84
|
const EXPLICIT_EXECUTION_CONTINUATION_PATTERNS = [
|
|
95
|
-
|
|
96
|
-
|
|
85
|
+
/(?:继续|接着|就按|按(?:照)?(?:(?:这个|该|上述|上面|前面|刚才)的?)?(?:方案|计划|卡片))/iu,
|
|
86
|
+
/\b(?:continue|proceed|go ahead|follow the plan)\b/iu,
|
|
97
87
|
];
|
|
98
88
|
const IMPLEMENTATION_AUTHORIZATION_PATTERNS = [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
/(?:做(?:完|好|掉|这个|这项|这次|一个)|实现|修复|完成|落地|开发|添加|新增|替换|删除|执行|全都做好)/iu,
|
|
90
|
+
/(?:请|麻烦|直接|开始|继续)(?:帮我)?(?:处理|修改|更新)|帮我(?:处理|修改|更新)|需要(?:处理|修改|更新)|可以(?:帮我)?(?:处理|修改|更新)|^(?:处理|修改|更新)(?:一下|这个|该|文件|代码|配置|依赖|问题|功能|实现|文档|测试)/iu,
|
|
91
|
+
/\b(?:do it|implement|fix|complete|build|add|replace|remove|execute|ship)\b/iu,
|
|
92
|
+
/^(?:please\s+)?(?:(?:change|modify)\b|update\b(?!\s+(?:me|us|them|everyone|the team)\b))|\b(?:please|can you|could you|would you|go ahead and|start to|continue to)\s+(?:(?:change|modify)\b|update\b(?!\s+(?:me|us|them|everyone|the team)\b))|\bi (?:need|want) you to\s+(?:(?:change|modify)\b|update\b(?!\s+(?:me|us|them|everyone|the team)\b))/iu,
|
|
103
93
|
];
|
|
104
94
|
const PLAN_ONLY_PATTERNS = [
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
95
|
+
/(?:只|仅).{0,16}(?:规划|计划|分析|评估|建议|方案|审查|复核|评审|检查)/iu,
|
|
96
|
+
/(?:先|帮我)(?:规划|计划|分析|评估)(?:一下)?[^。!?\n]{0,40}(?:$|[。!?])/iu,
|
|
97
|
+
/^\s*(?:请)?(?:规划|计划|分析|评估|建议|审查|复核|评审|检查)/iu,
|
|
98
|
+
/^\s*(?:请)?(?:列一下|列出|整理(?:一份)?|给我(?:一份)?)[^。!?\n]{0,64}(?:地方|清单|列表|说明|建议|方案|示例|影响|步骤)(?:$|[。!?])/iu,
|
|
99
|
+
/\b(?:review|audit|inspect)\s+only\b/iu,
|
|
100
|
+
/\b(?:just|only)\s+(?:plan|analy[sz]e|assess|evaluate|review|audit|inspect|recommend|explain|describe|outline|list)\b/iu,
|
|
101
|
+
/^\s*(?:please\s+)?(?:plan|analy[sz]e|assess|evaluate|review|audit|inspect|recommend|explain|describe|outline|list)\b/iu,
|
|
112
102
|
];
|
|
113
103
|
const PLAN_THEN_IMPLEMENT_PATTERNS = [
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
104
|
+
/(?:规划|计划|分析|评估|建议|审查|复核|评审|检查)[^。!?\n]{0,48}(?:然后|再|之后|接着|并(?:且)?)[^。!?\n]{0,24}(?:实现|修复|完成|落地|开发|添加|新增|修改|更新(?![^。!?\n]{0,8}(?:我|我们|团队|进展|结果|情况|发现|消息|状态))|替换|删除|执行)/iu,
|
|
105
|
+
/(?:列一下|列出|整理(?:一份)?|给我(?:一份)?)[^。!?\n]{0,64}(?:然后|再|之后|接着|并(?:且)?)[^。!?\n]{0,24}(?:实现|修复|完成|落地|开发|添加|新增|修改|更新|替换|删除|执行)/iu,
|
|
106
|
+
/\b(?:plan|analy[sz]e|assess|evaluate|review|audit|inspect|recommend|explain|describe|outline|list)\b[^.!?\n]{0,64}\b(?:then|and(?: then)?|after that)\b[^.!?\n]{0,24}\b(?:implement|fix|complete|build|add|change|update(?!\s+(?:me|us|them|everyone|the team)\b)|modify|replace|remove|execute|ship)\b/iu,
|
|
117
107
|
];
|
|
118
108
|
const STATUS_UPDATE_PATTERNS = [
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
109
|
+
/(?:更新|同步)[^。!?\n]{0,24}(?:进展|结果|情况|发现|消息|状态)/iu,
|
|
110
|
+
/\bupdate\b[^.!?\n]{1,48}\b(?:on|about|regarding)\b/iu,
|
|
111
|
+
/\bupdate\b[^.!?\n]{1,48}\bwith\s+(?:the\s+)?(?:findings|progress|results|status|details|news|outcome)\b/iu,
|
|
122
112
|
];
|
|
123
113
|
const UNAMBIGUOUS_DELIVERY_PATTERNS = [
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
114
|
+
/(?:^|[,;。]|然后|再|之后|接着|并(?:且)?|请|帮我)(?:做(?:完|好|掉)|实现|修复|完成|落地|开发|添加|新增|修改|替换|删除|执行)/iu,
|
|
115
|
+
/更新(?:代码|项目|依赖|包|清单|文档|测试|配置|文件|运行时|服务|应用|界面|数据库|架构)/iu,
|
|
116
|
+
/\b(?:do it|implement|execute|ship)\b/iu,
|
|
117
|
+
/(?:^|\b(?:then|and|to|please)\s+)\b(?:fix|complete|build|add|change|modify|replace|remove)\b/iu,
|
|
118
|
+
/\bupdate\s+(?:the\s+)?(?:code|project|dependencies?|packages?|manifest|docs?|documentation|tests?|config(?:uration)?|files?|runtime|services?|app(?:lication)?|ui|interface|schema|database|architecture)\b/iu,
|
|
129
119
|
];
|
|
130
120
|
const NON_IMPLEMENTATION_QUERY_PATTERNS = [
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
121
|
+
/(?:有什么|有何|哪些|是什么|为何|为什么|怎么样|怎么看|发生了什么|有变化吗|影响(?:是|有)?什么)[^。!?\n]*[??]?$/iu,
|
|
122
|
+
/^\s*(?:what|why|how)\b[^.!?\n]*[?]\s*$/iu,
|
|
123
|
+
/\b(?:what changed|what changes|what impact|which changes|difference between)\b[^.!?\n]*[?]?$/iu,
|
|
134
124
|
];
|
|
135
125
|
const NO_IMPLEMENTATION_PATTERNS = [
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
126
|
+
/(?:不要|别|请勿|禁止|无需|不用|不需要|不能)[^。!?\n]{0,28}(?:改|修改|编辑|写入|实现|执行|落地|动文件|动代码)/iu,
|
|
127
|
+
/\b(?:do not|don't|never|without)\b[^.!?\n]{0,48}\b(?:implement|modify|edit|change|write|execute|apply|make changes?)\b/iu,
|
|
128
|
+
/\b(?:plan|analyze|assess|evaluate|recommend)(?: only)?\b[^.!?]{0,30}\b(?:do not|don't|without) (?:implementing|changes?)\b/iu,
|
|
139
129
|
];
|
|
140
130
|
const GLOBAL_NO_EDIT_PATTERNS = [
|
|
141
|
-
|
|
142
|
-
|
|
131
|
+
/(?:不要|别|请勿|禁止)[^,;。!?\n]{0,12}(?:改|修改|编辑|写入)[^,;。!?\n]{0,12}(?:任何|全部|所有|整个)[^,;。!?\n]{0,12}(?:文件|代码|内容|实现|东西)/iu,
|
|
132
|
+
/\b(?:do not|don't|never)\b[^,;.!?\n]{0,12}\b(?:modify|edit|change|write)\b[^,;.!?\n]{0,16}\b(?:anything|any (?:files?|code|changes?)|all (?:files?|code|changes?)|the (?:whole|entire) codebase)\b/iu,
|
|
143
133
|
];
|
|
144
134
|
const SCOPED_NO_EDIT_WITH_EXECUTION_PATTERNS = [
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
/(?:不要|别|请勿)[^,;。!?\n]{0,12}(?:改|修改|编辑|写入)(?![^,;。!?\n]{0,12}(?:任何|全部|所有|整个))[^,;。!?\n]{1,28}[,;。](?![^,;。!?\n]{0,20}(?:不要|别|请勿|禁止|无需|不用|不需要|不能))[ \t]*[^,;。!?\n]{0,20}(?:实现|修复|修改|更新|执行|落地)/iu,
|
|
136
|
+
/\b(?:do not|don't|never)\b[^,;.!?\n]{0,12}\b(?:modify|edit|change|write)\b(?![^,;.!?\n]{0,16}\b(?:anything|any (?:files?|code|changes?)|all (?:files?|code|changes?)|the (?:whole|entire) codebase)\b)[^,;.!?\n]{1,36}[,;.](?![^,;.!?\n]{0,24}\b(?:do not|don't|never|no need to|without|skip)\b)\s*[^,;.!?\n]{0,24}\b(?:implement|fix|change|update|execute|apply)\b/iu,
|
|
147
137
|
];
|
|
148
138
|
const EXECUTION_ACTION_PATTERNS = [
|
|
149
|
-
|
|
150
|
-
|
|
139
|
+
/(?:开始|执行|实施|落实|动手)/iu,
|
|
140
|
+
/\b(?:start|execute|implement|apply)\b/iu,
|
|
151
141
|
];
|
|
152
142
|
const ROUTE_CARD_REFERENCE_PATTERNS = [
|
|
153
|
-
|
|
154
|
-
|
|
143
|
+
/(?:(?:这个|该|上述|上面|前面|刚才)的?(?:方案|计划|卡片|实现|改动|工作))/iu,
|
|
144
|
+
/\b(?:(?:this|that|the|above|previous)\s+(?:plan|proposal|route card|implementation|change)|(?:it|that))\b/iu,
|
|
155
145
|
];
|
|
156
146
|
const NEW_TASK_PATTERNS = [
|
|
157
|
-
|
|
158
|
-
|
|
147
|
+
/(?:另一个|另一项|另一件|另外(?:一个|一项|一件)|新(?:的)?(?:问题|任务|需求|工作))/iu,
|
|
148
|
+
/\b(?:another|(?:a )?new|different|separate)\s+(?:task|issue|problem|request|change|project)\b/iu,
|
|
149
|
+
];
|
|
150
|
+
const REVIEWER_PENDING_CONTEXT_PATTERNS = [
|
|
151
|
+
/(?:验收条件|证据包|前述|上述|刚才|之前|原任务)/iu,
|
|
152
|
+
/(?:补充|更新|新增|修改|还有|同时)[^。!?\n]{0,28}(?:验收|审查|复核|证据|测试|差异|改动)/iu,
|
|
153
|
+
/\b(?:A\d+|acceptance criteria|evidence packet|previous|above|same task)\b/iu,
|
|
154
|
+
/\b(?:add|update|clarify|also|additionally)\b[^.!?\n]{0,36}\b(?:acceptance|review|evidence|tests?|diff|patch)\b/iu,
|
|
159
155
|
];
|
|
160
|
-
|
|
161
156
|
const FRONTEND_SCOPE_PATTERNS = [
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
/(?:前端|界面|页面|网页|网站|着陆页|应用界面|仪表盘|控制台|组件|交互界面|移动端|桌面端|游戏界面|3D场景)/iu,
|
|
158
|
+
/\b(?:front[- ]?end|ui|ux|interface|web(?:site| app)?|landing page|page|dashboard|component|mobile|desktop|game ui|3d scene)\b/iu,
|
|
164
159
|
];
|
|
165
160
|
const FRONTEND_DELIVERY_PATTERNS = [
|
|
166
|
-
|
|
167
|
-
|
|
161
|
+
/(?:设计|制作|实现|开发|构建|创建|搭建|改版|重做|重构|优化|美化|修复)/iu,
|
|
162
|
+
/\b(?:design|build|implement|develop|create|craft|redesign|revamp|rework|optimi[sz]e|fix)\b/iu,
|
|
168
163
|
];
|
|
169
164
|
const FRONTEND_STRONG_WORK_PATTERNS = [
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
/(?:从零|新建|新做|整页|整站|整体改版|完整界面|设计并实现|重新设计|重做|改版|搭建)/iu,
|
|
166
|
+
/\b(?:build|create|design and implement|redesign|revamp|rebuild)\b[^.!?\n]{0,60}\b(?:ui|interface|page|website|web app|dashboard|component|game)\b/iu,
|
|
172
167
|
];
|
|
173
168
|
const FRONTEND_SURFACE_PATTERNS = [
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
169
|
+
/登录(?:页|页面)/iu,
|
|
170
|
+
/(?:登录后)?首页/iu,
|
|
171
|
+
/(?:个人空间|个人中心|用户中心|个人主页)/iu,
|
|
172
|
+
/(?:注册|设置|搜索|列表|详情|结算|支付)(?:页|页面)/iu,
|
|
173
|
+
/\b(?:login page|home page|profile|personal space|settings page|search page|list page|detail page|checkout page)\b/iu,
|
|
179
174
|
];
|
|
180
175
|
const FRONTEND_NON_UI_PATTERNS = [
|
|
181
|
-
|
|
182
|
-
|
|
176
|
+
/(?:API|接口)(?:调用|请求|响应|超时|缓存|鉴权|数据|字段|契约)/iu,
|
|
177
|
+
/\b(?:api|endpoint|backend|server-side)\b/iu,
|
|
183
178
|
];
|
|
184
179
|
const FRONTEND_UI_PRODUCTION_PATTERNS = [
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
/(?:UI|UX|用户界面|界面介绍|布局|样式|排版|配色|交互|视觉|响应式|移动端|桌面端|截图|浏览器验收)/iu,
|
|
181
|
+
/\b(?:ui|ux|interface|layout|styling|typography|interaction|visual|responsive|mobile|desktop|screenshot|browser acceptance)\b/iu,
|
|
187
182
|
];
|
|
188
183
|
const FRONTEND_EXPLICIT_SPECIALIST_PATTERNS = [
|
|
189
|
-
|
|
190
|
-
|
|
184
|
+
/(?:交给|使用|用)[^。!?\n]{0,30}(?:前端|UI|UX)(?:专长|专家|模型)/iu,
|
|
185
|
+
/\b(?:use|with|via)\b[^.!?\n]{0,30}\b(?:front[- ]?end|ui|ux) (?:specialist|expert|model)\b/iu,
|
|
191
186
|
];
|
|
192
187
|
const FRONTEND_AXIS_PATTERNS = Object.freeze({
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
responsive: [/(?:响应式|移动端|桌面端|多端|窄屏|宽屏|视口)/iu, /\b(?:responsive|mobile|desktop|viewport|breakpoint)\b/iu],
|
|
189
|
+
interaction: [/(?:交互|动效|动画|拖拽|手势|状态流转|多状态)/iu, /\b(?:interaction|animation|motion|drag|gesture|state flow|multiple states)\b/iu],
|
|
190
|
+
visual: [/(?:视觉|品牌|排版|配色|设计系统|素材|图片|图标|3D|游戏界面)/iu, /\b(?:visual|brand|typography|palette|design system|asset|image|icon|3d|game ui)\b/iu],
|
|
191
|
+
comprehension: [/(?:一眼(?:就)?(?:看懂|明白|理解)|做什么|首屏认知|价值表达|信息架构|界面介绍)/iu, /\b(?:understand at a glance|first-screen comprehension|value proposition|information architecture|what (?:it|the product) does)\b/iu],
|
|
192
|
+
acceptance: [/(?:截图|浏览器验收|视觉验收|无障碍|Playwright|真机)/iu, /\b(?:screenshot|browser acceptance|visual acceptance|accessibility|playwright|device testing)\b/iu],
|
|
198
193
|
});
|
|
199
|
-
|
|
200
194
|
function matchesAny(text, patterns) {
|
|
201
|
-
|
|
195
|
+
return patterns.some((pattern) => pattern.test(text));
|
|
202
196
|
}
|
|
203
|
-
|
|
204
197
|
function stripQuotedMaterial(text) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
198
|
+
return text
|
|
199
|
+
.replace(/```[\s\S]*?```/gu, " ")
|
|
200
|
+
.replace(/^\s*>.*$/gmu, " ")
|
|
201
|
+
.replace(/`[^`\n]*`/gu, " ")
|
|
202
|
+
.replace(/“[^”\n]*”|‘[^’\n]*’|「[^」\n]*」|『[^』\n]*』|《[^》\n]*》|"[^"\n]*"/gu, " ");
|
|
210
203
|
}
|
|
211
|
-
|
|
212
204
|
export function classifyResponsibilityInterruptionText(text) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
205
|
+
const explicit = stripQuotedMaterial(String(text ?? "")).trim();
|
|
206
|
+
if (!explicit)
|
|
207
|
+
return "clear";
|
|
208
|
+
if (matchesAny(explicit, PURE_RESPONSIBILITY_CONTINUATION_PATTERNS))
|
|
209
|
+
return "continue";
|
|
210
|
+
if (matchesAny(explicit, OUTPUT_LIMIT_DIAGNOSTIC_PATTERNS))
|
|
211
|
+
return "preserve";
|
|
212
|
+
return "clear";
|
|
213
|
+
}
|
|
214
|
+
export function classifyPendingReviewerText(text) {
|
|
215
|
+
const explicit = stripQuotedMaterial(String(text ?? "")).trim();
|
|
216
|
+
if (!explicit)
|
|
217
|
+
return "dormant";
|
|
218
|
+
if (matchesAny(explicit, NEW_TASK_PATTERNS))
|
|
219
|
+
return "supersede";
|
|
220
|
+
if (matchesAny(explicit, PURE_RESPONSIBILITY_CONTINUATION_PATTERNS)
|
|
221
|
+
|| matchesAny(explicit, CONTINUATION_PATTERNS)
|
|
222
|
+
|| matchesAny(explicit, REVIEWER_PENDING_CONTEXT_PATTERNS))
|
|
223
|
+
return "continue";
|
|
224
|
+
return "dormant";
|
|
218
225
|
}
|
|
219
|
-
|
|
220
226
|
function isExecutionContinuation(text) {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
227
|
+
if (matchesAny(text, NEW_TASK_PATTERNS))
|
|
228
|
+
return false;
|
|
229
|
+
if (matchesAny(text, EXPLICIT_EXECUTION_CONTINUATION_PATTERNS))
|
|
230
|
+
return true;
|
|
231
|
+
return matchesAny(text, EXECUTION_ACTION_PATTERNS)
|
|
232
|
+
&& matchesAny(text, ROUTE_CARD_REFERENCE_PATTERNS);
|
|
225
233
|
}
|
|
226
|
-
|
|
227
234
|
export function classifyImplementationAuthorization(text) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
235
|
+
const explicit = stripQuotedMaterial(String(text ?? "")).trim();
|
|
236
|
+
if (!explicit)
|
|
237
|
+
return Object.freeze({ status: "unknown" });
|
|
238
|
+
if (matchesAny(explicit, GLOBAL_NO_EDIT_PATTERNS))
|
|
239
|
+
return Object.freeze({ status: "plan-only" });
|
|
240
|
+
if (matchesAny(explicit, SCOPED_NO_EDIT_WITH_EXECUTION_PATTERNS))
|
|
241
|
+
return Object.freeze({ status: "authorized" });
|
|
242
|
+
if (matchesAny(explicit, NO_IMPLEMENTATION_PATTERNS))
|
|
243
|
+
return Object.freeze({ status: "plan-only" });
|
|
244
|
+
if (matchesAny(explicit, STATUS_UPDATE_PATTERNS)
|
|
245
|
+
&& !matchesAny(explicit, UNAMBIGUOUS_DELIVERY_PATTERNS)
|
|
246
|
+
&& !matchesAny(explicit, CONCRETE_CHANGE_PATTERNS)) {
|
|
247
|
+
return Object.freeze({ status: matchesAny(explicit, PLAN_ONLY_PATTERNS) ? "plan-only" : "unknown" });
|
|
248
|
+
}
|
|
249
|
+
if (isExecutionContinuation(explicit) || matchesAny(explicit, PLAN_THEN_IMPLEMENT_PATTERNS)) {
|
|
250
|
+
return Object.freeze({ status: "authorized" });
|
|
251
|
+
}
|
|
252
|
+
if (matchesAny(explicit, PLAN_ONLY_PATTERNS))
|
|
253
|
+
return Object.freeze({ status: "plan-only" });
|
|
254
|
+
if (matchesAny(explicit, NON_IMPLEMENTATION_QUERY_PATTERNS))
|
|
255
|
+
return Object.freeze({ status: "unknown" });
|
|
256
|
+
if (matchesAny(explicit, IMPLEMENTATION_AUTHORIZATION_PATTERNS)
|
|
257
|
+
|| matchesAny(explicit, CONCRETE_CHANGE_PATTERNS)) {
|
|
258
|
+
return Object.freeze({ status: "authorized" });
|
|
259
|
+
}
|
|
260
|
+
return Object.freeze({ status: "unknown" });
|
|
248
261
|
}
|
|
249
|
-
|
|
250
262
|
function hasContextualPlannerGap(text) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
263
|
+
return matchesAny(text, RISK_PATTERNS)
|
|
264
|
+
&& matchesAny(text, UNVERIFIED_CAUSAL_PATTERNS)
|
|
265
|
+
&& matchesAny(text, CONCRETE_CHANGE_PATTERNS)
|
|
266
|
+
&& (matchesAny(text, SPECIFIC_PARAMETER_PATTERNS)
|
|
267
|
+
|| matchesAny(text, URGENCY_PATTERNS)
|
|
268
|
+
|| matchesAny(text, IRREVERSIBLE_ACTION_PATTERNS));
|
|
257
269
|
}
|
|
258
|
-
|
|
259
270
|
function isLowRiskTransform(text) {
|
|
260
|
-
|
|
271
|
+
return matchesAny(stripQuotedMaterial(text), LOW_RISK_TRANSFORM_PATTERNS);
|
|
261
272
|
}
|
|
262
|
-
|
|
263
273
|
function frontendSpecializationSignals(text) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
274
|
+
const explicit = matchesAny(text, FRONTEND_EXPLICIT_SPECIALIST_PATTERNS);
|
|
275
|
+
const surfaceCount = FRONTEND_SURFACE_PATTERNS.filter((pattern) => pattern.test(text)).length;
|
|
276
|
+
const explicitScope = matchesAny(text, FRONTEND_SCOPE_PATTERNS);
|
|
277
|
+
const scope = surfaceCount > 0 || explicitScope;
|
|
278
|
+
const delivery = matchesAny(text, FRONTEND_DELIVERY_PATTERNS);
|
|
279
|
+
const strongWork = matchesAny(text, FRONTEND_STRONG_WORK_PATTERNS);
|
|
280
|
+
const axes = Object.entries(FRONTEND_AXIS_PATTERNS)
|
|
281
|
+
.filter(([, patterns]) => matchesAny(text, patterns))
|
|
282
|
+
.map(([axis]) => axis);
|
|
283
|
+
const nonUiRequest = matchesAny(text, FRONTEND_NON_UI_PATTERNS)
|
|
284
|
+
&& !matchesAny(text, FRONTEND_UI_PRODUCTION_PATTERNS);
|
|
285
|
+
const specialistDepth = explicit
|
|
286
|
+
|| strongWork
|
|
287
|
+
|| axes.length >= 2
|
|
288
|
+
|| (surfaceCount >= 2 && (explicitScope || axes.length >= 1));
|
|
289
|
+
return Object.freeze({
|
|
290
|
+
explicit,
|
|
291
|
+
scope,
|
|
292
|
+
delivery,
|
|
293
|
+
strongWork,
|
|
294
|
+
nonUiRequest,
|
|
295
|
+
specialistDepth,
|
|
296
|
+
surfaceCount,
|
|
297
|
+
axes: Object.freeze(axes),
|
|
298
|
+
substantial: scope && delivery && specialistDepth && !nonUiRequest,
|
|
299
|
+
});
|
|
290
300
|
}
|
|
291
|
-
|
|
292
301
|
function frontendRouteSignals(frontend) {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
302
|
+
return [
|
|
303
|
+
...(frontend.scope ? ["frontend-interface-scope"] : []),
|
|
304
|
+
...(frontend.delivery ? ["frontend-delivery-request"] : []),
|
|
305
|
+
...(frontend.explicit ? ["explicit-frontend-specialist"] : []),
|
|
306
|
+
...(frontend.strongWork ? ["substantial-frontend-work"] : []),
|
|
307
|
+
...(frontend.surfaceCount >= 2 ? ["frontend-multi-surface"] : []),
|
|
308
|
+
...frontend.axes.map((axis) => `frontend-${axis}`),
|
|
309
|
+
];
|
|
301
310
|
}
|
|
302
|
-
|
|
303
311
|
function genuineUserText(message) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
const source = message?.source;
|
|
313
|
+
if (message?.role !== "user" || !isUnknownRecord(source) || source.kind !== "user" || !Array.isArray(message.content))
|
|
314
|
+
return "";
|
|
315
|
+
return message.content
|
|
316
|
+
.filter((block) => block?.type === "text" && typeof block.text === "string")
|
|
317
|
+
.map((block) => block.text)
|
|
318
|
+
.join("\n")
|
|
319
|
+
.trim();
|
|
310
320
|
}
|
|
311
|
-
|
|
312
321
|
function genuineUserTexts(messages, sessionEvents = []) {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
322
|
+
const candidates = [
|
|
323
|
+
...(Array.isArray(messages) ? [...messages].reverse() : []),
|
|
324
|
+
...(Array.isArray(sessionEvents)
|
|
325
|
+
? [...sessionEvents].reverse()
|
|
326
|
+
.filter((event) => event?.type === "user/message")
|
|
327
|
+
.map((event) => event.data)
|
|
328
|
+
: []),
|
|
329
|
+
];
|
|
330
|
+
const seen = new Set();
|
|
331
|
+
const texts = [];
|
|
332
|
+
for (const message of candidates) {
|
|
333
|
+
const text = genuineUserText(message);
|
|
334
|
+
if (!text || seen.has(text))
|
|
335
|
+
continue;
|
|
336
|
+
seen.add(text);
|
|
337
|
+
texts.push(text);
|
|
338
|
+
}
|
|
339
|
+
return texts;
|
|
330
340
|
}
|
|
331
|
-
|
|
332
341
|
function route(role, reasonCode, reason, signals, action = role === "controller" ? "direct" : "delegate", targetRole) {
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
+
return Object.freeze({
|
|
343
|
+
role,
|
|
344
|
+
mode: action,
|
|
345
|
+
action,
|
|
346
|
+
...(targetRole === undefined ? {} : { targetRole }),
|
|
347
|
+
reasonCode,
|
|
348
|
+
reason,
|
|
349
|
+
signals: Object.freeze([...new Set(signals)]),
|
|
350
|
+
});
|
|
342
351
|
}
|
|
343
|
-
|
|
344
352
|
export function decideResearchPrefetch(input = {}) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
"researcher",
|
|
353
|
-
RESEARCHER_EVIDENCE_REASON,
|
|
354
|
-
proposal.gap,
|
|
355
|
-
["evidence-grounded-responsibility-gap", `state:${proposal.stateDigest}`],
|
|
356
|
-
);
|
|
353
|
+
const text = typeof input.text === "string" ? input.text.trim() : "";
|
|
354
|
+
const explicitIntentText = stripQuotedMaterial(text);
|
|
355
|
+
const proposal = input.proposal?.responsibility === "researcher" ? input.proposal : undefined;
|
|
356
|
+
if (!proposal || !explicitIntentText || isLowRiskTransform(explicitIntentText)) {
|
|
357
|
+
return route("controller", "RESEARCHER_PREFETCH_NOT_NEEDED", "No evidence-grounded multi-source compression gap was proposed.", ["no-research-prefetch"]);
|
|
358
|
+
}
|
|
359
|
+
return route("researcher", RESEARCHER_EVIDENCE_REASON, proposal.gap, ["evidence-grounded-responsibility-gap", `state:${proposal.stateDigest}`]);
|
|
357
360
|
}
|
|
358
|
-
|
|
359
361
|
/**
|
|
360
362
|
* Choose the smallest useful odai role. Risk alone never creates another role.
|
|
361
363
|
* Executor routing requires a frozen route card and observable net benefit;
|
|
362
364
|
* those facts cannot be inferred from task prose.
|
|
363
365
|
*/
|
|
364
366
|
export function decideRoute(input = {}) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
signals.push("
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const frontendSignals = frontend.scope || frontend.explicit ? frontendRouteSignals(frontend) : [];
|
|
492
|
-
if (frontend.substantial && !isLowRiskTransform(explicitIntentText)) {
|
|
493
|
-
signals.push(...frontendSignals);
|
|
494
|
-
return route(
|
|
495
|
-
"controller",
|
|
496
|
-
FRONTEND_SPECIALIST_REASON,
|
|
497
|
-
"Substantial user-facing interface work can benefit from a configured frontend specialist without a child handoff.",
|
|
498
|
-
signals,
|
|
499
|
-
"upgrade",
|
|
500
|
-
"frontend",
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
signals.push(...frontendSignals, "no-independent-gap");
|
|
505
|
-
const direct = route(
|
|
506
|
-
"controller",
|
|
507
|
-
"DIRECT_DEFAULT_NO_INDEPENDENT_GAP",
|
|
508
|
-
"No evidence-grounded independent decision, execution, or acceptance gap was found.",
|
|
509
|
-
signals,
|
|
510
|
-
);
|
|
511
|
-
if (frontendSignals.length > 0) {
|
|
512
|
-
const lowRiskTransform = isLowRiskTransform(explicitIntentText);
|
|
513
|
-
considerations.push(Object.freeze({
|
|
514
|
-
role: "frontend",
|
|
515
|
-
match: "partial",
|
|
516
|
-
action: "skip",
|
|
517
|
-
reasonCode: frontend.nonUiRequest
|
|
518
|
-
? "FRONTEND_API_REQUEST"
|
|
519
|
-
: lowRiskTransform
|
|
520
|
-
? "FRONTEND_LOW_RISK_TRANSFORM"
|
|
521
|
-
: "FRONTEND_BELOW_SPECIALIST_THRESHOLD",
|
|
522
|
-
signals: Object.freeze(frontendSignals),
|
|
523
|
-
unmet: Object.freeze(frontend.nonUiRequest
|
|
524
|
-
? ["ui-production-request"]
|
|
525
|
-
: [
|
|
526
|
-
...(frontend.scope ? [] : ["interface-scope"]),
|
|
527
|
-
...(frontend.delivery ? [] : ["delivery-request"]),
|
|
528
|
-
...(frontend.specialistDepth ? [] : ["specialist-or-substantial-scope"]),
|
|
529
|
-
]),
|
|
530
|
-
}));
|
|
531
|
-
}
|
|
532
|
-
return considerations.length === 0
|
|
533
|
-
? direct
|
|
534
|
-
: Object.freeze({ ...direct, considerations: Object.freeze(considerations) });
|
|
367
|
+
const text = typeof input.text === "string" ? input.text.trim() : "";
|
|
368
|
+
const explicitIntentText = stripQuotedMaterial(text);
|
|
369
|
+
const proposal = input.proposal;
|
|
370
|
+
const signals = [];
|
|
371
|
+
const considerations = [];
|
|
372
|
+
const riskPresent = matchesAny(text, RISK_PATTERNS);
|
|
373
|
+
const unverifiedCausalClaim = matchesAny(text, UNVERIFIED_CAUSAL_PATTERNS);
|
|
374
|
+
const concreteChangeRequest = matchesAny(text, CONCRETE_CHANGE_PATTERNS);
|
|
375
|
+
const specificOperationalParameter = matchesAny(text, SPECIFIC_PARAMETER_PATTERNS);
|
|
376
|
+
const urgencyPressure = matchesAny(text, URGENCY_PATTERNS);
|
|
377
|
+
const irreversibleAction = matchesAny(text, IRREVERSIBLE_ACTION_PATTERNS);
|
|
378
|
+
const frontend = frontendSpecializationSignals(explicitIntentText);
|
|
379
|
+
if (riskPresent)
|
|
380
|
+
signals.push("risk-present");
|
|
381
|
+
if (unverifiedCausalClaim)
|
|
382
|
+
signals.push("unverified-causal-claim");
|
|
383
|
+
if (concreteChangeRequest)
|
|
384
|
+
signals.push("concrete-change-request");
|
|
385
|
+
if (specificOperationalParameter)
|
|
386
|
+
signals.push("specific-operational-parameter");
|
|
387
|
+
if (urgencyPressure)
|
|
388
|
+
signals.push("urgency-pressure");
|
|
389
|
+
if (irreversibleAction)
|
|
390
|
+
signals.push("irreversible-action");
|
|
391
|
+
const interruption = input.interruption;
|
|
392
|
+
if (isContinuationRole(interruption?.responsibility)
|
|
393
|
+
&& classifyResponsibilityInterruptionText(interruption?.continuationText) === "continue") {
|
|
394
|
+
return route("controller", OUTPUT_LIMIT_CONTINUATION_REASON, `The verified ${interruption.responsibility} responsibility was interrupted by the provider output limit and the user explicitly continued it.`, ["verified-output-limit-interruption", "explicit-continuation"], "upgrade", interruption.responsibility);
|
|
395
|
+
}
|
|
396
|
+
const executionAuthorizedByState = proposal?.responsibility === "executor"
|
|
397
|
+
&& input.routeCard?.authorization?.status === "authorized";
|
|
398
|
+
if (input.routeCard?.frozen === true
|
|
399
|
+
&& input.routeCard?.observableBenefit === true
|
|
400
|
+
&& (isExecutionContinuation(explicitIntentText) || executionAuthorizedByState)) {
|
|
401
|
+
signals.push("route-card-frozen", "observable-net-benefit", ...(executionAuthorizedByState ? ["evidence-grounded-responsibility-gap", `state:${proposal.stateDigest}`] : ["explicit-execution-continuation"]));
|
|
402
|
+
return route("controller", EXECUTOR_ROUTE_CARD_REASON, executionAuthorizedByState
|
|
403
|
+
? proposal.gap
|
|
404
|
+
: "A frozen route card exists, executor separation has an observable net benefit, and the user explicitly continued implementation.", signals, "upgrade", "executor");
|
|
405
|
+
}
|
|
406
|
+
if (proposal?.responsibility === "user") {
|
|
407
|
+
signals.push("user-decision-gap", `state:${proposal.stateDigest}`);
|
|
408
|
+
return route("controller", "USER_DECISION_REQUIRED", proposal.gap, signals);
|
|
409
|
+
}
|
|
410
|
+
if (proposal?.responsibility === "reviewer") {
|
|
411
|
+
signals.push("evidence-grounded-responsibility-gap", `state:${proposal.stateDigest}`);
|
|
412
|
+
return route("reviewer", "REVIEWER_EVIDENCE_STATE_GAP", proposal.gap, signals);
|
|
413
|
+
}
|
|
414
|
+
if (proposal?.responsibility === "planner") {
|
|
415
|
+
signals.push("evidence-grounded-responsibility-gap", `state:${proposal.stateDigest}`);
|
|
416
|
+
return route("controller", "PLANNER_EVIDENCE_STATE_GAP", proposal.gap, signals, "upgrade", "planner");
|
|
417
|
+
}
|
|
418
|
+
if (proposal?.responsibility === "frontend") {
|
|
419
|
+
signals.push("evidence-grounded-responsibility-gap", `state:${proposal.stateDigest}`);
|
|
420
|
+
return route("controller", "FRONTEND_EVIDENCE_STATE_GAP", proposal.gap, signals, "upgrade", "frontend");
|
|
421
|
+
}
|
|
422
|
+
if (matchesAny(explicitIntentText, REVIEWER_PATTERNS)) {
|
|
423
|
+
signals.push("review-language-present");
|
|
424
|
+
considerations.push(Object.freeze({
|
|
425
|
+
role: "reviewer",
|
|
426
|
+
match: "lexical",
|
|
427
|
+
action: "skip",
|
|
428
|
+
reasonCode: "REVIEWER_GAP_NOT_PROVEN",
|
|
429
|
+
signals: Object.freeze(["review-language-present"]),
|
|
430
|
+
unmet: Object.freeze(["current-evidence-package", "acceptance-impact"]),
|
|
431
|
+
}));
|
|
432
|
+
}
|
|
433
|
+
if (matchesAny(explicitIntentText, PLANNER_PATTERNS)) {
|
|
434
|
+
signals.push("planning-language-present");
|
|
435
|
+
considerations.push(Object.freeze({
|
|
436
|
+
role: "planner",
|
|
437
|
+
match: "lexical",
|
|
438
|
+
action: "skip",
|
|
439
|
+
reasonCode: "PLANNER_GAP_NOT_PROVEN",
|
|
440
|
+
signals: Object.freeze(["planning-language-present"]),
|
|
441
|
+
unmet: Object.freeze(["evidence-grounded-decision-branch", "observable-capability-benefit"]),
|
|
442
|
+
}));
|
|
443
|
+
}
|
|
444
|
+
else if (matchesAny(explicitIntentText, PLANNER_META_PATTERNS)) {
|
|
445
|
+
signals.push("planner-meta-question");
|
|
446
|
+
considerations.push(Object.freeze({
|
|
447
|
+
role: "planner",
|
|
448
|
+
match: "meta-question",
|
|
449
|
+
action: "skip",
|
|
450
|
+
reasonCode: "PLANNER_META_QUERY_NO_INDEPENDENT_GAP",
|
|
451
|
+
signals: Object.freeze(["planner-meta-question"]),
|
|
452
|
+
unmet: Object.freeze(["prior-task-state-with-unresolved-decision-branch"]),
|
|
453
|
+
}));
|
|
454
|
+
}
|
|
455
|
+
const contextualPlannerGap = riskPresent
|
|
456
|
+
&& unverifiedCausalClaim
|
|
457
|
+
&& concreteChangeRequest
|
|
458
|
+
&& (specificOperationalParameter || urgencyPressure || irreversibleAction);
|
|
459
|
+
if (contextualPlannerGap) {
|
|
460
|
+
return route("controller", HIGH_IMPACT_PLANNER_REASON, "An unverified causal claim is being used to justify a concrete high-impact change, so the controller needs a stronger decision route.", signals, "upgrade", "planner");
|
|
461
|
+
}
|
|
462
|
+
const frontendSignals = frontend.scope || frontend.explicit ? frontendRouteSignals(frontend) : [];
|
|
463
|
+
if (frontend.substantial && !isLowRiskTransform(explicitIntentText)) {
|
|
464
|
+
signals.push(...frontendSignals);
|
|
465
|
+
return route("controller", FRONTEND_SPECIALIST_REASON, "Substantial user-facing interface work can benefit from a configured frontend specialist without a child handoff.", signals, "upgrade", "frontend");
|
|
466
|
+
}
|
|
467
|
+
signals.push(...frontendSignals, "no-independent-gap");
|
|
468
|
+
const direct = route("controller", "DIRECT_DEFAULT_NO_INDEPENDENT_GAP", "No evidence-grounded independent decision, execution, or acceptance gap was found.", signals);
|
|
469
|
+
if (frontendSignals.length > 0) {
|
|
470
|
+
const lowRiskTransform = isLowRiskTransform(explicitIntentText);
|
|
471
|
+
considerations.push(Object.freeze({
|
|
472
|
+
role: "frontend",
|
|
473
|
+
match: "partial",
|
|
474
|
+
action: "skip",
|
|
475
|
+
reasonCode: frontend.nonUiRequest
|
|
476
|
+
? "FRONTEND_API_REQUEST"
|
|
477
|
+
: lowRiskTransform
|
|
478
|
+
? "FRONTEND_LOW_RISK_TRANSFORM"
|
|
479
|
+
: "FRONTEND_BELOW_SPECIALIST_THRESHOLD",
|
|
480
|
+
signals: Object.freeze(frontendSignals),
|
|
481
|
+
unmet: Object.freeze(frontend.nonUiRequest
|
|
482
|
+
? ["ui-production-request"]
|
|
483
|
+
: [
|
|
484
|
+
...(frontend.scope ? [] : ["interface-scope"]),
|
|
485
|
+
...(frontend.delivery ? [] : ["delivery-request"]),
|
|
486
|
+
...(frontend.specialistDepth ? [] : ["specialist-or-substantial-scope"]),
|
|
487
|
+
]),
|
|
488
|
+
}));
|
|
489
|
+
}
|
|
490
|
+
return considerations.length === 0
|
|
491
|
+
? direct
|
|
492
|
+
: Object.freeze({ ...direct, considerations: Object.freeze(considerations) });
|
|
535
493
|
}
|
|
536
|
-
|
|
537
494
|
export function extractLatestUserText(messages) {
|
|
538
|
-
|
|
495
|
+
return genuineUserTexts(messages)[0] ?? "";
|
|
539
496
|
}
|
|
540
|
-
|
|
541
497
|
export function extractRoutingText(messages, sessionEvents) {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
498
|
+
const texts = genuineUserTexts(messages, sessionEvents);
|
|
499
|
+
const latest = texts[0] ?? "";
|
|
500
|
+
if (!latest
|
|
501
|
+
|| hasContextualPlannerGap(latest)
|
|
502
|
+
|| !matchesAny(stripQuotedMaterial(latest), CONTINUATION_PATTERNS)
|
|
503
|
+
|| isLowRiskTransform(latest)) {
|
|
504
|
+
return latest;
|
|
505
|
+
}
|
|
506
|
+
let referencedHighImpact;
|
|
507
|
+
let referencedFrontend;
|
|
508
|
+
for (const text of texts.slice(1)) {
|
|
509
|
+
if (hasContextualPlannerGap(text)) {
|
|
510
|
+
referencedHighImpact = text;
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
const frontend = frontendSpecializationSignals(stripQuotedMaterial(text));
|
|
514
|
+
if (frontend.scope && frontend.delivery) {
|
|
515
|
+
referencedFrontend = text;
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
if (!isLowRiskTransform(text))
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
if (referencedHighImpact) {
|
|
522
|
+
return `${latest}\n\nReferenced earlier high-impact user context:\n${referencedHighImpact}`;
|
|
557
523
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
referencedFrontend = text;
|
|
561
|
-
break;
|
|
524
|
+
if (referencedFrontend) {
|
|
525
|
+
return `${latest}\n\nReferenced earlier frontend user context:\n${referencedFrontend}`;
|
|
562
526
|
}
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
if (referencedHighImpact) {
|
|
566
|
-
return `${latest}\n\nReferenced earlier high-impact user context:\n${referencedHighImpact}`;
|
|
567
|
-
}
|
|
568
|
-
if (referencedFrontend) {
|
|
569
|
-
return `${latest}\n\nReferenced earlier frontend user context:\n${referencedFrontend}`;
|
|
570
|
-
}
|
|
571
|
-
return latest;
|
|
527
|
+
return latest;
|
|
572
528
|
}
|
|
573
|
-
|
|
574
529
|
export function requiresFailClosedProtection(decision) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
530
|
+
if (decision?.reasonCode === HIGH_IMPACT_PLANNER_REASON)
|
|
531
|
+
return true;
|
|
532
|
+
if (!decision)
|
|
533
|
+
return false;
|
|
534
|
+
const decisionRole = decision.targetRole ?? decision.role;
|
|
535
|
+
if (decisionRole !== "planner" && decisionRole !== "executor" && decisionRole !== "reviewer")
|
|
536
|
+
return false;
|
|
537
|
+
const signals = new Set(decision.signals);
|
|
538
|
+
if (!signals.has("risk-present"))
|
|
539
|
+
return false;
|
|
540
|
+
return signals.has("irreversible-action")
|
|
541
|
+
|| (signals.has("concrete-change-request")
|
|
542
|
+
&& (signals.has("specific-operational-parameter") || signals.has("urgency-pressure")));
|
|
585
543
|
}
|
|
586
|
-
|
|
587
544
|
function observeProtocol(decision) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
545
|
+
const shared = [
|
|
546
|
+
"Observe-mode controller protocol:",
|
|
547
|
+
"- No independent role was run. Do not claim independent planning or review.",
|
|
548
|
+
"- Perform the missing responsibility locally: separate facts from assumptions, inspect decisive project evidence, and state what remains unverified.",
|
|
549
|
+
"- Ground the path in capabilities and evidence that actually exist. Treat unavailable environments, tools, owners, thresholds, and protections as missing conditions, not facts.",
|
|
550
|
+
"- End with concrete evidence-gathering steps and explicit decision criteria that let the user safely continue; objection alone is not a complete delivery.",
|
|
551
|
+
];
|
|
552
|
+
if (!requiresFailClosedProtection(decision))
|
|
553
|
+
return shared;
|
|
554
|
+
return [
|
|
555
|
+
...shared,
|
|
556
|
+
"- High-impact fail-closed boundary: do not implement, persist, or publish the requested change in this turn. Use read-only evidence only.",
|
|
557
|
+
"- Explain the protection-chain gap and keep the current state unchanged until the decision basis and end-to-end safety dependency are verified.",
|
|
558
|
+
];
|
|
602
559
|
}
|
|
603
|
-
|
|
604
560
|
export function renderRouteNotice(decision, runtimeMode, actualRoute) {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
].join("\n");
|
|
561
|
+
const routeRole = decision.targetRole ?? decision.role;
|
|
562
|
+
const isUpgrade = decision.action === "upgrade"
|
|
563
|
+
&& (runtimeMode === "auto" || ["executor", "frontend"].includes(routeRole));
|
|
564
|
+
const action = isUpgrade
|
|
565
|
+
? "The current controller turn requested an in-place upgrade; no child was started."
|
|
566
|
+
: runtimeMode === "observe"
|
|
567
|
+
? `The ${routeRole} gap was selected in observe mode; do not start a child automatically.`
|
|
568
|
+
: `The ${routeRole} route was selected and executed as an independent child.`;
|
|
569
|
+
const routeIdentity = actualRoute
|
|
570
|
+
? [`${isUpgrade ? "requested controller route" : "verified child route"}: ${actualRoute.provider}/${actualRoute.model} (reasoning: ${actualRoute.reasoningEffort ?? "unspecified"}, maxTokens: ${actualRoute.maxTokens ?? (isUpgrade ? "inherited from Controller policy" : "provider default")})`]
|
|
571
|
+
: [];
|
|
572
|
+
return [
|
|
573
|
+
"odai automatic routing decision",
|
|
574
|
+
`role: ${decision.role}`,
|
|
575
|
+
`action: ${isUpgrade ? "upgrade" : decision.action}`,
|
|
576
|
+
...(decision.targetRole ? [`target responsibility: ${decision.targetRole}`] : []),
|
|
577
|
+
`reason: ${decision.reasonCode}`,
|
|
578
|
+
`runtime: ${runtimeMode}`,
|
|
579
|
+
action,
|
|
580
|
+
...routeIdentity,
|
|
581
|
+
...(runtimeMode === "observe" ? ["", ...observeProtocol(decision)] : []),
|
|
582
|
+
].join("\n");
|
|
628
583
|
}
|
|
629
|
-
|
|
630
584
|
export function renderMissingRouteConfigNotice(decision, runtimeMode, configFailure) {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
])
|
|
651
|
-
].join("\n");
|
|
585
|
+
const routeRole = decision.targetRole ?? decision.role;
|
|
586
|
+
const naturalRole = RESPONSIBILITY_LABELS[routeRole] ?? routeRole;
|
|
587
|
+
const invalidConfig = typeof configFailure === "string" && configFailure !== "";
|
|
588
|
+
return [
|
|
589
|
+
`odai routing capability is ${invalidConfig ? "invalid" : "not configured"}`,
|
|
590
|
+
`required responsibility: ${routeRole}`,
|
|
591
|
+
`runtime: ${runtimeMode}`,
|
|
592
|
+
`${invalidConfig ? "untrusted" : "missing"} responsibility mapping: ${routeRole}`,
|
|
593
|
+
...(invalidConfig ? [`configuration error: ${configFailure}`] : []),
|
|
594
|
+
`No ${routeRole} model was called. Do not claim that this responsibility ran or that the controller was upgraded.`,
|
|
595
|
+
`Tell the user that the required ${routeRole} model is ${invalidConfig ? "unavailable because its saved configuration is invalid" : "not configured"}. Ask them to name the provider, model, and optional reasoning effort in natural language.`,
|
|
596
|
+
`Example: “把${naturalRole}模型设为 <provider>/<model>,推理档设为 <effort>。”`,
|
|
597
|
+
`When the user specifies that mapping, call the odai_routing_config tool to ${invalidConfig ? "repair and " : ""}persist it. Do not ask the user to edit YAML or JSON, run a command, or add routing terminology to future task prompts.`,
|
|
598
|
+
...(requiresFailClosedProtection(decision) ? [
|
|
599
|
+
"High-impact fail-closed protection is active for this turn.",
|
|
600
|
+
"Do not implement, persist, or publish the requested change. Use read-only evidence only until the missing responsibility is configured or the decision gap is otherwise resolved.",
|
|
601
|
+
] : [
|
|
602
|
+
"Continue only with parts that do not depend on the missing independent responsibility.",
|
|
603
|
+
]),
|
|
604
|
+
].join("\n");
|
|
652
605
|
}
|
|
653
|
-
|
|
654
606
|
export function renderRouteFailureNotice(decision, failure) {
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
].join("\n");
|
|
607
|
+
const routeRole = decision.targetRole ?? decision.role;
|
|
608
|
+
if (!requiresFailClosedProtection(decision)) {
|
|
609
|
+
return `odai ${routeRole} route failed (${failure}); continue directly as controller and do not claim delegated evidence.`;
|
|
610
|
+
}
|
|
611
|
+
return [
|
|
612
|
+
`odai ${routeRole} route failed (${failure}); no independent evidence was obtained.`,
|
|
613
|
+
"High-impact fail-closed protection is active for this turn.",
|
|
614
|
+
"Do not implement, persist, or publish the requested change. Use read-only evidence only.",
|
|
615
|
+
"Ground the path in capabilities and evidence that actually exist. Treat unavailable environments, tools, owners, thresholds, and protections as missing conditions, not facts.",
|
|
616
|
+
"Explain the unresolved decision-evidence and protection-chain gaps, then provide concrete evidence-gathering steps and explicit decision criteria. Objection alone is not a complete delivery.",
|
|
617
|
+
].join("\n");
|
|
667
618
|
}
|
|
668
|
-
|
|
669
619
|
export function renderDelegationPrompt(decision, taskText, roleContract) {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
].join("\n");
|
|
620
|
+
if (typeof roleContract !== "string" || roleContract.trim() === "") {
|
|
621
|
+
throw new TypeError(`canonical ${decision.role} role contract must be a non-empty string`);
|
|
622
|
+
}
|
|
623
|
+
return [
|
|
624
|
+
`You are the odai ${decision.role}.`,
|
|
625
|
+
roleContract.trim(),
|
|
626
|
+
"Runtime boundary: do not edit files, run shell commands, ask the user, or delegate further. The controller owns all final decisions and delivery.",
|
|
627
|
+
"Context boundary: this is a bounded task and evidence packet, not an inherited controller transcript. Use only the supplied contract, task, evidence, and source pointers; do not request or reconstruct the controller's full history.",
|
|
628
|
+
"",
|
|
629
|
+
"Task:",
|
|
630
|
+
taskText,
|
|
631
|
+
].join("\n");
|
|
683
632
|
}
|
|
633
|
+
//# sourceMappingURL=router.mjs.map
|