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