principles-disciple 1.72.0 → 1.74.0

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 (319) hide show
  1. package/INSTALL.md +1 -3
  2. package/openclaw.plugin.json +10 -5
  3. package/package.json +17 -19
  4. package/scripts/acceptance-test.mjs +16 -73
  5. package/scripts/sync-plugin.mjs +382 -77
  6. package/src/commands/archive-impl.ts +2 -1
  7. package/src/commands/capabilities.ts +2 -2
  8. package/src/commands/context.ts +2 -2
  9. package/src/commands/disable-impl.ts +2 -1
  10. package/src/commands/evolution-status.ts +16 -16
  11. package/src/commands/export.ts +12 -67
  12. package/src/commands/pain.ts +91 -1
  13. package/src/commands/principle-rollback.ts +2 -1
  14. package/src/commands/promote-impl.ts +7 -43
  15. package/src/commands/rollback-impl.ts +2 -1
  16. package/src/commands/rollback.ts +2 -1
  17. package/src/commands/samples.ts +2 -1
  18. package/src/commands/thinking-os.ts +2 -1
  19. package/src/config/errors.ts +18 -2
  20. package/src/constants/diagnostician.ts +2 -2
  21. package/src/constants/tools.ts +2 -1
  22. package/src/core/__tests__/focus-history.test.ts +210 -0
  23. package/src/core/config.ts +1 -1
  24. package/src/core/correction-cue-learner.ts +2 -136
  25. package/src/core/correction-types.ts +16 -88
  26. package/src/core/dictionary.ts +19 -20
  27. package/src/core/empathy-keyword-matcher.ts +17 -289
  28. package/src/core/empathy-types.ts +18 -229
  29. package/src/core/event-log.ts +29 -132
  30. package/src/core/evolution-reducer.ts +21 -2
  31. package/src/core/evolution-types.ts +76 -464
  32. package/src/core/file-store.ts +80 -0
  33. package/src/core/focus-history.ts +228 -955
  34. package/src/core/local-worker-routing.ts +34 -314
  35. package/src/core/merge-gate-audit.ts +0 -195
  36. package/src/core/migration.ts +0 -1
  37. package/src/core/pain-diagnostic-gate.ts +154 -0
  38. package/src/core/pain-signal.ts +21 -138
  39. package/src/core/pain.ts +15 -88
  40. package/src/core/path-resolver.ts +0 -1
  41. package/src/core/paths.ts +0 -1
  42. package/src/core/pd-task-reconciler.ts +26 -115
  43. package/src/core/pd-task-service.ts +9 -9
  44. package/src/core/pd-task-types.ts +23 -127
  45. package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +174 -0
  46. package/src/core/principle-compiler/code-validator.ts +15 -42
  47. package/src/core/principle-compiler/compiler.ts +100 -15
  48. package/src/core/principle-compiler/index.ts +5 -2
  49. package/src/core/principle-compiler/template-generator.ts +4 -104
  50. package/src/core/principle-injection.ts +10 -202
  51. package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +42 -0
  52. package/src/core/principle-internalization/lifecycle-read-model.ts +39 -242
  53. package/src/core/principle-internalization/principle-lifecycle-service.ts +12 -10
  54. package/src/core/principle-tree-ledger-adapter.ts +145 -0
  55. package/src/core/principle-tree-ledger.ts +8 -6
  56. package/src/core/reflection/reflection-context.ts +14 -109
  57. package/src/core/replay-engine.ts +8 -500
  58. package/src/core/rule-host-helpers.ts +5 -35
  59. package/src/core/rule-host-types.ts +10 -82
  60. package/src/core/rule-host.ts +6 -63
  61. package/src/core/runtime-v2-prompt-activation-reader.ts +231 -0
  62. package/src/core/session-tracker.ts +87 -101
  63. package/src/core/shadow-observation-registry.ts +19 -48
  64. package/src/core/trajectory.ts +3 -1
  65. package/src/core/workflow-funnel-loader.ts +62 -68
  66. package/src/core/workspace-context.ts +46 -0
  67. package/src/core/workspace-dir-service.ts +1 -1
  68. package/src/core/workspace-dir-validation.ts +18 -9
  69. package/src/hooks/AGENTS.md +1 -1
  70. package/src/hooks/gate-block-helper.ts +71 -64
  71. package/src/hooks/gate.ts +183 -31
  72. package/src/hooks/lifecycle.ts +30 -32
  73. package/src/hooks/llm.ts +60 -32
  74. package/src/hooks/pain.ts +297 -103
  75. package/src/hooks/prompt.ts +400 -440
  76. package/src/hooks/subagent.ts +2 -29
  77. package/src/i18n/commands.ts +2 -10
  78. package/src/index.ts +95 -85
  79. package/src/openclaw-sdk.ts +311 -0
  80. package/src/service/central-database.ts +8 -4
  81. package/src/service/evolution-queue-migration.ts +2 -1
  82. package/src/service/evolution-worker.ts +163 -1786
  83. package/src/service/internalization-trigger-adapter.ts +302 -0
  84. package/src/service/keyword-optimization-service.ts +4 -4
  85. package/src/service/monitoring-query-service.ts +1 -215
  86. package/src/service/queue-io.ts +60 -331
  87. package/src/service/runtime-summary-service.ts +59 -16
  88. package/src/service/subagent-workflow/index.ts +0 -41
  89. package/src/service/subagent-workflow/types.ts +9 -120
  90. package/src/service/subagent-workflow/workflow-store.ts +2 -119
  91. package/src/service/workflow-watchdog.ts +0 -43
  92. package/src/types/event-payload.ts +16 -74
  93. package/src/types/event-types.ts +38 -547
  94. package/src/types/hygiene-types.ts +7 -30
  95. package/src/types/principle-tree-schema.ts +20 -222
  96. package/src/types/queue.ts +15 -70
  97. package/src/types/runtime-summary.ts +5 -49
  98. package/src/utils/io.ts +8 -20
  99. package/src/utils/retry.ts +1 -1
  100. package/src/utils/shadow-fingerprint.ts +2 -2
  101. package/src/utils/workspace-resolver.ts +50 -0
  102. package/templates/langs/en/core/AGENTS.md +7 -7
  103. package/templates/langs/en/core/BOOT.md +1 -1
  104. package/templates/langs/en/core/HEARTBEAT.md +2 -2
  105. package/templates/langs/en/principles/THINKING_OS.md +3 -2
  106. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  107. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  108. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  109. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  110. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  111. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  112. package/templates/langs/en/skills/evolve-task/SKILL.md +3 -3
  113. package/templates/langs/en/skills/pd-cli-operator/SKILL.md +67 -0
  114. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +1 -1
  115. package/templates/langs/en/skills/pd-mentor/SKILL.md +2 -3
  116. package/templates/langs/en/skills/pd-pain-signal/SKILL.md +17 -39
  117. package/templates/langs/en/skills/pd-runtime-v2/SKILL.md +61 -0
  118. package/templates/langs/zh/core/AGENTS.md +7 -7
  119. package/templates/langs/zh/core/BOOT.md +1 -1
  120. package/templates/langs/zh/core/HEARTBEAT.md +2 -2
  121. package/templates/langs/zh/principles/THINKING_OS.md +3 -2
  122. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  123. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  124. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  125. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +8 -8
  126. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  127. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  128. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  129. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +21 -5
  130. package/templates/langs/zh/skills/evolve-task/SKILL.md +4 -4
  131. package/templates/langs/zh/skills/pd-cli-operator/SKILL.md +67 -0
  132. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +1 -1
  133. package/templates/langs/zh/skills/pd-mentor/SKILL.md +2 -3
  134. package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +17 -38
  135. package/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +61 -0
  136. package/tests/build-artifacts.test.ts +1 -3
  137. package/tests/commands/evolution-status.test.ts +0 -118
  138. package/tests/core/bootstrap-rules.test.ts +1 -1
  139. package/tests/core/config.test.ts +1 -1
  140. package/tests/core/event-log.test.ts +35 -0
  141. package/tests/core/evolution-engine.test.ts +610 -0
  142. package/tests/core/file-store.test.ts +102 -0
  143. package/tests/core/focus-history.test.ts +203 -11
  144. package/tests/core/merge-gate-audit.test.ts +2 -169
  145. package/tests/core/migration.test.ts +7 -7
  146. package/tests/core/model-deployment-registry.test.ts +7 -1
  147. package/tests/core/model-training-registry.test.ts +19 -0
  148. package/tests/core/observability.test.ts +0 -1
  149. package/tests/core/pain-diagnostic-gate.test.ts +498 -0
  150. package/tests/core/pain.test.ts +0 -1
  151. package/tests/core/path-resolver.test.ts +1 -1
  152. package/tests/core/paths-refactor.test.ts +0 -22
  153. package/tests/core/principle-internalization/deprecated-readiness.test.ts +2 -2
  154. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +2 -2
  155. package/tests/core/principle-internalization/{internalization-routing-policy.test.ts → lifecycle-routing-policy.test.ts} +6 -6
  156. package/tests/core/principle-internalization/lineage-source-retired.test.ts +56 -0
  157. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +1 -23
  158. package/tests/core/principle-tree-ledger-adapter.test.ts +253 -0
  159. package/tests/core/reflection-context.test.ts +0 -14
  160. package/tests/core/replay-engine.test.ts +127 -215
  161. package/tests/core/rule-host-helpers.test.ts +2 -2
  162. package/tests/core/rule-implementation-runtime.test.ts +0 -27
  163. package/tests/core/workflow-funnel-loader.test.ts +162 -0
  164. package/tests/core/workspace-context.test.ts +2 -2
  165. package/tests/core/workspace-dir-validation.test.ts +8 -1
  166. package/tests/core-anti-growth.test.ts +191 -0
  167. package/tests/hook-workspace-nextaction-contract.test.ts +42 -0
  168. package/tests/hooks/confirm-first-removal.test.ts +188 -0
  169. package/tests/hooks/gate-auto-correct-shadow.test.ts +310 -0
  170. package/tests/hooks/gate-auto-correct.test.ts +665 -0
  171. package/tests/hooks/gate-no-path-write-tool.test.ts +172 -0
  172. package/tests/hooks/gate-rule-host-pipeline.test.ts +2 -1
  173. package/tests/hooks/pain.test.ts +269 -12
  174. package/tests/hooks/prompt-characterization.test.ts +500 -0
  175. package/tests/hooks/prompt-size-guard.test.ts +32 -17
  176. package/tests/hooks/runtime-v2-prompt-activation.test.ts +869 -0
  177. package/tests/index.test.ts +94 -1
  178. package/tests/integration/auto-entry-gate.test.ts +248 -0
  179. package/tests/integration/internalization-trigger-guard.test.ts +69 -0
  180. package/tests/integration/m8-legacy-paths.test.ts +63 -0
  181. package/tests/integration/runtime-v2-pain-guard.test.ts +125 -0
  182. package/tests/plugin-config-resolution-cutover.test.ts +359 -0
  183. package/tests/runtime-v2-discovery-guard.test.ts +154 -0
  184. package/tests/service/central-database.test.ts +457 -0
  185. package/tests/service/evolution-worker.correction-observer.test.ts +173 -0
  186. package/tests/service/evolution-worker.timeout.test.ts +11 -129
  187. package/tests/service/internalization-trigger-adapter.test.ts +251 -0
  188. package/tests/service/monitoring-query-service.test.ts +1 -47
  189. package/tests/service/queue-io.test.ts +1 -62
  190. package/tests/service/runtime-summary-service.test.ts +3 -1
  191. package/tests/service/workflow-watchdog.test.ts +0 -91
  192. package/tests/utils/file-lock.test.ts +5 -3
  193. package/tests/utils/session-key.test.ts +52 -0
  194. package/tests/utils/subagent-probe.test.ts +48 -1
  195. package/vitest.config.ts +4 -11
  196. package/.planning/codebase/ARCHITECTURE.md +0 -157
  197. package/.planning/codebase/CONCERNS.md +0 -145
  198. package/.planning/codebase/CONVENTIONS.md +0 -148
  199. package/.planning/codebase/INTEGRATIONS.md +0 -81
  200. package/.planning/codebase/STACK.md +0 -87
  201. package/.planning/codebase/STRUCTURE.md +0 -193
  202. package/.planning/codebase/TESTING.md +0 -243
  203. package/.planning/phases/01-basic-visualization/01-GAP-CLOSURE-VERIFICATION.md +0 -113
  204. package/docs/COMMAND_REFERENCE.md +0 -76
  205. package/docs/COMMAND_REFERENCE_EN.md +0 -79
  206. package/scripts/build-web.mjs +0 -46
  207. package/scripts/diagnose-nocturnal.mjs +0 -537
  208. package/scripts/seed-nocturnal-scenarios.mjs +0 -384
  209. package/src/commands/nocturnal-review.ts +0 -322
  210. package/src/commands/nocturnal-rollout.ts +0 -790
  211. package/src/commands/nocturnal-train.ts +0 -986
  212. package/src/commands/pd-reflect.ts +0 -88
  213. package/src/core/adaptive-thresholds.ts +0 -478
  214. package/src/core/diagnostician-task-store.ts +0 -192
  215. package/src/core/nocturnal-arbiter.ts +0 -715
  216. package/src/core/nocturnal-artifact-lineage.ts +0 -116
  217. package/src/core/nocturnal-artificer.ts +0 -257
  218. package/src/core/nocturnal-candidate-scoring.ts +0 -530
  219. package/src/core/nocturnal-compliance.ts +0 -1146
  220. package/src/core/nocturnal-dataset.ts +0 -763
  221. package/src/core/nocturnal-executability.ts +0 -428
  222. package/src/core/nocturnal-export.ts +0 -499
  223. package/src/core/nocturnal-paths.ts +0 -240
  224. package/src/core/nocturnal-reasoning-deriver.ts +0 -343
  225. package/src/core/nocturnal-rule-implementation-validator.ts +0 -246
  226. package/src/core/nocturnal-snapshot-contract.ts +0 -99
  227. package/src/core/nocturnal-trajectory-extractor.ts +0 -512
  228. package/src/core/nocturnal-trinity-types.ts +0 -218
  229. package/src/core/nocturnal-trinity.ts +0 -2680
  230. package/src/core/principle-internalization/deprecated-readiness.ts +0 -93
  231. package/src/core/principle-internalization/internalization-routing-policy.ts +0 -208
  232. package/src/core/principle-internalization/lifecycle-metrics.ts +0 -152
  233. package/src/http/principles-console-route.ts +0 -709
  234. package/src/service/central-health-service.ts +0 -49
  235. package/src/service/central-overview-service.ts +0 -138
  236. package/src/service/control-ui-query-service.ts +0 -900
  237. package/src/service/cooldown-strategy.ts +0 -97
  238. package/src/service/evolution-pain-context.ts +0 -79
  239. package/src/service/evolution-query-service.ts +0 -407
  240. package/src/service/health-query-service.ts +0 -1038
  241. package/src/service/nocturnal-config.ts +0 -214
  242. package/src/service/nocturnal-runtime.ts +0 -734
  243. package/src/service/nocturnal-service.ts +0 -1605
  244. package/src/service/nocturnal-target-selector.ts +0 -545
  245. package/src/service/sleep-cycle.ts +0 -157
  246. package/src/service/startup-reconciler.ts +0 -112
  247. package/src/service/subagent-workflow/correction-observer-types.ts +0 -82
  248. package/src/service/subagent-workflow/correction-observer-workflow-manager.ts +0 -250
  249. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +0 -1
  250. package/src/service/subagent-workflow/dynamic-timeout.ts +0 -30
  251. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +0 -268
  252. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +0 -795
  253. package/src/service/subagent-workflow/runtime-direct-driver.ts +0 -268
  254. package/src/service/subagent-workflow/workflow-manager-base.ts +0 -580
  255. package/src/tools/write-pain-flag.ts +0 -215
  256. package/templates/langs/en/skills/plan-script/SKILL.md +0 -32
  257. package/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
  258. package/tests/commands/nocturnal-review.test.ts +0 -448
  259. package/tests/commands/nocturnal-train.test.ts +0 -97
  260. package/tests/commands/pd-reflect.test.ts +0 -49
  261. package/tests/core/adaptive-thresholds.test.ts +0 -261
  262. package/tests/core/nocturnal-arbiter.test.ts +0 -559
  263. package/tests/core/nocturnal-artifact-lineage.test.ts +0 -53
  264. package/tests/core/nocturnal-artificer.test.ts +0 -241
  265. package/tests/core/nocturnal-candidate-scoring.test.ts +0 -532
  266. package/tests/core/nocturnal-compliance-p-principles.test.ts +0 -133
  267. package/tests/core/nocturnal-compliance.test.ts +0 -646
  268. package/tests/core/nocturnal-dataset.test.ts +0 -892
  269. package/tests/core/nocturnal-e2e.test.ts +0 -234
  270. package/tests/core/nocturnal-executability.test.ts +0 -357
  271. package/tests/core/nocturnal-export.test.ts +0 -517
  272. package/tests/core/nocturnal-reasoning-deriver.test.ts +0 -372
  273. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +0 -428
  274. package/tests/core/nocturnal-rule-implementation-validator.test.ts +0 -127
  275. package/tests/core/nocturnal-snapshot-contract.test.ts +0 -121
  276. package/tests/core/nocturnal-trajectory-extractor.test.ts +0 -634
  277. package/tests/core/nocturnal-trinity.test.ts +0 -2053
  278. package/tests/core/pain-auto-repair.test.ts +0 -96
  279. package/tests/core/pain-integration.test.ts +0 -510
  280. package/tests/fixtures/nocturnal-reviewed-subset.json +0 -183
  281. package/tests/http/principles-console-route.test.ts +0 -162
  282. package/tests/integration/chaos-resilience.test.ts +0 -348
  283. package/tests/integration/empathy-workflow-integration.test.ts +0 -626
  284. package/tests/integration/pain-diagnostician-loop.e2e.test.ts +0 -380
  285. package/tests/service/control-ui-query-service.test.ts +0 -121
  286. package/tests/service/cooldown-strategy.test.ts +0 -164
  287. package/tests/service/data-endpoints-regression.test.ts +0 -834
  288. package/tests/service/empathy-observer-workflow-manager.test.ts +0 -175
  289. package/tests/service/evolution-worker.nocturnal.test.ts +0 -601
  290. package/tests/service/nocturnal-runtime-hardening.test.ts +0 -118
  291. package/tests/service/nocturnal-runtime.test.ts +0 -473
  292. package/tests/service/nocturnal-service-code-candidate.test.ts +0 -330
  293. package/tests/service/nocturnal-target-selector.test.ts +0 -615
  294. package/tests/service/startup-reconciler.test.ts +0 -148
  295. package/tests/tools/write-pain-flag.test.ts +0 -358
  296. package/ui/src/App.tsx +0 -45
  297. package/ui/src/api.ts +0 -220
  298. package/ui/src/charts.tsx +0 -955
  299. package/ui/src/components/ErrorState.tsx +0 -6
  300. package/ui/src/components/Loading.tsx +0 -13
  301. package/ui/src/components/ProtectedRoute.tsx +0 -12
  302. package/ui/src/components/Shell.tsx +0 -91
  303. package/ui/src/components/WorkspaceConfig.tsx +0 -178
  304. package/ui/src/components/index.ts +0 -5
  305. package/ui/src/context/auth.tsx +0 -80
  306. package/ui/src/context/theme.tsx +0 -66
  307. package/ui/src/hooks/useAutoRefresh.ts +0 -39
  308. package/ui/src/i18n/ui.ts +0 -473
  309. package/ui/src/main.tsx +0 -16
  310. package/ui/src/pages/EvolutionPage.tsx +0 -333
  311. package/ui/src/pages/FeedbackPage.tsx +0 -138
  312. package/ui/src/pages/GateMonitorPage.tsx +0 -136
  313. package/ui/src/pages/LoginPage.tsx +0 -89
  314. package/ui/src/pages/OverviewPage.tsx +0 -599
  315. package/ui/src/pages/SamplesPage.tsx +0 -174
  316. package/ui/src/pages/ThinkingModelsPage.tsx +0 -702
  317. package/ui/src/styles.css +0 -2020
  318. package/ui/src/types.ts +0 -384
  319. package/ui/src/utils/format.ts +0 -15
@@ -1,900 +0,0 @@
1
- import { ControlUiDatabase } from '../core/control-ui-db.js';
2
- import { getThinkingModel, listThinkingModels, getThinkingModelDefinitions } from '../core/thinking-models.js';
3
- import { WorkspaceContext } from '../core/workspace-context.js';
4
-
5
- /** Time window (in minutes) for querying principle events related to a sample */
6
- const PRINCIPLE_EVENT_WINDOW_MINUTES = 10;
7
-
8
- export interface OverviewResponse {
9
- workspaceDir: string;
10
- generatedAt: string;
11
- dataFreshness: string | null;
12
- dataSource: 'trajectory_db_analytics';
13
- runtimeControlPlaneSource: 'pd_evolution_status';
14
- summary: {
15
- repeatErrorRate: number;
16
- userCorrectionRate: number;
17
- pendingSamples: number;
18
- approvedSamples: number;
19
- thinkingCoverageRate: number;
20
- painEvents: number;
21
- principleEventCount: number;
22
- gateBlocks: number;
23
- taskOutcomes: number;
24
- };
25
- dailyTrend: {
26
- day: string;
27
- toolCalls: number;
28
- failures: number;
29
- userCorrections: number;
30
- thinkingTurns: number;
31
- }[];
32
- topRegressions: {
33
- toolName: string;
34
- errorType: string;
35
- occurrences: number;
36
- }[];
37
- sampleQueue: {
38
- counters: Record<string, number>;
39
- preview: {
40
- sampleId: string;
41
- sessionId: string;
42
- qualityScore: number;
43
- reviewStatus: string;
44
- createdAt: string;
45
- }[];
46
- };
47
- thinkingSummary: {
48
- activeModels: number;
49
- dormantModels: number;
50
- effectiveModels: number;
51
- coverageRate: number;
52
- modelBreakdown?: { modelId: string; hits: number }[];
53
- modelDefinitions?: { modelId: string; name: string; description: string }[];
54
- };
55
- }
56
-
57
- export interface SampleListFilters {
58
- status?: string;
59
- qualityMin?: number;
60
- dateFrom?: string;
61
- dateTo?: string;
62
- failureMode?: string;
63
- page?: number;
64
- pageSize?: number;
65
- }
66
-
67
- export interface SamplesResponse {
68
- counters: Record<string, number>;
69
- items: {
70
- sampleId: string;
71
- sessionId: string;
72
- reviewStatus: string;
73
- qualityScore: number;
74
- failureMode: string;
75
- relatedThinkingCount: number;
76
- createdAt: string;
77
- updatedAt: string;
78
- diffExcerpt: string;
79
- }[];
80
- pagination: {
81
- page: number;
82
- pageSize: number;
83
- total: number;
84
- totalPages: number;
85
- };
86
- }
87
-
88
- export interface SampleDetailResponse {
89
- sampleId: string;
90
- sessionId: string;
91
- reviewStatus: string;
92
- qualityScore: number;
93
- createdAt: string;
94
- updatedAt: string;
95
- badAttempt: {
96
- assistantTurnId: number;
97
- rawText: string;
98
- sanitizedText: string;
99
- createdAt: string;
100
- };
101
- userCorrection: {
102
- userTurnId: number;
103
- rawText: string;
104
- correctionCue: string | null;
105
- createdAt: string;
106
- };
107
- recoveryToolSpan: { id: number; toolName: string }[];
108
- relatedPrinciples: {
109
- principleId: string | null;
110
- eventType: string;
111
- createdAt: string;
112
- }[];
113
- relatedThinkingHits: {
114
- id: number;
115
- modelId: string;
116
- modelName: string;
117
- matchedPattern: string;
118
- scenarios: string[];
119
- createdAt: string;
120
- triggerExcerpt: string;
121
- }[];
122
- reviewHistory: {
123
- reviewStatus: string;
124
- note: string | null;
125
- createdAt: string;
126
- }[];
127
- }
128
-
129
- export interface ThinkingModelSummary {
130
- modelId: string;
131
- name: string;
132
- description: string;
133
- hits: number;
134
- coverageRate: number;
135
- successRate: number;
136
- failureRate: number;
137
- painRate: number;
138
- correctionRate: number;
139
- correctionSampleRate: number;
140
- commonScenarios: string[];
141
- recommendation: 'reinforce' | 'rework' | 'archive';
142
- }
143
-
144
- export interface ThinkingOverviewResponse {
145
- summary: {
146
- totalModels: number;
147
- activeModels: number;
148
- dormantModels: number;
149
- effectiveModels: number;
150
- coverageRate: number;
151
- };
152
- topModels: ThinkingModelSummary[];
153
- dormantModels: {
154
- modelId: string;
155
- name: string;
156
- description: string;
157
- }[];
158
- effectiveModels: ThinkingModelSummary[];
159
- scenarioMatrix: {
160
- modelId: string;
161
- modelName: string;
162
- scenario: string;
163
- hits: number;
164
- }[];
165
- coverageTrend: {
166
- day: string;
167
- assistantTurns: number;
168
- thinkingTurns: number;
169
- coverageRate: number;
170
- }[];
171
- }
172
-
173
- export interface ThinkingModelDetailResponse {
174
- modelMeta: {
175
- modelId: string;
176
- name: string;
177
- description: string;
178
- hits: number;
179
- coverageRate: number;
180
- recommendation: 'reinforce' | 'rework' | 'archive';
181
- };
182
- usageTrend: {
183
- day: string;
184
- hits: number;
185
- }[];
186
- scenarioDistribution: {
187
- scenario: string;
188
- hits: number;
189
- }[];
190
- outcomeStats: {
191
- events: number;
192
- successRate: number;
193
- failureRate: number;
194
- painRate: number;
195
- correctionRate: number;
196
- correctionSampleRate: number;
197
- };
198
- recentEvents: {
199
- id: number;
200
- createdAt: string;
201
- matchedPattern: string;
202
- scenarios: string[];
203
- triggerExcerpt: string;
204
- toolContext: { toolName: string; outcome: string; errorType?: string | null }[];
205
- painContext: { source: string; score: number }[];
206
- principleContext: { principleId: string | null; eventType: string }[];
207
- }[];
208
- }
209
-
210
- function parseJson<T>(raw: string | null | undefined, fallback: T): T {
211
- if (!raw) return fallback;
212
- try {
213
- return JSON.parse(raw) as T;
214
- } catch {
215
- return fallback;
216
- }
217
- }
218
-
219
- function roundRate(numerator: number, denominator: number): number {
220
- if (!denominator) return 0;
221
- return Number((numerator / denominator).toFixed(4));
222
- }
223
-
224
- function clampPageSize(input?: number): number {
225
- if (!Number.isFinite(input)) return 20;
226
- return Math.min(100, Math.max(1, Number(input)));
227
- }
228
-
229
- function summarizeRecommendation(model: {
230
- hits: number;
231
- successRate: number;
232
- failureRate: number;
233
- painRate: number;
234
- correctionRate: number;
235
- }): 'reinforce' | 'rework' | 'archive' {
236
- if (model.hits === 0) return 'archive';
237
- if (model.failureRate > model.successRate || model.correctionRate >= 0.35 || model.painRate >= 0.3) {
238
- return 'rework';
239
- }
240
- return 'reinforce';
241
- }
242
-
243
- export class ControlUiQueryService {
244
- private readonly workspaceDir: string;
245
- private readonly trajectory;
246
- private readonly uiDb: ControlUiDatabase;
247
-
248
- constructor(workspaceDir: string) {
249
- this.workspaceDir = workspaceDir;
250
- this.trajectory = WorkspaceContext.fromHookContext({ workspaceDir }).trajectory;
251
- this.uiDb = new ControlUiDatabase({ workspaceDir });
252
- }
253
-
254
- dispose(): void {
255
- this.uiDb.dispose();
256
- }
257
-
258
-
259
- getOverview(days = 30): OverviewResponse {
260
- const stats = this.trajectory.getDataStats();
261
- const regressionRows = this.uiDb.all<{
262
- tool_name: string;
263
- error_type: string;
264
- occurrences: number;
265
- }>('SELECT tool_name, error_type, occurrences FROM v_error_clusters ORDER BY occurrences DESC LIMIT 5');
266
- const failureStats = this.uiDb.get<{ total_failures: number; repeated_failures: number }>(`
267
- SELECT
268
- COALESCE(SUM(occurrences), 0) AS total_failures,
269
- COALESCE(SUM(CASE WHEN occurrences > 1 THEN occurrences ELSE 0 END), 0) AS repeated_failures
270
- FROM v_error_clusters
271
- `) ?? { total_failures: 0, repeated_failures: 0 };
272
- const correctionTotal = this.uiDb.get<{ count: number }>(
273
- 'SELECT COUNT(*) AS count FROM user_turns WHERE correction_detected = 1',
274
- )?.count ?? 0;
275
- const principleEventCount = this.uiDb.get<{ count: number }>(
276
- 'SELECT COUNT(*) AS count FROM principle_events',
277
- )?.count ?? 0;
278
- const gateBlockCount = this.uiDb.get<{ count: number }>(
279
- 'SELECT COUNT(*) AS count FROM gate_blocks',
280
- )?.count ?? 0;
281
- const taskOutcomeCount = this.uiDb.get<{ count: number }>(
282
- 'SELECT COUNT(*) AS count FROM task_outcomes',
283
- )?.count ?? 0;
284
- const sampleCounters = this.uiDb.all<{ review_status: string; total: number }>(
285
- 'SELECT review_status, total FROM v_sample_queue',
286
- );
287
- const samplePreview = this.uiDb.all<{
288
- sample_id: string;
289
- session_id: string;
290
- quality_score: number;
291
- review_status: string;
292
- created_at: string;
293
- }>(`
294
- SELECT sample_id, session_id, quality_score, review_status, created_at
295
- FROM correction_samples
296
- ORDER BY created_at DESC
297
- LIMIT 5
298
- `);
299
- const coverageRow = this.uiDb.get<{ thinking_turns: number; assistant_turns: number }>(`
300
- SELECT
301
- COUNT(DISTINCT assistant_turn_id) AS thinking_turns,
302
- (SELECT COUNT(*) FROM assistant_turns) AS assistant_turns
303
- FROM thinking_model_events
304
- `) ?? { thinking_turns: 0, assistant_turns: 0 };
305
- const effectiveCount = this.uiDb.all<{
306
- events: number;
307
- success_windows: number;
308
- failure_windows: number;
309
- pain_windows: number;
310
- correction_windows: number;
311
- }>('SELECT events, success_windows, failure_windows, pain_windows, correction_windows FROM v_thinking_model_effectiveness')
312
- .filter((row) => summarizeRecommendation({
313
- hits: Number(row.events),
314
- successRate: roundRate(Number(row.success_windows), Number(row.events)),
315
- failureRate: roundRate(Number(row.failure_windows), Number(row.events)),
316
- painRate: roundRate(Number(row.pain_windows), Number(row.events)),
317
- correctionRate: roundRate(Number(row.correction_windows), Number(row.events)),
318
- }) === 'reinforce').length;
319
- const modelBreakdown = this.uiDb.all<{ modelId: string; hits: number }>(`
320
- SELECT model_id as modelId, COUNT(*) as hits
321
- FROM thinking_model_events
322
- GROUP BY model_id
323
- ORDER BY hits DESC
324
- `).map(row => ({ modelId: row.modelId, hits: Number(row.hits) }));
325
- const dailyTrend = this.uiDb.all<{
326
- day: string;
327
- tool_calls: number;
328
- failures: number;
329
- user_corrections: number;
330
- thinking_turns: number;
331
- }>(`
332
- WITH thinking_daily AS (
333
- SELECT substr(created_at, 1, 10) AS day, COUNT(DISTINCT assistant_turn_id) AS thinking_turns
334
- FROM thinking_model_events
335
- GROUP BY substr(created_at, 1, 10)
336
- )
337
- SELECT
338
- dm.day AS day,
339
- dm.tool_calls AS tool_calls,
340
- dm.failures AS failures,
341
- dm.user_corrections AS user_corrections,
342
- COALESCE(td.thinking_turns, 0) AS thinking_turns
343
- FROM v_daily_metrics dm
344
- LEFT JOIN thinking_daily td ON td.day = dm.day
345
- ORDER BY dm.day DESC
346
- LIMIT ?
347
- `, days).reverse();
348
- const counters = Object.fromEntries(sampleCounters.map((row) => [row.review_status, Number(row.total)]));
349
- const activeModels = this.uiDb.get<{ count: number }>(
350
- 'SELECT COUNT(DISTINCT model_id) AS count FROM thinking_model_events',
351
- )?.count ?? 0;
352
-
353
- return {
354
- workspaceDir: this.workspaceDir,
355
- generatedAt: new Date().toISOString(),
356
- dataFreshness: stats.lastIngestAt,
357
- dataSource: 'trajectory_db_analytics',
358
- runtimeControlPlaneSource: 'pd_evolution_status',
359
- summary: {
360
- repeatErrorRate: roundRate(Number(failureStats.repeated_failures), Number(failureStats.total_failures)),
361
- userCorrectionRate: roundRate(correctionTotal, stats.userTurns),
362
- pendingSamples: stats.pendingSamples,
363
- approvedSamples: stats.approvedSamples,
364
- thinkingCoverageRate: roundRate(coverageRow.thinking_turns, coverageRow.assistant_turns),
365
- painEvents: stats.painEvents,
366
- principleEventCount,
367
- gateBlocks: Number(gateBlockCount),
368
- taskOutcomes: Number(taskOutcomeCount),
369
- },
370
- dailyTrend: dailyTrend.map((row) => ({
371
- day: row.day,
372
- toolCalls: Number(row.tool_calls),
373
- failures: Number(row.failures),
374
- userCorrections: Number(row.user_corrections),
375
- thinkingTurns: Number(row.thinking_turns),
376
- })),
377
- topRegressions: regressionRows.map((row) => ({
378
- toolName: row.tool_name,
379
- errorType: row.error_type,
380
- occurrences: Number(row.occurrences),
381
- })),
382
- sampleQueue: {
383
- counters,
384
- preview: samplePreview.map((row) => ({
385
- sampleId: row.sample_id,
386
- sessionId: row.session_id,
387
- qualityScore: Number(row.quality_score),
388
- reviewStatus: row.review_status,
389
- createdAt: row.created_at,
390
- })),
391
- },
392
- thinkingSummary: {
393
- activeModels,
394
- dormantModels: Math.max(0, listThinkingModels().length - activeModels),
395
- effectiveModels: effectiveCount,
396
- coverageRate: roundRate(coverageRow.thinking_turns, coverageRow.assistant_turns),
397
- modelBreakdown,
398
- modelDefinitions: getThinkingModelDefinitions(),
399
- },
400
- };
401
- }
402
-
403
-
404
- listSamples(filters: SampleListFilters = {}): SamplesResponse {
405
- const page = Math.max(1, Number(filters.page ?? 1));
406
- const pageSize = clampPageSize(filters.pageSize);
407
- const offset = (page - 1) * pageSize;
408
- const where: string[] = [];
409
- const params: unknown[] = [];
410
-
411
- if (filters.status && filters.status !== 'all') {
412
- where.push('cs.review_status = ?');
413
- params.push(filters.status);
414
- }
415
- if (Number.isFinite(filters.qualityMin)) {
416
- where.push('cs.quality_score >= ?');
417
- params.push(Number(filters.qualityMin));
418
- }
419
- if (filters.dateFrom) {
420
- where.push('cs.created_at >= ?');
421
- params.push(filters.dateFrom);
422
- }
423
- if (filters.dateTo) {
424
- where.push('cs.created_at <= ?');
425
- params.push(filters.dateTo);
426
- }
427
- if (filters.failureMode) {
428
- where.push(`
429
- COALESCE(
430
- (
431
- SELECT COALESCE(tc.error_type, tc.tool_name)
432
- FROM tool_calls tc
433
- WHERE tc.session_id = cs.session_id
434
- AND tc.outcome = 'failure'
435
- AND tc.created_at <= ut.created_at
436
- ORDER BY tc.created_at DESC
437
- LIMIT 1
438
- ),
439
- 'unknown'
440
- ) = ?
441
- `);
442
- params.push(filters.failureMode);
443
- }
444
-
445
- const whereClause = where.length > 0 ? `WHERE ${where.join(' AND ')}` : '';
446
- const total = Number(this.uiDb.get<{ count: number }>(`
447
- SELECT COUNT(*) AS count
448
- FROM correction_samples cs
449
- JOIN user_turns ut ON ut.id = cs.user_correction_turn_id
450
- ${whereClause}
451
- `, ...params)?.count ?? 0);
452
-
453
- const items = this.uiDb.all<{
454
- sample_id: string;
455
- session_id: string;
456
- review_status: string;
457
- quality_score: number;
458
- created_at: string;
459
- updated_at: string;
460
- diff_excerpt: string;
461
- failure_mode: string;
462
- related_thinking_count: number;
463
- }>(`
464
- SELECT
465
- cs.sample_id,
466
- cs.session_id,
467
- cs.review_status,
468
- cs.quality_score,
469
- cs.created_at,
470
- cs.updated_at,
471
- cs.diff_excerpt,
472
- COALESCE(
473
- (
474
- SELECT COALESCE(tc.error_type, tc.tool_name)
475
- FROM tool_calls tc
476
- WHERE tc.session_id = cs.session_id
477
- AND tc.outcome = 'failure'
478
- AND tc.created_at <= ut.created_at
479
- ORDER BY tc.created_at DESC
480
- LIMIT 1
481
- ),
482
- 'unknown'
483
- ) AS failure_mode,
484
- (
485
- SELECT COUNT(*)
486
- FROM thinking_model_events tme
487
- JOIN assistant_turns at2 ON at2.id = cs.bad_assistant_turn_id
488
- WHERE tme.session_id = cs.session_id
489
- AND tme.created_at >= at2.created_at
490
- AND tme.created_at <= ut.created_at
491
- ) AS related_thinking_count
492
- FROM correction_samples cs
493
- JOIN user_turns ut ON ut.id = cs.user_correction_turn_id
494
- ${whereClause}
495
- ORDER BY cs.created_at DESC
496
- LIMIT ? OFFSET ?
497
- `, ...params, pageSize, offset);
498
- const counters = this.uiDb.all<{ review_status: string; count: number }>(`
499
- SELECT review_status, COUNT(*) AS count
500
- FROM correction_samples
501
- GROUP BY review_status
502
- `);
503
-
504
- return {
505
- counters: Object.fromEntries(counters.map((row) => [row.review_status, Number(row.count)])),
506
- items: items.map((row) => ({
507
- sampleId: row.sample_id,
508
- sessionId: row.session_id,
509
- reviewStatus: row.review_status,
510
- qualityScore: Number(row.quality_score),
511
- failureMode: row.failure_mode,
512
- relatedThinkingCount: Number(row.related_thinking_count),
513
- createdAt: row.created_at,
514
- updatedAt: row.updated_at,
515
- diffExcerpt: row.diff_excerpt,
516
- })),
517
- pagination: {
518
- page,
519
- pageSize,
520
- total,
521
- totalPages: total === 0 ? 0 : Math.ceil(total / pageSize),
522
- },
523
- };
524
- }
525
-
526
- getSampleDetail(sampleId: string): SampleDetailResponse | null {
527
- const row = this.uiDb.get<{
528
- sample_id: string;
529
- session_id: string;
530
- review_status: string;
531
- quality_score: number;
532
- created_at: string;
533
- updated_at: string;
534
- recovery_tool_span_json: string;
535
- principle_ids_json: string;
536
- bad_turn_id: number;
537
- bad_raw_text: string | null;
538
- bad_blob_ref: string | null;
539
- bad_sanitized_text: string;
540
- bad_created_at: string;
541
- user_turn_id: number;
542
- user_raw_text: string | null;
543
- user_blob_ref: string | null;
544
- user_correction_cue: string | null;
545
- user_created_at: string;
546
- }>(`
547
- SELECT
548
- cs.sample_id,
549
- cs.session_id,
550
- cs.review_status,
551
- cs.quality_score,
552
- cs.created_at,
553
- cs.updated_at,
554
- cs.recovery_tool_span_json,
555
- cs.principle_ids_json,
556
- at.id AS bad_turn_id,
557
- at.raw_text AS bad_raw_text,
558
- at.blob_ref AS bad_blob_ref,
559
- at.sanitized_text AS bad_sanitized_text,
560
- at.created_at AS bad_created_at,
561
- ut.id AS user_turn_id,
562
- ut.raw_text AS user_raw_text,
563
- ut.blob_ref AS user_blob_ref,
564
- ut.correction_cue AS user_correction_cue,
565
- ut.created_at AS user_created_at
566
- FROM correction_samples cs
567
- JOIN assistant_turns at ON at.id = cs.bad_assistant_turn_id
568
- JOIN user_turns ut ON ut.id = cs.user_correction_turn_id
569
- WHERE cs.sample_id = ?
570
- `, sampleId);
571
- if (!row) return null;
572
-
573
- const reviewHistory = this.uiDb.all<{
574
- review_status: string;
575
- note: string | null;
576
- created_at: string;
577
- }>(`
578
- SELECT review_status, note, created_at
579
- FROM sample_reviews
580
- WHERE sample_id = ?
581
- ORDER BY created_at DESC
582
- `, sampleId);
583
- const relatedThinkingHits = this.uiDb.all<{
584
- id: number;
585
- model_id: string;
586
- matched_pattern: string;
587
- scenario_json: string;
588
- created_at: string;
589
- trigger_excerpt: string;
590
- }>(`
591
- SELECT id, model_id, matched_pattern, scenario_json, created_at, trigger_excerpt
592
- FROM thinking_model_events
593
- WHERE session_id = ?
594
- AND created_at >= ?
595
- AND created_at <= ?
596
- ORDER BY created_at DESC
597
- LIMIT 20
598
- `, row.session_id, row.bad_created_at, row.user_created_at);
599
- const relatedPrinciples = this.uiDb.all<{
600
- principle_id: string | null;
601
- event_type: string;
602
- created_at: string;
603
- }>(`
604
- SELECT principle_id, event_type, created_at
605
- FROM principle_events
606
- WHERE created_at >= ?
607
- AND created_at <= datetime(?, '+' || ? || ' minutes')
608
- ORDER BY created_at DESC
609
- LIMIT 20
610
- `, row.bad_created_at, row.user_created_at, PRINCIPLE_EVENT_WINDOW_MINUTES);
611
- const seededPrincipleIds = parseJson<string[]>(row.principle_ids_json, []).map((principleId) => ({
612
- principleId,
613
- eventType: 'seeded_from_sample',
614
- createdAt: row.created_at,
615
- }));
616
-
617
- return {
618
- sampleId: row.sample_id,
619
- sessionId: row.session_id,
620
- reviewStatus: row.review_status,
621
- qualityScore: Number(row.quality_score),
622
- createdAt: row.created_at,
623
- updatedAt: row.updated_at,
624
- badAttempt: {
625
- assistantTurnId: Number(row.bad_turn_id),
626
- rawText: this.uiDb.restoreRawText(row.bad_raw_text, row.bad_blob_ref),
627
- sanitizedText: row.bad_sanitized_text,
628
- createdAt: row.bad_created_at,
629
- },
630
- userCorrection: {
631
- userTurnId: Number(row.user_turn_id),
632
- rawText: this.uiDb.restoreRawText(row.user_raw_text, row.user_blob_ref),
633
- correctionCue: row.user_correction_cue,
634
- createdAt: row.user_created_at,
635
- },
636
- recoveryToolSpan: parseJson<{ id: number; toolName: string }[]>(row.recovery_tool_span_json, []),
637
- relatedPrinciples: [
638
- ...seededPrincipleIds,
639
- ...relatedPrinciples.map((item) => ({
640
- principleId: item.principle_id,
641
- eventType: item.event_type,
642
- createdAt: item.created_at,
643
- })),
644
- ],
645
- relatedThinkingHits: relatedThinkingHits.map((item) => ({
646
- id: Number(item.id),
647
- modelId: item.model_id,
648
- modelName: getThinkingModel(item.model_id)?.name ?? item.model_id,
649
- matchedPattern: item.matched_pattern,
650
- scenarios: parseJson<string[]>(item.scenario_json, []),
651
- createdAt: item.created_at,
652
- triggerExcerpt: item.trigger_excerpt,
653
- })),
654
- reviewHistory: reviewHistory.map((item) => ({
655
- reviewStatus: item.review_status,
656
- note: item.note,
657
- createdAt: item.created_at,
658
- })),
659
- };
660
- }
661
-
662
- reviewSample(sampleId: string, decision: 'approved' | 'rejected', note?: string) {
663
- return this.trajectory.reviewCorrectionSample(sampleId, decision, note);
664
- }
665
-
666
- exportCorrections(mode: 'raw' | 'redacted') {
667
- return this.trajectory.exportCorrections({ mode, approvedOnly: true });
668
- }
669
-
670
- getThinkingOverview(): ThinkingOverviewResponse {
671
- const topModels = this.loadThinkingModelSummaries();
672
- const knownModels = listThinkingModels();
673
- const activeIds = new Set(topModels.filter((model) => model.hits > 0).map((model) => model.modelId));
674
- const dormantModels = knownModels
675
- .filter((model) => !activeIds.has(model.id))
676
- .map((model) => ({
677
- modelId: model.id,
678
- name: model.name,
679
- description: model.description,
680
- }));
681
- const coverageRow = this.uiDb.get<{ thinking_turns: number; assistant_turns: number }>(`
682
- SELECT
683
- COUNT(DISTINCT assistant_turn_id) AS thinking_turns,
684
- (SELECT COUNT(*) FROM assistant_turns) AS assistant_turns
685
- FROM thinking_model_events
686
- `) ?? { thinking_turns: 0, assistant_turns: 0 };
687
- const coverageTrend = this.uiDb.all<{
688
- day: string;
689
- assistant_turns: number;
690
- thinking_turns: number;
691
- }>(`
692
- WITH assistant_daily AS (
693
- SELECT substr(created_at, 1, 10) AS day, COUNT(*) AS assistant_turns
694
- FROM assistant_turns
695
- GROUP BY substr(created_at, 1, 10)
696
- ),
697
- thinking_daily AS (
698
- SELECT substr(created_at, 1, 10) AS day, COUNT(DISTINCT assistant_turn_id) AS thinking_turns
699
- FROM thinking_model_events
700
- GROUP BY substr(created_at, 1, 10)
701
- )
702
- SELECT
703
- assistant_daily.day AS day,
704
- assistant_daily.assistant_turns AS assistant_turns,
705
- COALESCE(thinking_daily.thinking_turns, 0) AS thinking_turns
706
- FROM assistant_daily
707
- LEFT JOIN thinking_daily ON thinking_daily.day = assistant_daily.day
708
- ORDER BY assistant_daily.day ASC
709
- `);
710
- const scenarioMatrix = this.uiDb.all<{
711
- model_id: string;
712
- scenario: string;
713
- hits: number;
714
- }>('SELECT model_id, scenario, hits FROM v_thinking_model_scenarios ORDER BY hits DESC, model_id ASC');
715
-
716
- return {
717
- summary: {
718
- totalModels: knownModels.length,
719
- activeModels: activeIds.size,
720
- dormantModels: dormantModels.length,
721
- effectiveModels: topModels.filter((model) => model.recommendation === 'reinforce').length,
722
- coverageRate: roundRate(coverageRow.thinking_turns, coverageRow.assistant_turns),
723
- },
724
- topModels,
725
- dormantModels,
726
- effectiveModels: topModels.filter((model) => model.recommendation === 'reinforce'),
727
- scenarioMatrix: scenarioMatrix.map((row) => ({
728
- modelId: row.model_id,
729
- modelName: getThinkingModel(row.model_id)?.name ?? row.model_id,
730
- scenario: row.scenario,
731
- hits: Number(row.hits),
732
- })),
733
- coverageTrend: coverageTrend.map((row) => ({
734
- day: row.day,
735
- assistantTurns: Number(row.assistant_turns),
736
- thinkingTurns: Number(row.thinking_turns),
737
- coverageRate: roundRate(Number(row.thinking_turns), Number(row.assistant_turns)),
738
- })),
739
- };
740
- }
741
-
742
- getThinkingModelDetail(modelId: string): ThinkingModelDetailResponse | null {
743
- if (!getThinkingModel(modelId)) {
744
- return null;
745
- }
746
-
747
- const summary = this.loadThinkingModelSummaries().find((item) => item.modelId === modelId) ?? {
748
- modelId,
749
- name: getThinkingModel(modelId)?.name ?? modelId,
750
- description: getThinkingModel(modelId)?.description ?? 'Unknown thinking model.',
751
- hits: 0,
752
- coverageRate: 0,
753
- successRate: 0,
754
- failureRate: 0,
755
- painRate: 0,
756
- correctionRate: 0,
757
- correctionSampleRate: 0,
758
- commonScenarios: [],
759
- recommendation: 'archive' as const,
760
- };
761
- const usageTrend = this.uiDb.all<{ day: string; hits: number }>(`
762
- SELECT day, hits
763
- FROM v_thinking_model_daily_trend
764
- WHERE model_id = ?
765
- ORDER BY day ASC
766
- `, modelId);
767
- const scenarioDistribution = this.uiDb.all<{ scenario: string; hits: number }>(`
768
- SELECT scenario, hits
769
- FROM v_thinking_model_scenarios
770
- WHERE model_id = ?
771
- ORDER BY hits DESC, scenario ASC
772
- `, modelId);
773
- const effect = this.uiDb.get<{
774
- events: number;
775
- success_windows: number;
776
- failure_windows: number;
777
- pain_windows: number;
778
- correction_windows: number;
779
- correction_sample_windows: number;
780
- }>('SELECT * FROM v_thinking_model_effectiveness WHERE model_id = ?', modelId) ?? {
781
- events: 0,
782
- success_windows: 0,
783
- failure_windows: 0,
784
- pain_windows: 0,
785
- correction_windows: 0,
786
- correction_sample_windows: 0,
787
- };
788
- const recentEvents = this.uiDb.all<{
789
- id: number;
790
- created_at: string;
791
- matched_pattern: string;
792
- scenario_json: string;
793
- trigger_excerpt: string;
794
- tool_context_json: string;
795
- pain_context_json: string;
796
- principle_context_json: string;
797
- }>(`
798
- SELECT id, created_at, matched_pattern, scenario_json, trigger_excerpt,
799
- tool_context_json, pain_context_json, principle_context_json
800
- FROM thinking_model_events
801
- WHERE model_id = ?
802
- ORDER BY created_at DESC
803
- LIMIT 20
804
- `, modelId);
805
-
806
- return {
807
- modelMeta: {
808
- modelId: summary.modelId,
809
- name: summary.name,
810
- description: summary.description,
811
- hits: summary.hits,
812
- coverageRate: summary.coverageRate,
813
- recommendation: summary.recommendation,
814
- },
815
- usageTrend: usageTrend.map((row) => ({
816
- day: row.day,
817
- hits: Number(row.hits),
818
- })),
819
- scenarioDistribution: scenarioDistribution.map((row) => ({
820
- scenario: row.scenario,
821
- hits: Number(row.hits),
822
- })),
823
- outcomeStats: {
824
- events: Number(effect.events),
825
- successRate: roundRate(Number(effect.success_windows), Number(effect.events)),
826
- failureRate: roundRate(Number(effect.failure_windows), Number(effect.events)),
827
- painRate: roundRate(Number(effect.pain_windows), Number(effect.events)),
828
- correctionRate: roundRate(Number(effect.correction_windows), Number(effect.events)),
829
- correctionSampleRate: roundRate(Number(effect.correction_sample_windows), Number(effect.events)),
830
- },
831
- recentEvents: recentEvents.map((row) => ({
832
- id: Number(row.id),
833
- createdAt: row.created_at,
834
- matchedPattern: row.matched_pattern,
835
- scenarios: parseJson<string[]>(row.scenario_json, []),
836
- triggerExcerpt: row.trigger_excerpt,
837
- toolContext: parseJson<{ toolName: string; outcome: string; errorType?: string | null }[]>(row.tool_context_json, []),
838
- painContext: parseJson<{ source: string; score: number }[]>(row.pain_context_json, []),
839
- principleContext: parseJson<{ principleId: string | null; eventType: string }[]>(row.principle_context_json, []),
840
- })),
841
- };
842
- }
843
-
844
- private loadThinkingModelSummaries(): ThinkingModelSummary[] {
845
- const knownModels = listThinkingModels();
846
- const usageRows = new Map(this.uiDb.all<{
847
- model_id: string;
848
- hits: number;
849
- coverage_rate: number;
850
- }>('SELECT model_id, hits, coverage_rate FROM v_thinking_model_usage').map((row) => [row.model_id, row]));
851
- const effectRows = new Map(this.uiDb.all<{
852
- model_id: string;
853
- events: number;
854
- success_windows: number;
855
- failure_windows: number;
856
- pain_windows: number;
857
- correction_windows: number;
858
- correction_sample_windows: number;
859
- }>('SELECT * FROM v_thinking_model_effectiveness').map((row) => [row.model_id, row]));
860
- const scenarioRows = this.uiDb.all<{
861
- model_id: string;
862
- scenario: string;
863
- hits: number;
864
- }>('SELECT model_id, scenario, hits FROM v_thinking_model_scenarios ORDER BY hits DESC');
865
-
866
- return knownModels.map((model) => {
867
- const usage = usageRows.get(model.id);
868
- const effect = effectRows.get(model.id);
869
- const events = Number(effect?.events ?? usage?.hits ?? 0);
870
- const successRate = roundRate(Number(effect?.success_windows ?? 0), events);
871
- const failureRate = roundRate(Number(effect?.failure_windows ?? 0), events);
872
- const painRate = roundRate(Number(effect?.pain_windows ?? 0), events);
873
- const correctionRate = roundRate(Number(effect?.correction_windows ?? 0), events);
874
- const correctionSampleRate = roundRate(Number(effect?.correction_sample_windows ?? 0), events);
875
- return {
876
- modelId: model.id,
877
- name: model.name,
878
- description: model.description,
879
- hits: Number(usage?.hits ?? 0),
880
- coverageRate: Number(usage?.coverage_rate ?? 0),
881
- successRate,
882
- failureRate,
883
- painRate,
884
- correctionRate,
885
- correctionSampleRate,
886
- commonScenarios: scenarioRows
887
- .filter((row) => row.model_id === model.id)
888
- .slice(0, 3)
889
- .map((row) => row.scenario),
890
- recommendation: summarizeRecommendation({
891
- hits: Number(usage?.hits ?? 0),
892
- successRate,
893
- failureRate,
894
- painRate,
895
- correctionRate,
896
- }),
897
- };
898
- }).sort((left, right) => right.hits - left.hits || left.modelId.localeCompare(right.modelId));
899
- }
900
- }