muonroi-cli 1.8.3 → 1.8.5

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 (477) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +133 -122
  3. package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
  4. package/dist/packages/agent-harness-core/src/driver.js +46 -0
  5. package/dist/packages/agent-harness-core/src/event-tee.d.ts +48 -0
  6. package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
  7. package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
  8. package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
  9. package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
  10. package/dist/packages/agent-harness-core/src/protocol.js +15 -0
  11. package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
  12. package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
  13. package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
  14. package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
  15. package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
  16. package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
  17. package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
  18. package/dist/packages/agent-harness-opentui/src/install.js +10 -0
  19. package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
  20. package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
  21. package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
  22. package/dist/src/agent-harness/mock-model.d.ts +28 -0
  23. package/dist/src/agent-harness/mock-model.js +63 -1
  24. package/dist/src/agent-harness/test-spawn.js +31 -0
  25. package/dist/src/cli/config/screen-providers.js +1 -1
  26. package/dist/src/cli/cost-forensics.d.ts +10 -0
  27. package/dist/src/cli/cost-forensics.js +30 -15
  28. package/dist/src/cli/keys-bundle.d.ts +1 -1
  29. package/dist/src/cli/keys-bundle.js +1 -1
  30. package/dist/src/cli/keys.d.ts +2 -2
  31. package/dist/src/cli/keys.js +19 -81
  32. package/dist/src/council/clarifier.d.ts +28 -2
  33. package/dist/src/council/clarifier.js +81 -15
  34. package/dist/src/council/context.js +49 -15
  35. package/dist/src/council/debate-checkpoint.d.ts +129 -0
  36. package/dist/src/council/debate-checkpoint.js +176 -0
  37. package/dist/src/council/debate-planner.js +51 -3
  38. package/dist/src/council/debate-summary.d.ts +25 -0
  39. package/dist/src/council/debate-summary.js +85 -0
  40. package/dist/src/council/debate.d.ts +169 -2
  41. package/dist/src/council/debate.js +1210 -134
  42. package/dist/src/council/index.d.ts +85 -1
  43. package/dist/src/council/index.js +634 -196
  44. package/dist/src/council/leader.d.ts +26 -0
  45. package/dist/src/council/leader.js +150 -9
  46. package/dist/src/council/llm.d.ts +32 -0
  47. package/dist/src/council/llm.js +231 -38
  48. package/dist/src/council/panel-select.d.ts +30 -0
  49. package/dist/src/council/panel-select.js +72 -0
  50. package/dist/src/council/planner.js +23 -0
  51. package/dist/src/council/preflight.d.ts +7 -0
  52. package/dist/src/council/preflight.js +14 -2
  53. package/dist/src/council/prompts.d.ts +30 -3
  54. package/dist/src/council/prompts.js +254 -84
  55. package/dist/src/council/stance-recall.d.ts +42 -0
  56. package/dist/src/council/stance-recall.js +57 -0
  57. package/dist/src/council/strip-think.d.ts +17 -0
  58. package/dist/src/council/strip-think.js +33 -0
  59. package/dist/src/council/types.d.ts +128 -0
  60. package/dist/src/ee/artifact-cache.d.ts +16 -0
  61. package/dist/src/ee/artifact-cache.js +32 -0
  62. package/dist/src/ee/auth.d.ts +1 -0
  63. package/dist/src/ee/auth.js +15 -2
  64. package/dist/src/ee/bridge.d.ts +10 -0
  65. package/dist/src/ee/bridge.js +58 -0
  66. package/dist/src/ee/client.js +81 -18
  67. package/dist/src/ee/export-transcripts.d.ts +1 -0
  68. package/dist/src/ee/export-transcripts.js +8 -10
  69. package/dist/src/ee/extract-session.js +29 -0
  70. package/dist/src/ee/extract-style.d.ts +58 -0
  71. package/dist/src/ee/extract-style.js +270 -0
  72. package/dist/src/ee/recall-ledger.d.ts +9 -0
  73. package/dist/src/ee/recall-ledger.js +3 -0
  74. package/dist/src/ee/scope.d.ts +1 -0
  75. package/dist/src/ee/scope.js +26 -1
  76. package/dist/src/ee/search.d.ts +7 -0
  77. package/dist/src/ee/search.js +24 -0
  78. package/dist/src/ee/transcript-emit.js +2 -0
  79. package/dist/src/ee/types.d.ts +22 -0
  80. package/dist/src/ee/who-am-i-brain.d.ts +35 -0
  81. package/dist/src/ee/who-am-i-brain.js +220 -0
  82. package/dist/src/ee/who-am-i.d.ts +10 -3
  83. package/dist/src/ee/who-am-i.js +12 -0
  84. package/dist/src/ee/workflow-event.d.ts +48 -0
  85. package/dist/src/ee/workflow-event.js +81 -0
  86. package/dist/src/flow/compaction/compress.d.ts +3 -3
  87. package/dist/src/flow/compaction/compress.js +45 -8
  88. package/dist/src/flow/compaction/extract.d.ts +4 -7
  89. package/dist/src/flow/compaction/extract.js +50 -10
  90. package/dist/src/flow/compaction/index.d.ts +13 -1
  91. package/dist/src/flow/compaction/index.js +70 -3
  92. package/dist/src/flow/compaction/input-guard.d.ts +24 -0
  93. package/dist/src/flow/compaction/input-guard.js +43 -0
  94. package/dist/src/flow/fold-planning.d.ts +36 -0
  95. package/dist/src/flow/fold-planning.js +83 -0
  96. package/dist/src/flow/hierarchy.d.ts +146 -0
  97. package/dist/src/flow/hierarchy.js +427 -0
  98. package/dist/src/flow/index.d.ts +1 -0
  99. package/dist/src/flow/index.js +2 -0
  100. package/dist/src/flow/run-artifacts.d.ts +102 -0
  101. package/dist/src/flow/run-artifacts.js +208 -0
  102. package/dist/src/generated/version.d.ts +1 -1
  103. package/dist/src/generated/version.js +1 -1
  104. package/dist/src/gsd/assessment-schema.d.ts +44 -0
  105. package/dist/src/gsd/assessment-schema.js +134 -0
  106. package/dist/src/gsd/capability-registry.d.ts +45 -0
  107. package/dist/src/gsd/capability-registry.js +337 -0
  108. package/dist/src/gsd/complexity-assessor.d.ts +39 -0
  109. package/dist/src/gsd/complexity-assessor.js +152 -0
  110. package/dist/src/gsd/config-bridge.d.ts +7 -0
  111. package/dist/src/gsd/config-bridge.js +114 -0
  112. package/dist/src/gsd/config-loader.d.ts +27 -0
  113. package/dist/src/gsd/config-loader.js +50 -0
  114. package/dist/src/gsd/council-context.d.ts +44 -0
  115. package/dist/src/gsd/council-context.js +114 -0
  116. package/dist/src/gsd/ee-closure.d.ts +28 -0
  117. package/dist/src/gsd/ee-closure.js +49 -0
  118. package/dist/src/gsd/flags.d.ts +55 -0
  119. package/dist/src/gsd/flags.js +83 -0
  120. package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
  121. package/dist/src/gsd/gsd-dispatch.js +131 -0
  122. package/dist/src/gsd/gsd-runtime.d.ts +22 -0
  123. package/dist/src/gsd/gsd-runtime.js +37 -0
  124. package/dist/src/gsd/host-adapter.d.ts +11 -0
  125. package/dist/src/gsd/host-adapter.js +29 -0
  126. package/dist/src/gsd/index.d.ts +24 -1
  127. package/dist/src/gsd/index.js +27 -0
  128. package/dist/src/gsd/loop-host-contract.d.ts +21 -0
  129. package/dist/src/gsd/loop-host-contract.js +39 -0
  130. package/dist/src/gsd/loop-host.d.ts +69 -0
  131. package/dist/src/gsd/loop-host.js +245 -0
  132. package/dist/src/gsd/loop-resolver.d.ts +36 -0
  133. package/dist/src/gsd/loop-resolver.js +79 -0
  134. package/dist/src/gsd/model-tier.d.ts +13 -0
  135. package/dist/src/gsd/model-tier.js +45 -0
  136. package/dist/src/gsd/mutation-gate.d.ts +16 -0
  137. package/dist/src/gsd/mutation-gate.js +41 -0
  138. package/dist/src/gsd/native-roadmap.d.ts +89 -0
  139. package/dist/src/gsd/native-roadmap.js +343 -0
  140. package/dist/src/gsd/native-state.d.ts +47 -0
  141. package/dist/src/gsd/native-state.js +220 -0
  142. package/dist/src/gsd/paths.d.ts +23 -0
  143. package/dist/src/gsd/paths.js +66 -0
  144. package/dist/src/gsd/phase-dag.d.ts +12 -0
  145. package/dist/src/gsd/phase-dag.js +94 -0
  146. package/dist/src/gsd/phase-sync.d.ts +42 -0
  147. package/dist/src/gsd/phase-sync.js +321 -0
  148. package/dist/src/gsd/pil-gate-context.d.ts +13 -0
  149. package/dist/src/gsd/pil-gate-context.js +64 -0
  150. package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
  151. package/dist/src/gsd/pil-gate-critic.js +74 -0
  152. package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
  153. package/dist/src/gsd/plan-council-prompts.js +79 -0
  154. package/dist/src/gsd/plan-council.d.ts +44 -0
  155. package/dist/src/gsd/plan-council.js +251 -0
  156. package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
  157. package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
  158. package/dist/src/gsd/product-workspace.d.ts +13 -0
  159. package/dist/src/gsd/product-workspace.js +124 -0
  160. package/dist/src/gsd/ship-bridge.d.ts +25 -0
  161. package/dist/src/gsd/ship-bridge.js +65 -0
  162. package/dist/src/gsd/state-document.d.ts +40 -0
  163. package/dist/src/gsd/state-document.js +163 -0
  164. package/dist/src/gsd/verdict-schema.d.ts +39 -0
  165. package/dist/src/gsd/verdict-schema.js +144 -0
  166. package/dist/src/gsd/verify-context.d.ts +22 -0
  167. package/dist/src/gsd/verify-context.js +27 -0
  168. package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
  169. package/dist/src/gsd/verify-council-prompts.js +85 -0
  170. package/dist/src/gsd/verify-council.d.ts +25 -0
  171. package/dist/src/gsd/verify-council.js +119 -0
  172. package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
  173. package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
  174. package/dist/src/gsd/workflow-engine.d.ts +60 -0
  175. package/dist/src/gsd/workflow-engine.js +207 -0
  176. package/dist/src/gsd/workflow-tools.d.ts +13 -0
  177. package/dist/src/gsd/workflow-tools.js +277 -0
  178. package/dist/src/hooks/index.js +1 -1
  179. package/dist/src/index.js +44 -11
  180. package/dist/src/maintain/pr-builder.js +23 -13
  181. package/dist/src/mcp/auto-setup.js +57 -32
  182. package/dist/src/mcp/client-pool.js +1 -1
  183. package/dist/src/mcp/ee-tools.js +1 -0
  184. package/dist/src/mcp/oauth-callback.js +2 -2
  185. package/dist/src/mcp/research-onboarding.js +8 -7
  186. package/dist/src/mcp/runtime.js +34 -2
  187. package/dist/src/mcp/setup-guide-text.d.ts +1 -1
  188. package/dist/src/mcp/setup-guide-text.js +77 -76
  189. package/dist/src/models/catalog-client.d.ts +87 -0
  190. package/dist/src/models/catalog-client.js +105 -38
  191. package/dist/src/models/catalog.json +528 -265
  192. package/dist/src/models/registry.d.ts +22 -7
  193. package/dist/src/models/registry.js +73 -10
  194. package/dist/src/ops/doctor.js +8 -8
  195. package/dist/src/orchestrator/auto-commit.js +1 -1
  196. package/dist/src/orchestrator/batch-turn-runner.js +2 -2
  197. package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
  198. package/dist/src/orchestrator/cache-prefix.js +83 -0
  199. package/dist/src/orchestrator/compact-request.d.ts +32 -0
  200. package/dist/src/orchestrator/compact-request.js +41 -0
  201. package/dist/src/orchestrator/compaction.d.ts +10 -0
  202. package/dist/src/orchestrator/compaction.js +27 -7
  203. package/dist/src/orchestrator/council-manager.d.ts +12 -3
  204. package/dist/src/orchestrator/council-manager.js +65 -24
  205. package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
  206. package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
  207. package/dist/src/orchestrator/error-utils.d.ts +29 -0
  208. package/dist/src/orchestrator/error-utils.js +132 -24
  209. package/dist/src/orchestrator/grounding-check.js +39 -1
  210. package/dist/src/orchestrator/message-processor.js +242 -33
  211. package/dist/src/orchestrator/orchestrator.d.ts +39 -3
  212. package/dist/src/orchestrator/orchestrator.js +651 -102
  213. package/dist/src/orchestrator/preprocessor.js +1 -1
  214. package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
  215. package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
  216. package/dist/src/orchestrator/prompts.js +159 -159
  217. package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
  218. package/dist/src/orchestrator/reactive-delegation.js +59 -0
  219. package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
  220. package/dist/src/orchestrator/retry-classifier.js +46 -2
  221. package/dist/src/orchestrator/safety-intercept.d.ts +45 -0
  222. package/dist/src/orchestrator/safety-intercept.js +55 -0
  223. package/dist/src/orchestrator/scope-reminder.js +1 -1
  224. package/dist/src/orchestrator/session-experience.d.ts +2 -1
  225. package/dist/src/orchestrator/session-experience.js +2 -1
  226. package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
  227. package/dist/src/orchestrator/should-run-gate.js +18 -0
  228. package/dist/src/orchestrator/stall-watchdog.d.ts +24 -3
  229. package/dist/src/orchestrator/stall-watchdog.js +47 -13
  230. package/dist/src/orchestrator/stream-runner.js +62 -29
  231. package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
  232. package/dist/src/orchestrator/sub-agent-cap.js +16 -1
  233. package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
  234. package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
  235. package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
  236. package/dist/src/orchestrator/subagent-compactor.js +126 -15
  237. package/dist/src/orchestrator/tool-engine.d.ts +26 -0
  238. package/dist/src/orchestrator/tool-engine.js +669 -56
  239. package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
  240. package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
  241. package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
  242. package/dist/src/orchestrator/turn-watchdog.d.ts +37 -0
  243. package/dist/src/orchestrator/turn-watchdog.js +55 -0
  244. package/dist/src/pil/agent-operating-contract.d.ts +1 -1
  245. package/dist/src/pil/agent-operating-contract.js +1 -1
  246. package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
  247. package/dist/src/pil/cheap-model-playbook.js +5 -1
  248. package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
  249. package/dist/src/pil/cheap-model-workbooks.js +1 -1
  250. package/dist/src/pil/discovery-types.d.ts +1 -0
  251. package/dist/src/pil/discovery.js +16 -11
  252. package/dist/src/pil/layer1-intent.d.ts +18 -6
  253. package/dist/src/pil/layer1-intent.js +66 -757
  254. package/dist/src/pil/layer15-context-scan.js +15 -1
  255. package/dist/src/pil/layer2_5-ponytail.js +8 -8
  256. package/dist/src/pil/layer3-ee-injection.js +23 -8
  257. package/dist/src/pil/layer4-gsd.js +69 -16
  258. package/dist/src/pil/layer5-context.js +7 -3
  259. package/dist/src/pil/layer6-output.d.ts +23 -0
  260. package/dist/src/pil/layer6-output.js +5 -1
  261. package/dist/src/pil/llm-classify.d.ts +33 -2
  262. package/dist/src/pil/llm-classify.js +123 -131
  263. package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
  264. package/dist/src/pil/native-capabilities-workbook.js +1 -0
  265. package/dist/src/pil/pipeline.js +34 -2
  266. package/dist/src/pil/response-tools.js +5 -3
  267. package/dist/src/pil/schema.d.ts +1 -0
  268. package/dist/src/pil/schema.js +2 -0
  269. package/dist/src/pil/types.d.ts +18 -0
  270. package/dist/src/playbook/directives.d.ts +4 -0
  271. package/dist/src/playbook/directives.js +17 -5
  272. package/dist/src/product-loop/backlog-builder.d.ts +14 -1
  273. package/dist/src/product-loop/backlog-builder.js +30 -6
  274. package/dist/src/product-loop/discovery-context-format.js +3 -1
  275. package/dist/src/product-loop/discovery-ecosystem.js +4 -1
  276. package/dist/src/product-loop/discovery-interview.js +32 -3
  277. package/dist/src/product-loop/discovery-schema.js +5 -1
  278. package/dist/src/product-loop/done-gate.js +3 -3
  279. package/dist/src/product-loop/ideal-trace.d.ts +7 -0
  280. package/dist/src/product-loop/ideal-trace.js +64 -0
  281. package/dist/src/product-loop/index.d.ts +13 -1
  282. package/dist/src/product-loop/index.js +333 -52
  283. package/dist/src/product-loop/loop-driver.d.ts +7 -0
  284. package/dist/src/product-loop/loop-driver.js +327 -116
  285. package/dist/src/product-loop/phase-plan.d.ts +5 -0
  286. package/dist/src/product-loop/phase-plan.js +39 -2
  287. package/dist/src/product-loop/phase-runner.js +9 -1
  288. package/dist/src/product-loop/progress-snapshot.js +4 -4
  289. package/dist/src/product-loop/sprint-runner.d.ts +111 -0
  290. package/dist/src/product-loop/sprint-runner.js +559 -16
  291. package/dist/src/product-loop/types.d.ts +36 -5
  292. package/dist/src/providers/adapter.d.ts +1 -1
  293. package/dist/src/providers/adapter.js +3 -4
  294. package/dist/src/providers/auth/browser-flow.d.ts +1 -1
  295. package/dist/src/providers/auth/browser-flow.js +1 -1
  296. package/dist/src/providers/auth/openai-oauth.js +1 -1
  297. package/dist/src/providers/auth/registry.js +0 -34
  298. package/dist/src/providers/auth/token-store.js +4 -1
  299. package/dist/src/providers/auth/types.d.ts +1 -1
  300. package/dist/src/providers/auth/types.js +1 -1
  301. package/dist/src/providers/capabilities.d.ts +24 -5
  302. package/dist/src/providers/capabilities.js +42 -24
  303. package/dist/src/providers/endpoints.d.ts +2 -2
  304. package/dist/src/providers/endpoints.js +11 -10
  305. package/dist/src/providers/keychain.d.ts +1 -1
  306. package/dist/src/providers/keychain.js +7 -9
  307. package/dist/src/providers/mcp-vision-bridge.js +82 -172
  308. package/dist/src/providers/openai-compatible.js +8 -1
  309. package/dist/src/providers/pricing.d.ts +2 -2
  310. package/dist/src/providers/pricing.js +3 -13
  311. package/dist/src/providers/runtime.d.ts +27 -2
  312. package/dist/src/providers/runtime.js +78 -15
  313. package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
  314. package/dist/src/providers/strategies/base.strategy.js +24 -1
  315. package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
  316. package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
  317. package/dist/src/providers/strategies/registry.js +4 -4
  318. package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
  319. package/dist/src/providers/strategies/thinking-mode.js +280 -1
  320. package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
  321. package/dist/src/providers/strategies/zai.strategy.js +44 -0
  322. package/dist/src/providers/types.d.ts +5 -6
  323. package/dist/src/providers/types.js +2 -2
  324. package/dist/src/providers/vision-backend.d.ts +47 -0
  325. package/dist/src/providers/vision-backend.js +258 -0
  326. package/dist/src/providers/vision-proxy.d.ts +22 -9
  327. package/dist/src/providers/vision-proxy.js +63 -132
  328. package/dist/src/providers/wire-debug.js +95 -0
  329. package/dist/src/reporter/index.js +1 -1
  330. package/dist/src/router/decide.d.ts +13 -0
  331. package/dist/src/router/decide.js +138 -36
  332. package/dist/src/router/peak-hour.d.ts +38 -0
  333. package/dist/src/router/peak-hour.js +107 -0
  334. package/dist/src/router/step-router.js +3 -2
  335. package/dist/src/router/warm.js +4 -5
  336. package/dist/src/scaffold/bb-ecosystem-apply.js +47 -47
  337. package/dist/src/scaffold/bb-quality-gate.js +5 -5
  338. package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
  339. package/dist/src/scaffold/continuation-prompt.js +86 -60
  340. package/dist/src/scaffold/init-new.js +453 -453
  341. package/dist/src/scaffold/point-to-existing.d.ts +21 -0
  342. package/dist/src/scaffold/point-to-existing.js +25 -0
  343. package/dist/src/self-qa/agentic-loop.js +22 -22
  344. package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
  345. package/dist/src/{ui/state → state}/active-run.js +21 -0
  346. package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
  347. package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
  348. package/dist/src/state/turn-trace.d.ts +43 -0
  349. package/dist/src/state/turn-trace.js +32 -0
  350. package/dist/src/storage/db.js +2 -1
  351. package/dist/src/storage/index.d.ts +1 -1
  352. package/dist/src/storage/index.js +1 -1
  353. package/dist/src/storage/interaction-log.d.ts +1 -1
  354. package/dist/src/storage/interaction-log.js +5 -5
  355. package/dist/src/storage/migrations.js +196 -126
  356. package/dist/src/storage/session-experience-store.js +4 -4
  357. package/dist/src/storage/sessions.d.ts +28 -10
  358. package/dist/src/storage/sessions.js +112 -55
  359. package/dist/src/storage/transcript-view.js +1 -1
  360. package/dist/src/storage/transcript.d.ts +51 -0
  361. package/dist/src/storage/transcript.js +383 -112
  362. package/dist/src/storage/usage.js +14 -14
  363. package/dist/src/storage/workspaces.js +12 -12
  364. package/dist/src/tools/file.d.ts +15 -0
  365. package/dist/src/tools/file.js +32 -0
  366. package/dist/src/tools/native-tools.js +5 -0
  367. package/dist/src/tools/registry.d.ts +3 -0
  368. package/dist/src/tools/registry.js +460 -22
  369. package/dist/src/tools/research.d.ts +29 -0
  370. package/dist/src/tools/research.js +233 -0
  371. package/dist/src/types/index.d.ts +118 -3
  372. package/dist/src/ui/app.js +0 -0
  373. package/dist/src/ui/cards/product-status-card.js +1 -1
  374. package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
  375. package/dist/src/ui/components/bubble-body-guard.js +50 -0
  376. package/dist/src/ui/components/context-rail.d.ts +26 -0
  377. package/dist/src/ui/components/context-rail.js +33 -0
  378. package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
  379. package/dist/src/ui/components/council-conclusion-card.js +420 -0
  380. package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
  381. package/dist/src/ui/components/council-debate-pill.js +34 -0
  382. package/dist/src/ui/components/council-info-card.js +2 -2
  383. package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
  384. package/dist/src/ui/components/council-leader-bubble.js +21 -11
  385. package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
  386. package/dist/src/ui/components/council-message-bubble.js +16 -15
  387. package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
  388. package/dist/src/ui/components/council-phase-timeline.js +49 -15
  389. package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
  390. package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
  391. package/dist/src/ui/components/council-question-card.js +12 -12
  392. package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
  393. package/dist/src/ui/components/council-rail-rounds.js +57 -0
  394. package/dist/src/ui/components/council-round-group.d.ts +38 -0
  395. package/dist/src/ui/components/council-round-group.js +88 -0
  396. package/dist/src/ui/components/council-status-list.d.ts +3 -1
  397. package/dist/src/ui/components/council-status-list.js +36 -24
  398. package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
  399. package/dist/src/ui/components/council-synthesis-banner.js +20 -5
  400. package/dist/src/ui/components/halt-recovery-card.js +9 -5
  401. package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
  402. package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
  403. package/dist/src/ui/components/prompt-box.js +18 -16
  404. package/dist/src/ui/components/session-tree-card.d.ts +14 -0
  405. package/dist/src/ui/components/session-tree-card.js +46 -0
  406. package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
  407. package/dist/src/ui/components/slash-inline-menu.js +26 -5
  408. package/dist/src/ui/components/task-list-panel.d.ts +14 -1
  409. package/dist/src/ui/components/task-list-panel.js +22 -2
  410. package/dist/src/ui/containers/modals-layer.d.ts +2 -1
  411. package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
  412. package/dist/src/ui/mcp-modal.js +2 -4
  413. package/dist/src/ui/modals/api-key-modal.js +1 -1
  414. package/dist/src/ui/modals/connect-modal.js +4 -3
  415. package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
  416. package/dist/src/ui/modals/session-picker-modal.js +3 -5
  417. package/dist/src/ui/picker-providers.d.ts +1 -1
  418. package/dist/src/ui/picker-providers.js +1 -1
  419. package/dist/src/ui/primitives/index.d.ts +1 -0
  420. package/dist/src/ui/primitives/index.js +2 -0
  421. package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
  422. package/dist/src/ui/primitives/semantic-primitives.js +81 -0
  423. package/dist/src/ui/slash/compact.js +5 -7
  424. package/dist/src/ui/slash/cost.js +1 -1
  425. package/dist/src/ui/slash/council-inspect.js +4 -4
  426. package/dist/src/ui/slash/council.js +19 -1
  427. package/dist/src/ui/slash/debug.d.ts +3 -31
  428. package/dist/src/ui/slash/debug.js +9 -20
  429. package/dist/src/ui/slash/ideal.d.ts +6 -2
  430. package/dist/src/ui/slash/ideal.js +97 -7
  431. package/dist/src/ui/slash/menu-items.d.ts +7 -0
  432. package/dist/src/ui/slash/menu-items.js +12 -18
  433. package/dist/src/ui/slash/registry.d.ts +2 -0
  434. package/dist/src/ui/slash/registry.js +4 -0
  435. package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
  436. package/dist/src/ui/status-bar/cache-hit.js +9 -0
  437. package/dist/src/ui/status-bar/index.d.ts +1 -1
  438. package/dist/src/ui/status-bar/index.js +7 -3
  439. package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
  440. package/dist/src/ui/status-bar/usd-meter.js +6 -4
  441. package/dist/src/ui/theme.d.ts +1 -0
  442. package/dist/src/ui/theme.js +2 -0
  443. package/dist/src/ui/types.d.ts +7 -0
  444. package/dist/src/ui/use-app-logic.js +0 -0
  445. package/dist/src/ui/utils/format.d.ts +14 -0
  446. package/dist/src/ui/utils/format.js +23 -3
  447. package/dist/src/usage/downgrade.js +2 -2
  448. package/dist/src/usage/product-ledger.js +2 -2
  449. package/dist/src/utils/clipboard-image.js +23 -23
  450. package/dist/src/utils/install-manager.js +14 -11
  451. package/dist/src/utils/logger.js +2 -2
  452. package/dist/src/utils/permission-mode.js +5 -3
  453. package/dist/src/utils/redactor.js +1 -1
  454. package/dist/src/utils/settings.d.ts +153 -5
  455. package/dist/src/utils/settings.js +233 -29
  456. package/dist/src/utils/side-question.js +2 -2
  457. package/dist/src/utils/skills.js +3 -3
  458. package/dist/src/utils/visible-retry.d.ts +11 -0
  459. package/dist/src/utils/visible-retry.js +10 -1
  460. package/dist/src/verify/entrypoint.d.ts +1 -1
  461. package/dist/src/verify/entrypoint.js +1 -1
  462. package/dist/src/verify/recipes.d.ts +13 -0
  463. package/dist/src/verify/recipes.js +15 -0
  464. package/package.json +135 -132
  465. package/dist/src/providers/auth/gcloud.d.ts +0 -28
  466. package/dist/src/providers/auth/gcloud.js +0 -102
  467. package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
  468. package/dist/src/providers/auth/gemini-oauth.js +0 -472
  469. package/dist/src/providers/gemini.d.ts +0 -11
  470. package/dist/src/providers/gemini.js +0 -45
  471. package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
  472. package/dist/src/providers/siliconflow-sse-repair.js +0 -177
  473. package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
  474. package/dist/src/providers/strategies/google.strategy.js +0 -174
  475. package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
  476. package/dist/src/ui/containers/chat-feed.d.ts +0 -40
  477. package/dist/src/ui/containers/chat-feed.js +0 -66
@@ -1,17 +1,26 @@
1
1
  /**
2
2
  * src/pil/layer1-intent.ts
3
3
  *
4
- * Layer 1: Intent detection.
5
- * Pass 1 classifier (regex + tree-sitter): maps all 14 possible reason strings to TaskType.
6
- * Pass 2 keyword fallback: catches debug/plan/documentation that classifier misses.
7
- * Pass 3 EE brain fallback via bridge.classifyViaBrain (replaces ollamaClassify).
8
- * Populates taskType, confidence, and domain on PipelineContext.
9
- * outputStyle is always null from Layer 1 Layer 6 handles output style detection via bridge.
4
+ * Layer 1: Intent detection — MODEL-FIRST ONLY.
5
+ * The configured chat model (via opts.llmFallback) classifies taskType / intent
6
+ * / style / depth / clarity / scope / language. The old keyword-regex "Pass 0-4"
7
+ * cascade was DELETED (2026-07-07, no-regex rule) regex no longer decides
8
+ * intent. When no classifier is wired the layer degrades to UNKNOWN (taskType
9
+ * null, keep-tools), never a regex guess. On a classify miss the classifier
10
+ * self-repairs (see createLlmClassifier) before surfacing UNKNOWN.
10
11
  * Fail-open: any error returns ctx unchanged with applied=false.
12
+ *
13
+ * NOTE: scoreComplexity / scoreSufficiency below are retained ONLY because other
14
+ * modules (playbook, discovery, orchestrator) still import them; they no longer
15
+ * run on this layer's classification path.
11
16
  */
12
- import { classifyViaBrain, pilContext } from "../ee/bridge.js";
13
- import { classify } from "../router/classifier/index.js";
14
- import { getUnifiedPilBudgetMs, isLlmFirstBrainEnabled, isLlmFirstClassifyEnabled, isUnifiedPilEnabled, } from "./config.js";
17
+ import { pilContext } from "../ee/bridge.js";
18
+ import { getUnifiedPilBudgetMs, isLlmFirstBrainEnabled } from "./config.js";
19
+ function mapBrainGsdPhase(value) {
20
+ if (value === "discuss" || value === "execute")
21
+ return value;
22
+ return null;
23
+ }
15
24
  /** File/path reference regex — matches common source-file extensions. */
16
25
  const FILE_REF_RE = /[\w./-]+\.(ts|tsx|js|jsx|json|md|py|rs|go|cs)\b/gi;
17
26
  /** Keywords that force a "low" complexity signal (additive score -3). */
@@ -109,33 +118,6 @@ export function scoreComplexity(input) {
109
118
  complexity = "high";
110
119
  return { complexity, score };
111
120
  }
112
- // Maps every classifier reason string to a TaskType (or null for non-coding signals).
113
- const REASON_TO_TASK_TYPE = {
114
- "regex:refactor": "refactor",
115
- "regex:edit": "generate",
116
- "regex:create-file": "generate",
117
- "regex:run-command": "analyze",
118
- "regex:explain": "analyze",
119
- "regex:search": "analyze",
120
- "regex:install": "analyze",
121
- // tree-sitter:* parses indicate code presence ONLY — no intent signal.
122
- // Mapping these to "refactor" caused 4/5 baseline misclassifications
123
- // (Phase 4, 4P-1). Leave undefined so Pass 2 keyword fallback decides.
124
- "tree-sitter:typescript": undefined,
125
- "tree-sitter:python": undefined,
126
- "regex:read": "analyze",
127
- "regex:git": "analyze",
128
- "regex:short-message": "general",
129
- "regex:design": "plan",
130
- "regex:debug": "debug",
131
- // no-match / error / cold / low-confidence → null (conversational passthrough)
132
- "regex:no-match": undefined,
133
- "tree-sitter:no-fenced-code": undefined,
134
- "tree-sitter:cold": undefined,
135
- "tree-sitter:typescript-parse-error": undefined,
136
- "tree-sitter:python-parse-error": undefined,
137
- "low-confidence": undefined,
138
- };
139
121
  /**
140
122
  * Pass 0 — deterministic full-prompt overrides.
141
123
  *
@@ -300,56 +282,6 @@ export function isStatusCheckQuestion(raw) {
300
282
  return false;
301
283
  return STATUS_CHECK_VI_RE.test(t) || STATUS_CHECK_EN_RE.test(t);
302
284
  }
303
- // Keyword patterns for task types the classifier doesn't natively handle.
304
- // Applied when classifier abstains OR matches the low-signal "general" path.
305
- // Patterns are bilingual (EN + VN) — Vietnamese cues use accent-insensitive
306
- // alternations so common diacritic drops still match.
307
- const KEYWORD_PATTERNS = [
308
- {
309
- // EN: fix/bug/error/etc. VN: sửa lỗi, lỗi, hỏng, không chạy
310
- pattern: /\b(fix|bug|error|exception|crash|fail(?:s|ed|ing)?|broken|wrong|issue|traceback)\b|(sửa lỗi|sua loi|báo lỗi|bao loi|\blỗi\b|\bloi\b|hỏng|hong|không chạy|khong chay)/i,
311
- taskType: "debug",
312
- confidence: 0.65,
313
- },
314
- {
315
- // EN: plan/roadmap/architecture. VN: kế hoạch, thiết kế, kiến trúc, lộ trình
316
- pattern: /\b(plan|roadmap|phase|step(?:s)?|approach|design|architect(?:ure)?|strategy)\b|(kế hoạch|ke hoach|thiết kế|thiet ke|kiến trúc|kien truc|lộ trình|lo trinh)/i,
317
- taskType: "plan",
318
- confidence: 0.6,
319
- },
320
- {
321
- // EN: docs/readme/jsdoc. VN: tài liệu, viết doc, ghi chú, comment
322
- pattern: /\b(doc(?:s|umentation)?|readme|comment|jsdoc|tsdoc|docstring)\b|(tài liệu|tai lieu|viết doc|viet doc|ghi chú|ghi chu)/i,
323
- taskType: "documentation",
324
- confidence: 0.6,
325
- },
326
- {
327
- // EN: test/spec/coverage. VN: kiểm thử, viết test, kiểm tra
328
- pattern: /\b(test(?:s|ing)?|spec|unit test|coverage|assert(?:ion)?)\b|(kiểm thử|kiem thu|viết test|viet test|kiểm tra|kiem tra)/i,
329
- taskType: "analyze",
330
- confidence: 0.65,
331
- },
332
- {
333
- // EN: refactor. VN: tái cấu trúc, viết lại, tổ chức lại
334
- pattern: /\brefactor(?:ing)?\b|(tái cấu trúc|tai cau truc|viết lại|viet lai|tổ chức lại|to chuc lai)/i,
335
- taskType: "refactor",
336
- confidence: 0.7,
337
- },
338
- {
339
- // EN: create/generate. VN: tạo, sinh, viết mới
340
- pattern: /\b(generate|scaffold|bootstrap)\b|(tạo file|tao file|tạo module|tao module|sinh code|viết mới|viet moi)/i,
341
- taskType: "generate",
342
- confidence: 0.65,
343
- },
344
- ];
345
- // Catch-all classifier reasons whose taskType assignment is weak — Pass 2 keyword
346
- // rescue is allowed to override them when confidence is sub-threshold. Specific
347
- // rules like `regex:run-command` / `regex:git` stay authoritative.
348
- const CATCHALL_REASONS = new Set(["regex:edit", "regex:create-file"]);
349
- const HIGH_CONF_THRESHOLD_PASS2 = 0.7;
350
- // Valid task types for bridge classification parsing (matches RESPONSE_SCHEMAS keys minus 'general').
351
- const VALID_TASK_TYPES = ["refactor", "debug", "plan", "analyze", "documentation", "generate"];
352
- const VALID_STYLES = ["concise", "balanced", "detailed"];
353
285
  // Detect language/domain from prompt content. Order matters: code fences first
354
286
  // (highest signal), file extensions next, then bare keywords.
355
287
  const DOMAIN_PATTERNS = [
@@ -397,7 +329,7 @@ const STYLE_PATTERNS = [
397
329
  },
398
330
  { pattern: /\b(balanced|normal|standard|cân bằng|bình thường)\b/i, style: "balanced" },
399
331
  ];
400
- function detectStyleFromText(raw) {
332
+ function _detectStyleFromText(raw) {
401
333
  for (const { pattern, style } of STYLE_PATTERNS) {
402
334
  if (pattern.test(raw))
403
335
  return style;
@@ -599,11 +531,14 @@ export async function layer1Intent(ctx, opts = {}) {
599
531
  // downstream (layer3 retrieval) as before. Trivial turns ("ok", greetings)
600
532
  // also go through the model so chitchat is a semantic decision, not a regex
601
533
  // whitelist; the model returns intentKind="chat" for pure pleasantries.
602
- if (isLlmFirstClassifyEnabled() && opts.llmFallback) {
534
+ // Model-first is the SOLE classifier whenever one is wired. The old
535
+ // MUONROI_LLM_FIRST_CLASSIFY killswitch is gone: it used to select the
536
+ // keyword-regex cascade, which was deleted (2026-07-07, no-regex rule).
537
+ if (opts.llmFallback) {
603
538
  let llmRes = null;
604
539
  let classifyError = null;
605
540
  try {
606
- llmRes = await opts.llmFallback(ctx.raw);
541
+ llmRes = await opts.llmFallback(ctx.raw, { recentTurns: opts.recentTurns });
607
542
  }
608
543
  catch (err) {
609
544
  classifyError = err?.message ?? String(err);
@@ -615,14 +550,14 @@ export async function layer1Intent(ctx, opts = {}) {
615
550
  // breaks the turn. Only ever upgrades chitchat → task.
616
551
  if (intentKind === "chitchat" && hasActionableToolIntent(ctx.raw))
617
552
  intentKind = "task";
618
- const outputStyle = llmRes.outputStyle ?? detectStyleFromText(ctx.raw);
553
+ // Style + complexity come from the MODEL, never a keyword regex. Style
554
+ // is the model's word or null (layer4/6 handle null without regex).
555
+ // Complexity is derived from the model's depthTier purely for the
556
+ // telemetry trace — routing reads depthTier directly, not this.
557
+ const outputStyle = llmRes.outputStyle;
619
558
  const domain = extractDomain("", ctx.raw);
620
- const { complexity, score: complexityScore } = scoreComplexity({
621
- rawText: ctx.raw,
622
- taskType: llmRes.taskType,
623
- t0HitCount: 0,
624
- hasMaxSprintsOne: false,
625
- });
559
+ const complexity = llmRes.depthTier === "heavy" ? "high" : llmRes.depthTier === "quick" ? "low" : "medium";
560
+ const complexityScore = 0;
626
561
  const intentTrace = {
627
562
  pass1Reason: "llm-first",
628
563
  pass1Confidence: llmRes.confidence,
@@ -639,7 +574,7 @@ export async function layer1Intent(ctx, opts = {}) {
639
574
  pass3LegacyStyleSucceeded: false,
640
575
  pass4LlmAttempted: true,
641
576
  pass4LlmSucceeded: true,
642
- styleSource: llmRes.outputStyle ? "brain-unified" : outputStyle ? "explicit-regex" : "none",
577
+ styleSource: llmRes.outputStyle ? "brain-unified" : "none",
643
578
  finalTaskType: llmRes.taskType,
644
579
  finalConfidence: llmRes.confidence,
645
580
  complexity,
@@ -655,6 +590,7 @@ export async function layer1Intent(ctx, opts = {}) {
655
590
  // stays null → layer3 legacy path (behaviour unchanged). Gate:
656
591
  // MUONROI_LLM_FIRST_BRAIN=0 reverts.
657
592
  let llmFirstBrainData = null;
593
+ let llmFirstGsdPhase = mapBrainGsdPhase(ctx.gsdPhase);
658
594
  if (isLlmFirstBrainEnabled() && intentKind !== "chitchat") {
659
595
  let brainRaw = ctx.raw;
660
596
  if (ctx.sessionId) {
@@ -685,12 +621,14 @@ export async function layer1Intent(ctx, opts = {}) {
685
621
  t2_patterns: resp.t2_patterns,
686
622
  retrieval_skipped_reason: resp.retrieval_skipped_reason,
687
623
  };
624
+ llmFirstGsdPhase = mapBrainGsdPhase(resp.gsd_phase) ?? llmFirstGsdPhase;
688
625
  intentTrace.pass3UnifiedSucceeded = true;
689
626
  }
690
627
  }
691
628
  return {
692
629
  ...ctx,
693
630
  taskType: llmRes.taskType,
631
+ gsdPhase: llmFirstGsdPhase,
694
632
  domain,
695
633
  confidence: llmRes.confidence,
696
634
  outputStyle,
@@ -733,12 +671,10 @@ export async function layer1Intent(ctx, opts = {}) {
733
671
  console.error("[pil.layer1] model-first classify produced no usable result — NOT falling back to regex. " +
734
672
  `reason=${classifyError ?? "null/unparseable model response"} ` +
735
673
  `model-classifier=wired rawPreview=${JSON.stringify(ctx.raw.slice(0, 120))}`);
736
- const { complexity: failComplexity, score: failComplexityScore } = scoreComplexity({
737
- rawText: ctx.raw,
738
- taskType: null,
739
- t0HitCount: 0,
740
- hasMaxSprintsOne: false,
741
- });
674
+ // No regex on the failure path either — UNKNOWN classification carries a
675
+ // neutral "medium" complexity for the telemetry trace, decided by nothing.
676
+ const failComplexity = "medium";
677
+ const failComplexityScore = 0;
742
678
  return {
743
679
  ...ctx,
744
680
  taskType: null,
@@ -780,228 +716,27 @@ export async function layer1Intent(ctx, opts = {}) {
780
716
  ],
781
717
  };
782
718
  }
783
- // Pass 0 deterministic full-prompt overrides (Phase 5 BUG-B / BUG-D).
784
- // LEGACY regex cascade reached ONLY when no model classifier is wired
785
- // (opts.llmFallback absent) or the model-first flag is off. On the main chat
786
- // path the model classifier is always wired, so this never decides intent in
787
- // production. It is NOT a runtime fallback for a failed model call (that path
788
- // returns above with a logged failure).
789
- // Two narrow patterns short-circuit the whole pipeline:
790
- // - continuation phrase → general/chitchat
791
- // - performance/optimization verbs → refactor/task
792
- // Both eliminate LLM-bridge nondeterminism on inputs whose correct
793
- // label is unambiguous from the prompt alone.
794
- if (isContinuationPhrase(ctx.raw)) {
795
- const { complexity, score: complexityScore } = scoreComplexity({
796
- rawText: ctx.raw,
797
- taskType: "general",
798
- t0HitCount: 0,
799
- hasMaxSprintsOne: false,
800
- });
801
- const intentTrace = {
802
- pass1Reason: "pass0:continuation",
803
- pass1Confidence: 0.9,
804
- pass1TaskType: "general",
805
- pass1Hit: true,
806
- pass2Hit: false,
807
- pass25ChitchatHit: false,
808
- pass3UnifiedAttempted: false,
809
- pass3UnifiedSucceeded: false,
810
- pass3LegacyTaskAttempted: false,
811
- pass3LegacyTaskSucceeded: false,
812
- pass3LegacyStyleAttempted: false,
813
- pass3LegacyStyleSucceeded: false,
814
- pass4LlmAttempted: false,
815
- pass4LlmSucceeded: false,
816
- styleSource: "chitchat-default",
817
- finalTaskType: "general",
818
- finalConfidence: 0.9,
819
- complexity,
820
- complexityScore,
821
- };
822
- return {
823
- ...ctx,
824
- taskType: "general",
825
- domain: null,
826
- confidence: 0.9,
827
- outputStyle: "concise",
828
- intentKind: "chitchat",
829
- _brainData: null,
830
- _intentTrace: intentTrace,
831
- layers: [
832
- ...ctx.layers,
833
- {
834
- name: "intent-detection",
835
- applied: true,
836
- delta: "taskType=general,kind=chitchat,conf=0.90,domain=none,style=concise,pass0=continuation",
837
- },
838
- ],
839
- };
840
- }
841
- if (isStatusCheckQuestion(ctx.raw)) {
842
- // A meta question about prior work → conversational continuation. Route to
843
- // chitchat so layer4-gsd skips the "make a NEW plan + implement" scaffold
844
- // and the agent answers from the existing thread context (session
845
- // c6387d2c6e1b root cause). Mirrors the continuation branch above.
846
- const { complexity, score: complexityScore } = scoreComplexity({
847
- rawText: ctx.raw,
848
- taskType: "general",
849
- t0HitCount: 0,
850
- hasMaxSprintsOne: false,
851
- });
852
- const intentTrace = {
853
- pass1Reason: "pass0:status-check",
854
- pass1Confidence: 0.9,
855
- pass1TaskType: "general",
856
- pass1Hit: true,
857
- pass2Hit: false,
858
- pass25ChitchatHit: false,
859
- pass3UnifiedAttempted: false,
860
- pass3UnifiedSucceeded: false,
861
- pass3LegacyTaskAttempted: false,
862
- pass3LegacyTaskSucceeded: false,
863
- pass3LegacyStyleAttempted: false,
864
- pass3LegacyStyleSucceeded: false,
865
- pass4LlmAttempted: false,
866
- pass4LlmSucceeded: false,
867
- styleSource: "chitchat-default",
868
- finalTaskType: "general",
869
- finalConfidence: 0.9,
870
- complexity,
871
- complexityScore,
872
- };
873
- return {
874
- ...ctx,
875
- taskType: "general",
876
- domain: null,
877
- confidence: 0.9,
878
- outputStyle: "concise",
879
- intentKind: "chitchat",
880
- _brainData: null,
881
- _intentTrace: intentTrace,
882
- layers: [
883
- ...ctx.layers,
884
- {
885
- name: "intent-detection",
886
- applied: true,
887
- delta: "taskType=general,kind=chitchat,conf=0.90,domain=none,style=concise,pass0=status-check",
888
- },
889
- ],
890
- };
891
- }
892
- if (isTestGenerationTask(ctx.raw)) {
893
- const domainPass0 = extractDomain("", ctx.raw);
894
- const styleFromText = detectStyleFromText(ctx.raw) ?? "balanced";
895
- const { complexity, score: complexityScore } = scoreComplexity({
896
- rawText: ctx.raw,
897
- taskType: "generate",
898
- t0HitCount: 0,
899
- hasMaxSprintsOne: false,
900
- });
901
- const intentTrace = {
902
- pass1Reason: "pass0:test-generation",
903
- pass1Confidence: 0.9,
904
- pass1TaskType: "generate",
905
- pass1Hit: true,
906
- pass2Hit: false,
907
- pass25ChitchatHit: false,
908
- pass3UnifiedAttempted: false,
909
- pass3UnifiedSucceeded: false,
910
- pass3LegacyTaskAttempted: false,
911
- pass3LegacyTaskSucceeded: false,
912
- pass3LegacyStyleAttempted: false,
913
- pass3LegacyStyleSucceeded: false,
914
- pass4LlmAttempted: false,
915
- pass4LlmSucceeded: false,
916
- styleSource: detectStyleFromText(ctx.raw) ? "explicit-regex" : "classifier-default",
917
- finalTaskType: "generate",
918
- finalConfidence: 0.9,
919
- complexity,
920
- complexityScore,
921
- };
922
- return {
923
- ...ctx,
924
- taskType: "generate",
925
- domain: domainPass0,
926
- confidence: 0.9,
927
- outputStyle: styleFromText,
928
- intentKind: "task",
929
- _brainData: null,
930
- _intentTrace: intentTrace,
931
- layers: [
932
- ...ctx.layers,
933
- {
934
- name: "intent-detection",
935
- applied: true,
936
- delta: `taskType=generate,kind=task,conf=0.90,domain=${domainPass0 ?? "none"},style=${styleFromText},pass0=test-generation`,
937
- },
938
- ],
939
- };
940
- }
941
- if (isPerformanceRefactor(ctx.raw)) {
942
- const domainPass0 = extractDomain("", ctx.raw);
943
- const styleFromText = detectStyleFromText(ctx.raw) ?? "balanced";
944
- const { complexity, score: complexityScore } = scoreComplexity({
945
- rawText: ctx.raw,
946
- taskType: "refactor",
947
- t0HitCount: 0,
948
- hasMaxSprintsOne: false,
949
- });
950
- const intentTrace = {
951
- pass1Reason: "pass0:performance",
952
- pass1Confidence: 0.85,
953
- pass1TaskType: "refactor",
954
- pass1Hit: true,
955
- pass2Hit: false,
956
- pass25ChitchatHit: false,
957
- pass3UnifiedAttempted: false,
958
- pass3UnifiedSucceeded: false,
959
- pass3LegacyTaskAttempted: false,
960
- pass3LegacyTaskSucceeded: false,
961
- pass3LegacyStyleAttempted: false,
962
- pass3LegacyStyleSucceeded: false,
963
- pass4LlmAttempted: false,
964
- pass4LlmSucceeded: false,
965
- styleSource: detectStyleFromText(ctx.raw) ? "explicit-regex" : "classifier-default",
966
- finalTaskType: "refactor",
967
- finalConfidence: 0.85,
968
- complexity,
969
- complexityScore,
970
- };
971
- return {
972
- ...ctx,
973
- taskType: "refactor",
974
- domain: domainPass0,
975
- confidence: 0.85,
976
- outputStyle: styleFromText,
977
- intentKind: "task",
978
- _brainData: null,
979
- _intentTrace: intentTrace,
980
- layers: [
981
- ...ctx.layers,
982
- {
983
- name: "intent-detection",
984
- applied: true,
985
- delta: `taskType=refactor,kind=task,conf=0.85,domain=${domainPass0 ?? "none"},style=${styleFromText},pass0=performance`,
986
- },
987
- ],
988
- };
989
- }
990
- if (isGreenfieldBuildTask(ctx.raw)) {
991
- const domainPass0 = extractDomain("", ctx.raw);
992
- const styleFromText = detectStyleFromText(ctx.raw) ?? "balanced";
993
- const { complexity, score: complexityScore } = scoreComplexity({
994
- rawText: ctx.raw,
995
- taskType: "build",
996
- t0HitCount: 0,
997
- hasMaxSprintsOne: false,
998
- });
999
- const intentTrace = {
1000
- pass1Reason: "pass0:greenfield-build",
1001
- pass1Confidence: 0.85,
1002
- pass1TaskType: "build",
1003
- pass1Hit: true,
719
+ // No model classifier wired (opts.llmFallback absent) the regex
720
+ // classification cascade that used to run here was DELETED (2026-07-07,
721
+ // no-regex rule). Degrade to UNKNOWN (keep-tools): no PIL scaffold is
722
+ // imposed and the chat model still answers the turn, but nothing fabricates
723
+ // an intent from keyword regex.
724
+ console.error("[pil.layer1] no model classifier wired (opts.llmFallback absent) — UNKNOWN classification, NO regex cascade.");
725
+ return {
726
+ ...ctx,
727
+ taskType: null,
728
+ domain: null,
729
+ confidence: 0,
730
+ outputStyle: null,
731
+ intentKind: "task",
732
+ _brainData: null,
733
+ _intentTrace: {
734
+ pass1Reason: "no-classifier-wired",
735
+ pass1Confidence: 0,
736
+ pass1TaskType: null,
737
+ pass1Hit: false,
1004
738
  pass2Hit: false,
739
+ pass2Pattern: undefined,
1005
740
  pass25ChitchatHit: false,
1006
741
  pass3UnifiedAttempted: false,
1007
742
  pass3UnifiedSucceeded: false,
@@ -1011,441 +746,15 @@ export async function layer1Intent(ctx, opts = {}) {
1011
746
  pass3LegacyStyleSucceeded: false,
1012
747
  pass4LlmAttempted: false,
1013
748
  pass4LlmSucceeded: false,
1014
- styleSource: detectStyleFromText(ctx.raw) ? "explicit-regex" : "classifier-default",
1015
- finalTaskType: "build",
1016
- finalConfidence: 0.85,
1017
- complexity,
1018
- complexityScore,
1019
- };
1020
- return {
1021
- ...ctx,
1022
- taskType: "build",
1023
- domain: domainPass0,
1024
- confidence: 0.85,
1025
- outputStyle: styleFromText,
1026
- intentKind: "task",
1027
- _brainData: null,
1028
- _intentTrace: intentTrace,
1029
- layers: [
1030
- ...ctx.layers,
1031
- {
1032
- name: "intent-detection",
1033
- applied: true,
1034
- delta: `taskType=build,kind=task,conf=0.85,domain=${domainPass0 ?? "none"},style=${styleFromText},pass0=greenfield-build`,
1035
- },
1036
- ],
1037
- };
1038
- }
1039
- // Pass 1: local classifier.
1040
- const result = classify(ctx.raw);
1041
- const pass1TaskType = REASON_TO_TASK_TYPE[result.reason] ?? null;
1042
- let taskType = pass1TaskType;
1043
- let confidence = result.confidence;
1044
- const domain = extractDomain(result.reason, ctx.raw);
1045
- let outputStyle = null;
1046
- let intentKind = null;
1047
- let brainData = null;
1048
- // Step-by-step trace — populated as each pass runs so cost reports can
1049
- // attribute which pass actually decided the outcome.
1050
- let pass2Pattern;
1051
- let pass2Hit = false;
1052
- let pass25ChitchatHit = false;
1053
- let pass3UnifiedSucceeded = false;
1054
- let pass3LegacyTaskAttempted = false;
1055
- let pass3LegacyTaskSucceeded = false;
1056
- let pass3LegacyStyleAttempted = false;
1057
- let pass3LegacyStyleSucceeded = false;
1058
- let styleSource = "none";
1059
- // Pass 2: keyword fallback. Runs when classifier abstains OR when the
1060
- // classifier match was a low-signal "general" (regex:short-message) OR
1061
- // when the catch-all `regex:edit` / `regex:create-file` mapped a vague
1062
- // "fix X" / "tạo X" verb to taskType=generate at sub-threshold confidence
1063
- // (< 0.7). The catch-all v2 rules are deliberately weak (conf 0.55) so a
1064
- // VN debug prompt like "ci/cd đang bị lỗi, check và fix cho tôi" still
1065
- // routes through the keyword rescue here — which carries the bare-`lỗi`
1066
- // and `\bfix\b` debug cues that the catch-all regex cannot tell apart
1067
- // from generic edit.
1068
- const lowSignal = taskType === "general" && result.reason === "regex:short-message";
1069
- const catchAllRescue = taskType !== null && confidence < HIGH_CONF_THRESHOLD_PASS2 && CATCHALL_REASONS.has(result.reason);
1070
- if (taskType === null || lowSignal || catchAllRescue) {
1071
- for (const { pattern, taskType: kwType, confidence: kwConf } of KEYWORD_PATTERNS) {
1072
- if (pattern.test(ctx.raw)) {
1073
- taskType = kwType;
1074
- confidence = kwConf;
1075
- pass2Hit = true;
1076
- pass2Pattern = pattern.source;
1077
- break;
1078
- }
1079
- }
1080
- }
1081
- // Pass 2.5: hot-path chitchat short-circuit for ultra-short greetings
1082
- // ("hi", "ok", "thanks", "ty") — mapped to taskType="general" without
1083
- // burning a brain round-trip. Both conditions required (AND) so we don't
1084
- // accidentally swallow phrases like "refactor this" or "fix the bug" that
1085
- // happen to be short.
1086
- //
1087
- // WhoAmI v4.0: the outputStyle baseline from communication.brevity +
1088
- // decision_speed is now wired below (getWhoAmIProfile/outputStyleFromProfile
1089
- // at the classifier-default branch — it replaces "balanced" when no per-turn
1090
- // signal resolves the style). Not applied at this chitchat hot-path: greetings
1091
- // already force "concise" regardless of profile.
1092
- const trimmed = ctx.raw.trim();
1093
- const wordCount = trimmed.split(/\s+/).filter(Boolean).length;
1094
- const noTaskSignal = taskType === null || (taskType === "general" && result.reason === "regex:short-message");
1095
- if (noTaskSignal && trimmed.length < 10 && wordCount <= 2) {
1096
- taskType = "general";
1097
- confidence = 0.5;
1098
- intentKind = "chitchat";
1099
- outputStyle = "concise";
1100
- pass25ChitchatHit = true;
1101
- styleSource = "chitchat-default";
1102
- }
1103
- // Pass 2.6 — multi-word PURE social pleasantries ("cảm ơn bạn rất nhiều
1104
- // nhé", "thank you so much", "ok great thanks") that the 2-word hot-path
1105
- // above misses. Without this they fall through to the brain/LLM passes,
1106
- // which classify intentKind inconsistently (live session 40c726a31a37
1107
- // returned intentKind=null → toolCount=37, ~15-20K wasted tool-schema
1108
- // tokens for a thank-you). isSocialPleasantry is strict (every token is
1109
- // greeting/thanks/ack/filler vocab) so it can never swallow a task; the
1110
- // hasActionableToolIntent veto is belt-and-suspenders. Classifying here is
1111
- // also a cost win: it skips the brain round-trip (needsBrain requires
1112
- // intentKind !== "chitchat").
1113
- if (intentKind !== "chitchat" &&
1114
- (taskType === null || taskType === "general") &&
1115
- !hasActionableToolIntent(trimmed) &&
1116
- isSocialPleasantry(trimmed)) {
1117
- taskType = "general";
1118
- confidence = 0.5;
1119
- intentKind = "chitchat";
1120
- outputStyle = "concise";
1121
- pass25ChitchatHit = true;
1122
- styleSource = "chitchat-default";
1123
- }
1124
- // Pass 3 UNIFIED: single /api/pil-context call replaces the multi-call
1125
- // cascade (classifier rescue + style brain). Fires only when flag is on
1126
- // AND local signal is weak (no taskType or low confidence) AND we haven't
1127
- // already short-circuited to chitchat.
1128
- const HIGH_CONF_THRESHOLD = 0.7;
1129
- const needsBrain = isUnifiedPilEnabled() && intentKind !== "chitchat" && (taskType === null || confidence < HIGH_CONF_THRESHOLD);
1130
- let unifiedFailed = false;
1131
- if (needsBrain) {
1132
- // Step 8 (ee-anti-mu): enrich the raw passed to pilContext for sessions that may have
1133
- // experienced compaction (or any sessionId-bearing turn) so the brain sees EE checkpoints
1134
- // + the PRESERVE_FULL_CONTEXT veto token. Unconditional for any turn with sessionId
1135
- // (covers _compactionStats.count > 0 or step > K cases even if local conf high).
1136
- let brainRaw = ctx.raw;
1137
- if (ctx.sessionId) {
1138
- brainRaw =
1139
- ctx.raw +
1140
- ' [EE task checkpoints ("Context checkpoint summary" with ✔ DONE) from prior compactions are available via the ee.query tool. ' +
1141
- "To keep full tool history this turn when you see pre-warn or compaction note, emit exact literal PRESERVE_FULL_CONTEXT in reasoning or assistant note. " +
1142
- 'Self-check "task finished?" or "compacted yet this turn?" using the checkpoints.]';
1143
- }
1144
- const resp = await pilContext(brainRaw, {
1145
- projectCtx: domain ? { domain } : undefined,
1146
- budgetMs: getUnifiedPilBudgetMs(),
1147
- });
1148
- if (resp) {
1149
- if (resp.taskType)
1150
- taskType = resp.taskType;
1151
- if (resp.intentKind)
1152
- intentKind = resp.intentKind;
1153
- if (resp.outputStyle) {
1154
- outputStyle = resp.outputStyle;
1155
- styleSource = "brain-unified";
1156
- }
1157
- if (resp.confidence)
1158
- confidence = resp.confidence;
1159
- brainData = {
1160
- t0_principles: resp.t0_principles,
1161
- t1_rules: resp.t1_rules,
1162
- t2_patterns: resp.t2_patterns,
1163
- retrieval_skipped_reason: resp.retrieval_skipped_reason,
1164
- };
1165
- pass3UnifiedSucceeded = true;
1166
- }
1167
- else {
1168
- unifiedFailed = true;
1169
- }
1170
- }
1171
- // Pass 4 LLM FALLBACK: fires when the brain's confidence is below the
1172
- // hot-path skip threshold (HIGH_CONF_THRESHOLD = 0.7).
1173
- //
1174
- // Earlier iteration tried a tighter floor (0.5) to skip Pass 4 on "good
1175
- // enough" brain answers, but session eda85985dce9 showed the brain
1176
- // routinely returns 0.55–0.65 for ambiguous prompts like "fix CI fail"
1177
- // — and at that confidence band the brain's answer is wrong often
1178
- // enough that skipping Pass 4 reintroduces the classification leak we
1179
- // shipped Pass 4 to fix. The ~1s LLM round-trip is the price of
1180
- // correctness on borderline turns; high-confidence turns (brain ≥ 0.7)
1181
- // bypass Pass 4 entirely so the cost only hits weak signals.
1182
- let pass4LlmAttempted = false;
1183
- let pass4LlmSucceeded = false;
1184
- const llmFallbackEligible = !!opts.llmFallback &&
1185
- intentKind !== "chitchat" &&
1186
- (taskType === null || unifiedFailed || confidence < HIGH_CONF_THRESHOLD);
1187
- if (llmFallbackEligible) {
1188
- pass4LlmAttempted = true;
1189
- try {
1190
- const llmRes = await opts.llmFallback(ctx.raw);
1191
- if (llmRes) {
1192
- pass4LlmSucceeded = true;
1193
- taskType = llmRes.taskType;
1194
- confidence = llmRes.confidence;
1195
- // Pass 4 is reached ONLY when intentKind !== "chitchat" (see
1196
- // llmFallbackEligible above) — every genuine social pleasantry was
1197
- // already short-circuited upstream by Pass 0 (continuation /
1198
- // status-check), Pass 2.5 (ultra-short greeting) and Pass 2.6
1199
- // (isSocialPleasantry). So a taskType="general" result HERE is a
1200
- // SUBSTANTIVE question that slipped past the greeting detectors —
1201
- // NOT chitchat. Live repro (session b51ba653e890): "bạn đang được
1202
- // chạy bên trong CLI này thì ... CLI tác động thế nào đến bạn?" was
1203
- // mapped general→chitchat, which nuked the entire action toolset
1204
- // (message-processor.ts:1285 `isChitchat && !_priorTurnHadTools →
1205
- // {}`). The model announced "Tôi cần điều tra code ... không đoán"
1206
- // (Evidence-First contract) but had only respond_general — no
1207
- // read_file/grep/bash to act with → narration → respond_general
1208
- // spam-abort, zero answer. A general question is tool-capable:
1209
- // classify it "task" so the toolset survives. Per the established
1210
- // keep-tools precedent in this file (TOOL_NAME_RE veto), a false
1211
- // "task" merely re-adds ~1.5K tokens of tool schema, while a false
1212
- // "chitchat" BREAKS the turn.
1213
- intentKind = "task";
1214
- if (llmRes.outputStyle) {
1215
- outputStyle = llmRes.outputStyle;
1216
- styleSource = "brain-unified"; // closest existing source — LLM acts in same role
1217
- }
1218
- }
1219
- }
1220
- catch (err) {
1221
- console.error(`[pil.layer1] LLM fallback failed: ${err?.message}`);
1222
- }
1223
- }
1224
- // Pass 3 LEGACY FALLBACK: only runs when flag off.
1225
- // Cost optimization: when unified call FAILED, we skip the legacy brain
1226
- // round-trips entirely. The unified pilContext already tried the same
1227
- // backend; a second classifyViaBrain ~1.5s after a failure almost always
1228
- // fails too, wasting tokens and ~2.3s of wall time. The cheap regex style
1229
- // detector still runs below to recover explicit "ngắn gọn"/"detailed" cues.
1230
- const runLegacyBrain = !isUnifiedPilEnabled();
1231
- let legacyBrainAttempted = false;
1232
- if (runLegacyBrain) {
1233
- if (taskType === null) {
1234
- legacyBrainAttempted = true;
1235
- pass3LegacyTaskAttempted = true;
1236
- // 4P-2: neutral bridge-classifier prompt. Earlier wording biased the
1237
- // LLM toward `refactor` for any code touch (baseline trace
1238
- // taskType=refactor,conf=0.75 on a clear feature-add). The rewrite:
1239
- // - Lists categories in neutral order (analyze first, refactor 4th).
1240
- // - Restricts refactor to explicit restructure verbs.
1241
- // - Tells the model to prefer 'general' over guessing when ambiguous.
1242
- // - Clarifies that feature additions are 'generate' even when they
1243
- // touch existing files.
1244
- // 0.7 confidence threshold for Pass 2 keyword override remains
1245
- // unchanged (HIGH_CONF_THRESHOLD_PASS2 above).
1246
- const brainRaw = await classifyViaBrain(`You are a multilingual prompt classifier. The user's prompt may be in English, Vietnamese, or a mix of both.
1247
- Classify the prompt's INTENT (not its language). Reply with TWO lowercase words separated by a comma: <category>,<style>
1248
-
1249
- Category — pick ONE (listed in neutral order, no precedence):
1250
- analyze — explain / inspect / review existing code (giải thích, phân tích, review)
1251
- debug — fix a bug or investigate failure (sửa lỗi, fix bug, lỗi, traceback)
1252
- generate — create new code/file or add new behavior (tạo, sinh code, viết function mới, thêm)
1253
- refactor — restructure existing code (tái cấu trúc, refactor)
1254
- plan — design / roadmap / architecture (kế hoạch, thiết kế, kiến trúc)
1255
- documentation — write docs/comments (viết docs, comment, jsdoc)
1256
- general — chitchat OR unclear / ambiguous coding intent
1257
-
1258
- Rules (Phase 4 4P-2 disambiguation):
1259
- - Only return refactor when the user EXPLICITLY uses one of: rename, restructure, reorganize, extract, inline, move, migrate, reshape — applied to EXISTING code WITHOUT adding new behavior.
1260
- - Feature additions ('add flag', 'thêm', 'create endpoint', 'thêm option'), changing a DEFAULT value, adding tests, or improving coverage are 'generate' — NOT refactor.
1261
- - 'improve', 'change', 'update', 'modify', 'đổi', 'cải thiện' alone do NOT imply refactor — pick the specific category by what the change actually does.
1262
- - When the request is ambiguous, prefer 'general' over guessing refactor.
1263
-
1264
- Negative examples (NOT refactor):
1265
- - "đổi default --max-tool-rounds 8 sang 12" → generate
1266
- - "improve test coverage" → generate
1267
- - "tại sao X trả empty" → analyze
1268
- - "fix CI failing" → debug
1269
-
1270
- Style — pick ONE:
1271
- concise (ngắn gọn) | balanced (cân bằng) | detailed (chi tiết)
1272
-
1273
- Examples:
1274
- "Refactor this function" → refactor,balanced
1275
- "tại sao test fail" → debug,balanced
1276
- "thiết kế hệ thống auth" → plan,detailed
1277
- "thêm flag --foo" → generate,concise
1278
- "hi" → general,concise
1279
-
1280
- Prompt: "${ctx.raw.slice(0, 500)}"`, 1500);
1281
- if (brainRaw) {
1282
- pass3LegacyTaskSucceeded = true;
1283
- const lower = brainRaw.toLowerCase();
1284
- // 4P-2: match `general` BEFORE the coding-category list so an
1285
- // ambiguous prompt the model marked `general,*` doesn't accidentally
1286
- // fall through to a substring hit later. `none` kept as legacy alias.
1287
- if (/\bgeneral\b/.test(lower) || /\bnone\b/.test(lower)) {
1288
- taskType = "general";
1289
- confidence = 0.6;
1290
- intentKind = "chitchat";
1291
- if (outputStyle === null) {
1292
- outputStyle = "concise";
1293
- styleSource = "chitchat-default";
1294
- }
1295
- }
1296
- else {
1297
- const matched = VALID_TASK_TYPES.find((t) => lower.includes(t));
1298
- if (matched) {
1299
- taskType = matched;
1300
- confidence = 0.55;
1301
- intentKind = "task";
1302
- }
1303
- }
1304
- const styleMatched = VALID_STYLES.find((s) => lower.includes(s));
1305
- if (styleMatched) {
1306
- outputStyle = styleMatched;
1307
- styleSource = "brain-legacy";
1308
- }
1309
- }
1310
- }
1311
- // Pass 3.5: regex style detection — free, always runs before any brain call.
1312
- // Catches explicit user cues ("ngắn gọn", "chi tiết", "step by step").
1313
- if (outputStyle === null) {
1314
- const regexStyle = detectStyleFromText(ctx.raw);
1315
- if (regexStyle) {
1316
- outputStyle = regexStyle;
1317
- styleSource = "explicit-regex";
1318
- }
1319
- }
1320
- // Pass 3b: style brain call — only when task detection ITSELF needed the
1321
- // brain (pass3LegacyTaskAttempted). When pass1 or pass2 already decided
1322
- // the task cheaply, the 800ms style call adds no signal (confirmed by
1323
- // 112/112 wasted calls in production — 100% returned styleSource=none).
1324
- // Default to "balanced" instead: clear, cheap, and accurate for most
1325
- // coding turns.
1326
- if (outputStyle === null && taskType !== null) {
1327
- if (pass3LegacyTaskAttempted) {
1328
- legacyBrainAttempted = true;
1329
- pass3LegacyStyleAttempted = true;
1330
- const brainRawStyle = await classifyViaBrain(`Detect the user's preferred output style. The prompt may be EN or VN.
1331
- Reply with ONE word: concise (ngắn gọn) | balanced (bình thường) | detailed (chi tiết).
1332
-
1333
- Prompt: "${ctx.raw.slice(0, 300)}"`, 800);
1334
- if (brainRawStyle) {
1335
- pass3LegacyStyleSucceeded = true;
1336
- const styleMatched = VALID_STYLES.find((s) => brainRawStyle.toLowerCase().includes(s));
1337
- if (styleMatched) {
1338
- outputStyle = styleMatched;
1339
- styleSource = "brain-legacy";
1340
- }
1341
- }
1342
- }
1343
- else if (opts.profileStyleBaseline) {
1344
- // WhoAmI v4.0 baseline: a standing communication.brevity/decision_speed
1345
- // preference (computed once in the pipeline from the on-device profile)
1346
- // fills in when no per-turn signal resolved the style. Per-turn detection
1347
- // above still wins (override); this only replaces the generic "balanced".
1348
- outputStyle = opts.profileStyleBaseline;
1349
- styleSource = "whoami-profile";
1350
- }
1351
- else {
1352
- outputStyle = "balanced";
1353
- styleSource = "classifier-default";
1354
- }
1355
- }
1356
- }
1357
- else if (unifiedFailed && outputStyle === null) {
1358
- // Cheap rescue path when unified PIL is enabled but its call failed:
1359
- // run only the free regex style detector. The L6 brain-rescue call is
1360
- // suppressed below by the `_brainData` sentinel so we don't repeat the
1361
- // same network round-trip that just timed out.
1362
- const regexStyle = detectStyleFromText(ctx.raw);
1363
- if (regexStyle) {
1364
- outputStyle = regexStyle;
1365
- styleSource = "explicit-regex";
1366
- }
1367
- }
1368
- if (intentKind === null && taskType !== null && taskType !== "general") {
1369
- intentKind = "task";
1370
- }
1371
- // Safety net (harness 817e508f57ee): an explicit command/tool-execution
1372
- // request must NEVER be chitchat. Chitchat drops the whole toolset (incl.
1373
- // bash) in message-processor, so a "run this command" turn would leave the
1374
- // agent unable to act. Only ever UPGRADES chitchat → task (never the
1375
- // reverse), so the token-saving for genuine greetings is preserved.
1376
- if (intentKind === "chitchat" && hasActionableToolIntent(ctx.raw)) {
1377
- intentKind = "task";
1378
- }
1379
- // L6 brain-rescue suppression sentinel. L6 only checks truthiness of
1380
- // _brainData to decide whether to spend another 50ms brain round-trip on
1381
- // style detection. If we either (a) succeeded with unified pilContext,
1382
- // (b) failed unified (network already down), or (c) attempted a legacy
1383
- // brain call here, then L6 has nothing new to learn — set a sentinel.
1384
- const brainDataOut = brainData ??
1385
- (unifiedFailed || legacyBrainAttempted
1386
- ? {
1387
- t0_principles: [],
1388
- t1_rules: [],
1389
- t2_patterns: [],
1390
- retrieval_skipped_reason: unifiedFailed ? "unified-failed" : "legacy-attempted",
1391
- }
1392
- : null);
1393
- // pass1Hit = Pass 1 alone decided the final outcome (no later pass overrode).
1394
- // Note: chitchat short-circuit overrides Pass 1, so we exclude that case.
1395
- const pass1Hit = pass1TaskType !== null &&
1396
- taskType === pass1TaskType &&
1397
- !pass2Hit &&
1398
- !pass25ChitchatHit &&
1399
- !pass3UnifiedSucceeded &&
1400
- !pass3LegacyTaskSucceeded;
1401
- const { complexity, score: complexityScore } = scoreComplexity({
1402
- rawText: ctx.raw,
1403
- taskType,
1404
- t0HitCount: 0, // TODO P2: feed from prior-run state.md if available
1405
- hasMaxSprintsOne: false, // TODO P2: thread CLI flag down through ctx
1406
- });
1407
- const intentTrace = {
1408
- pass1Reason: result.reason,
1409
- pass1Confidence: result.confidence,
1410
- pass1TaskType,
1411
- pass1Hit,
1412
- pass2Hit,
1413
- pass2Pattern,
1414
- pass25ChitchatHit,
1415
- pass3UnifiedAttempted: needsBrain,
1416
- pass3UnifiedSucceeded,
1417
- pass3LegacyTaskAttempted,
1418
- pass3LegacyTaskSucceeded,
1419
- pass3LegacyStyleAttempted,
1420
- pass3LegacyStyleSucceeded,
1421
- pass4LlmAttempted,
1422
- pass4LlmSucceeded,
1423
- styleSource,
1424
- finalTaskType: taskType,
1425
- finalConfidence: confidence,
1426
- complexity,
1427
- complexityScore,
1428
- };
1429
- return {
1430
- ...ctx,
1431
- taskType,
1432
- domain,
1433
- confidence,
1434
- outputStyle,
1435
- intentKind,
1436
- _brainData: brainDataOut,
1437
- _intentTrace: intentTrace,
749
+ styleSource: "none",
750
+ finalTaskType: null,
751
+ finalConfidence: 0,
752
+ complexity: "medium",
753
+ complexityScore: 0,
754
+ },
1438
755
  layers: [
1439
756
  ...ctx.layers,
1440
- {
1441
- name: "intent-detection",
1442
- applied: taskType !== null,
1443
- delta: taskType !== null
1444
- ? `taskType=${taskType},kind=${intentKind ?? "unknown"},conf=${confidence.toFixed(2)},domain=${domain ?? "none"},style=${outputStyle ?? "none"},unified=${brainData ? "ok" : unifiedFailed ? "fail" : "skip"},llm=${pass4LlmSucceeded ? "ok" : pass4LlmAttempted ? "fail" : "skip"}`
1445
- : unifiedFailed
1446
- ? `taskType=null,unified=fail,llm=${pass4LlmSucceeded ? "ok" : pass4LlmAttempted ? "fail" : "skip"}`
1447
- : null,
1448
- },
757
+ { name: "intent-detection", applied: false, delta: "no-model-classifier — UNKNOWN, NO regex cascade" },
1449
758
  ],
1450
759
  };
1451
760
  }