dsh-data-domain-knowledge 0.1.0-alpha.9 → 0.1.1-alpha.2

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 (438) hide show
  1. package/README.md +118 -567
  2. package/cordis.patch.yml +5 -418
  3. package/eval/README.md +19 -8
  4. package/eval/benchmark-extraction-format.mjs +20 -0
  5. package/eval/evaluate-retrieval.mjs +17 -8
  6. package/eval/queries.example.jsonl +1 -0
  7. package/lib/client.js +4181 -3239
  8. package/lib/contract-envelope.d.ts +91 -0
  9. package/lib/contract-envelope.js +106 -0
  10. package/lib/contract-layout.d.ts +130 -0
  11. package/lib/contract-layout.js +138 -0
  12. package/lib/contract-refs.d.ts +39 -0
  13. package/lib/contract-refs.js +9 -0
  14. package/lib/contract-version.d.ts +311 -0
  15. package/lib/contract-version.js +270 -0
  16. package/lib/contract-wire.d.ts +147 -0
  17. package/lib/contract-wire.js +99 -0
  18. package/lib/contracts.d.ts +12 -0
  19. package/lib/contracts.js +12 -0
  20. package/lib/doc-page.js +2 -2
  21. package/lib/pages.js +3329 -1296
  22. package/lib/types/agent-behavior-rules.d.ts +10 -0
  23. package/lib/types/agent-behavior-rules.d.ts.map +1 -0
  24. package/lib/types/agent-behavior-rules.js +28 -0
  25. package/lib/types/agent-behavior-rules.js.map +1 -0
  26. package/lib/types/axis-registry.d.ts +37 -5
  27. package/lib/types/axis-registry.d.ts.map +1 -1
  28. package/lib/types/axis-registry.js +234 -26
  29. package/lib/types/axis-registry.js.map +1 -1
  30. package/lib/types/card-organize.d.ts +27 -12
  31. package/lib/types/card-organize.d.ts.map +1 -1
  32. package/lib/types/card-organize.js +58 -73
  33. package/lib/types/card-organize.js.map +1 -1
  34. package/lib/types/compiler/embedding-identity.d.ts +3 -0
  35. package/lib/types/compiler/embedding-identity.d.ts.map +1 -0
  36. package/lib/types/compiler/embedding-identity.js +24 -0
  37. package/lib/types/compiler/embedding-identity.js.map +1 -0
  38. package/lib/types/compiler/snapshot.d.ts +16 -0
  39. package/lib/types/compiler/snapshot.d.ts.map +1 -0
  40. package/lib/types/compiler/snapshot.js +2 -0
  41. package/lib/types/compiler/snapshot.js.map +1 -0
  42. package/lib/types/config-schema.d.ts +6 -3
  43. package/lib/types/config-schema.d.ts.map +1 -1
  44. package/lib/types/config-schema.js +6 -2
  45. package/lib/types/config-schema.js.map +1 -1
  46. package/lib/types/convert/host.d.ts +6 -5
  47. package/lib/types/convert/host.d.ts.map +1 -1
  48. package/lib/types/convert/host.js +58 -18
  49. package/lib/types/convert/host.js.map +1 -1
  50. package/lib/types/convert/ingest.d.ts +10 -1
  51. package/lib/types/convert/ingest.d.ts.map +1 -1
  52. package/lib/types/convert/ingest.js +68 -9
  53. package/lib/types/convert/ingest.js.map +1 -1
  54. package/lib/types/derive-contract.d.ts +3 -0
  55. package/lib/types/derive-contract.d.ts.map +1 -0
  56. package/lib/types/derive-contract.js +15 -0
  57. package/lib/types/derive-contract.js.map +1 -0
  58. package/lib/types/diagnosis/cards.d.ts +7 -3
  59. package/lib/types/diagnosis/cards.d.ts.map +1 -1
  60. package/lib/types/diagnosis/cards.js +13 -8
  61. package/lib/types/diagnosis/cards.js.map +1 -1
  62. package/lib/types/diagnosis/run.d.ts +4 -13
  63. package/lib/types/diagnosis/run.d.ts.map +1 -1
  64. package/lib/types/diagnosis/run.js +26 -16
  65. package/lib/types/diagnosis/run.js.map +1 -1
  66. package/lib/types/diagnosis/schema.js +2 -2
  67. package/lib/types/diagnosis/schema.js.map +1 -1
  68. package/lib/types/diagnosis/seed-source.d.ts +1 -1
  69. package/lib/types/diagnosis/seed-source.d.ts.map +1 -1
  70. package/lib/types/diagnosis/seed-source.js +5 -4
  71. package/lib/types/diagnosis/seed-source.js.map +1 -1
  72. package/lib/types/diagnosis/seed.d.ts +4 -4
  73. package/lib/types/diagnosis/seed.d.ts.map +1 -1
  74. package/lib/types/diagnosis/seed.js +6 -8
  75. package/lib/types/diagnosis/seed.js.map +1 -1
  76. package/lib/types/diagnosis/store.d.ts +24 -18
  77. package/lib/types/diagnosis/store.d.ts.map +1 -1
  78. package/lib/types/diagnosis/store.js +130 -65
  79. package/lib/types/diagnosis/store.js.map +1 -1
  80. package/lib/types/diagnosis/types.d.ts +47 -15
  81. package/lib/types/diagnosis/types.d.ts.map +1 -1
  82. package/lib/types/diagnosis/types.js.map +1 -1
  83. package/lib/types/environment/dsh-python.d.ts +77 -0
  84. package/lib/types/environment/dsh-python.d.ts.map +1 -0
  85. package/lib/types/environment/dsh-python.js +139 -0
  86. package/lib/types/environment/dsh-python.js.map +1 -0
  87. package/lib/types/environment/install.d.ts +15 -0
  88. package/lib/types/environment/install.d.ts.map +1 -0
  89. package/lib/types/environment/install.js +297 -0
  90. package/lib/types/environment/install.js.map +1 -0
  91. package/lib/types/environment/manifest.d.ts +208 -0
  92. package/lib/types/environment/manifest.d.ts.map +1 -0
  93. package/lib/types/environment/manifest.js +26 -0
  94. package/lib/types/environment/manifest.js.map +1 -0
  95. package/lib/types/environment/model-catalog.d.ts +223 -0
  96. package/lib/types/environment/model-catalog.d.ts.map +1 -0
  97. package/lib/types/environment/model-catalog.js +129 -0
  98. package/lib/types/environment/model-catalog.js.map +1 -0
  99. package/lib/types/environment/process.d.ts +10 -0
  100. package/lib/types/environment/process.d.ts.map +1 -0
  101. package/lib/types/environment/process.js +54 -0
  102. package/lib/types/environment/process.js.map +1 -0
  103. package/lib/types/environment/selection.d.ts +9 -0
  104. package/lib/types/environment/selection.d.ts.map +1 -0
  105. package/lib/types/environment/selection.js +29 -0
  106. package/lib/types/environment/selection.js.map +1 -0
  107. package/lib/types/environment/service.d.ts +64 -0
  108. package/lib/types/environment/service.d.ts.map +1 -0
  109. package/lib/types/environment/service.js +424 -0
  110. package/lib/types/environment/service.js.map +1 -0
  111. package/lib/types/environment/types.d.ts +56 -0
  112. package/lib/types/environment/types.d.ts.map +1 -0
  113. package/lib/types/environment/types.js +2 -0
  114. package/lib/types/environment/types.js.map +1 -0
  115. package/lib/types/events.d.ts +76 -0
  116. package/lib/types/events.d.ts.map +1 -0
  117. package/lib/types/events.js +52 -0
  118. package/lib/types/events.js.map +1 -0
  119. package/lib/types/extract-contract.d.ts +3 -0
  120. package/lib/types/extract-contract.d.ts.map +1 -0
  121. package/lib/types/extract-contract.js +41 -0
  122. package/lib/types/extract-contract.js.map +1 -0
  123. package/lib/types/extract-model.d.ts +5 -0
  124. package/lib/types/extract-model.d.ts.map +1 -1
  125. package/lib/types/extract-model.js.map +1 -1
  126. package/lib/types/extract-table-contract.d.ts +3 -0
  127. package/lib/types/extract-table-contract.d.ts.map +1 -0
  128. package/lib/types/extract-table-contract.js +27 -0
  129. package/lib/types/extract-table-contract.js.map +1 -0
  130. package/lib/types/extract-table.d.ts +8 -0
  131. package/lib/types/extract-table.d.ts.map +1 -0
  132. package/lib/types/extract-table.js +158 -0
  133. package/lib/types/extract-table.js.map +1 -0
  134. package/lib/types/extraction-runs.d.ts +30 -6
  135. package/lib/types/extraction-runs.d.ts.map +1 -1
  136. package/lib/types/extraction-runs.js +69 -8
  137. package/lib/types/extraction-runs.js.map +1 -1
  138. package/lib/types/fs-atomic.d.ts +0 -7
  139. package/lib/types/fs-atomic.d.ts.map +1 -1
  140. package/lib/types/fs-atomic.js +17 -2
  141. package/lib/types/fs-atomic.js.map +1 -1
  142. package/lib/types/images.d.ts +26 -0
  143. package/lib/types/images.d.ts.map +1 -0
  144. package/lib/types/images.js +196 -0
  145. package/lib/types/images.js.map +1 -0
  146. package/lib/types/index.d.ts +2 -2
  147. package/lib/types/index.d.ts.map +1 -1
  148. package/lib/types/index.js +598 -209
  149. package/lib/types/index.js.map +1 -1
  150. package/lib/types/intent/engine.d.ts +12 -4
  151. package/lib/types/intent/engine.d.ts.map +1 -1
  152. package/lib/types/intent/engine.js +43 -5
  153. package/lib/types/intent/engine.js.map +1 -1
  154. package/lib/types/intent/host.d.ts +5 -8
  155. package/lib/types/intent/host.d.ts.map +1 -1
  156. package/lib/types/intent/host.js +56 -11
  157. package/lib/types/intent/host.js.map +1 -1
  158. package/lib/types/intent/scope.d.ts +25 -0
  159. package/lib/types/intent/scope.d.ts.map +1 -0
  160. package/lib/types/intent/scope.js +116 -0
  161. package/lib/types/intent/scope.js.map +1 -0
  162. package/lib/types/intent/tools.d.ts +24 -20
  163. package/lib/types/intent/tools.d.ts.map +1 -1
  164. package/lib/types/intent/tools.js +65 -23
  165. package/lib/types/intent/tools.js.map +1 -1
  166. package/lib/types/intent/types.d.ts +11 -4
  167. package/lib/types/intent/types.d.ts.map +1 -1
  168. package/lib/types/knowledge-bases.d.ts +11 -5
  169. package/lib/types/knowledge-bases.d.ts.map +1 -1
  170. package/lib/types/knowledge-bases.js +52 -20
  171. package/lib/types/knowledge-bases.js.map +1 -1
  172. package/lib/types/knowledge-contract.d.ts +32 -0
  173. package/lib/types/knowledge-contract.d.ts.map +1 -0
  174. package/lib/types/knowledge-contract.js +116 -0
  175. package/lib/types/knowledge-contract.js.map +1 -0
  176. package/lib/types/knowledge.d.ts +31 -9
  177. package/lib/types/knowledge.d.ts.map +1 -1
  178. package/lib/types/knowledge.js +137 -60
  179. package/lib/types/knowledge.js.map +1 -1
  180. package/lib/types/layout.d.ts +10 -29
  181. package/lib/types/layout.d.ts.map +1 -1
  182. package/lib/types/layout.js +17 -36
  183. package/lib/types/layout.js.map +1 -1
  184. package/lib/types/materialize-snapshot.d.ts +49 -0
  185. package/lib/types/materialize-snapshot.d.ts.map +1 -0
  186. package/lib/types/materialize-snapshot.js +2 -0
  187. package/lib/types/materialize-snapshot.js.map +1 -0
  188. package/lib/types/migrate.d.ts +11 -0
  189. package/lib/types/migrate.d.ts.map +1 -1
  190. package/lib/types/migrate.js +83 -2
  191. package/lib/types/migrate.js.map +1 -1
  192. package/lib/types/model-text.d.ts +58 -1
  193. package/lib/types/model-text.d.ts.map +1 -1
  194. package/lib/types/model-text.js +85 -30
  195. package/lib/types/model-text.js.map +1 -1
  196. package/lib/types/oplog.d.ts.map +1 -1
  197. package/lib/types/oplog.js +7 -0
  198. package/lib/types/oplog.js.map +1 -1
  199. package/lib/types/organize-contract.d.ts +18 -0
  200. package/lib/types/organize-contract.d.ts.map +1 -0
  201. package/lib/types/organize-contract.js +82 -0
  202. package/lib/types/organize-contract.js.map +1 -0
  203. package/lib/types/pipeline/engine.d.ts +66 -0
  204. package/lib/types/pipeline/engine.d.ts.map +1 -0
  205. package/lib/types/pipeline/engine.js +352 -0
  206. package/lib/types/pipeline/engine.js.map +1 -0
  207. package/lib/types/pipeline/store.d.ts +73 -0
  208. package/lib/types/pipeline/store.d.ts.map +1 -0
  209. package/lib/types/pipeline/store.js +143 -0
  210. package/lib/types/pipeline/store.js.map +1 -0
  211. package/lib/types/pipeline/types.d.ts +102 -0
  212. package/lib/types/pipeline/types.d.ts.map +1 -0
  213. package/lib/types/pipeline/types.js +5 -0
  214. package/lib/types/pipeline/types.js.map +1 -0
  215. package/lib/types/present.d.ts +2 -0
  216. package/lib/types/present.d.ts.map +1 -1
  217. package/lib/types/present.js +9 -4
  218. package/lib/types/present.js.map +1 -1
  219. package/lib/types/preset-ids.d.ts +4 -0
  220. package/lib/types/preset-ids.d.ts.map +1 -0
  221. package/lib/types/preset-ids.js +6 -0
  222. package/lib/types/preset-ids.js.map +1 -0
  223. package/lib/types/query-analysis.d.ts +13 -1
  224. package/lib/types/query-analysis.d.ts.map +1 -1
  225. package/lib/types/query-analysis.js +62 -6
  226. package/lib/types/query-analysis.js.map +1 -1
  227. package/lib/types/recall-rank.d.ts +3 -3
  228. package/lib/types/recall-rank.d.ts.map +1 -1
  229. package/lib/types/recall-rank.js +4 -4
  230. package/lib/types/recall-rank.js.map +1 -1
  231. package/lib/types/retention.d.ts +39 -0
  232. package/lib/types/retention.d.ts.map +1 -0
  233. package/lib/types/retention.js +42 -0
  234. package/lib/types/retention.js.map +1 -0
  235. package/lib/types/retrieval/vector-index.d.ts +32 -0
  236. package/lib/types/retrieval/vector-index.d.ts.map +1 -0
  237. package/lib/types/retrieval/vector-index.js +15 -0
  238. package/lib/types/retrieval/vector-index.js.map +1 -0
  239. package/lib/types/retrieval/visibility.d.ts +6 -0
  240. package/lib/types/retrieval/visibility.d.ts.map +1 -0
  241. package/lib/types/retrieval/visibility.js +11 -0
  242. package/lib/types/retrieval/visibility.js.map +1 -0
  243. package/lib/types/runtime.d.ts +272 -27
  244. package/lib/types/runtime.d.ts.map +1 -1
  245. package/lib/types/runtime.js +2751 -537
  246. package/lib/types/runtime.js.map +1 -1
  247. package/lib/types/settings-schema.d.ts +17 -15
  248. package/lib/types/settings-schema.d.ts.map +1 -1
  249. package/lib/types/settings-schema.js +50 -47
  250. package/lib/types/settings-schema.js.map +1 -1
  251. package/lib/types/settings-volatile.d.ts +4 -4
  252. package/lib/types/settings-volatile.js +4 -4
  253. package/lib/types/source-evidence.d.ts +14 -0
  254. package/lib/types/source-evidence.d.ts.map +1 -0
  255. package/lib/types/source-evidence.js +36 -0
  256. package/lib/types/source-evidence.js.map +1 -0
  257. package/lib/types/store/axis-references.d.ts +5 -0
  258. package/lib/types/store/axis-references.d.ts.map +1 -0
  259. package/lib/types/store/axis-references.js +106 -0
  260. package/lib/types/store/axis-references.js.map +1 -0
  261. package/lib/types/store/derived.d.ts +12 -1
  262. package/lib/types/store/derived.d.ts.map +1 -1
  263. package/lib/types/store/derived.js +71 -12
  264. package/lib/types/store/derived.js.map +1 -1
  265. package/lib/types/store/knowledge-db.d.ts +31 -1
  266. package/lib/types/store/knowledge-db.d.ts.map +1 -1
  267. package/lib/types/store/knowledge-db.js +252 -18
  268. package/lib/types/store/knowledge-db.js.map +1 -1
  269. package/lib/types/store/migrate.d.ts.map +1 -1
  270. package/lib/types/store/migrate.js +17 -6
  271. package/lib/types/store/migrate.js.map +1 -1
  272. package/lib/types/trajectory-types.d.ts +172 -0
  273. package/lib/types/trajectory-types.d.ts.map +1 -0
  274. package/lib/types/trajectory-types.js +36 -0
  275. package/lib/types/trajectory-types.js.map +1 -0
  276. package/lib/types/types.d.ts +59 -27
  277. package/lib/types/types.d.ts.map +1 -1
  278. package/lib/types/types.js +6 -15
  279. package/lib/types/types.js.map +1 -1
  280. package/lib/types/wiki-finalize.d.ts +16 -0
  281. package/lib/types/wiki-finalize.d.ts.map +1 -1
  282. package/lib/types/wiki-finalize.js +26 -0
  283. package/lib/types/wiki-finalize.js.map +1 -1
  284. package/lib/types/wiki-materialize.d.ts +4 -0
  285. package/lib/types/wiki-materialize.d.ts.map +1 -1
  286. package/lib/types/wiki-materialize.js +21 -7
  287. package/lib/types/wiki-materialize.js.map +1 -1
  288. package/lib/types/wiki-trial-types.d.ts +87 -0
  289. package/lib/types/wiki-trial-types.d.ts.map +1 -1
  290. package/lib/types/wiki-trial-types.js +0 -16
  291. package/lib/types/wiki-trial-types.js.map +1 -1
  292. package/lib/types/wiki-trial.d.ts +40 -16
  293. package/lib/types/wiki-trial.d.ts.map +1 -1
  294. package/lib/types/wiki-trial.js +337 -224
  295. package/lib/types/wiki-trial.js.map +1 -1
  296. package/package.json +29 -20
  297. package/python/prepare-models.py +19 -0
  298. package/python/requirements.txt +8 -6
  299. package/scripts/doctor.mjs +13 -19
  300. package/scripts/environment.mjs +29 -0
  301. package/scripts/setup-embedding.sh +15 -5
  302. package/src/agent-behavior-rules.ts +37 -0
  303. package/src/axis-registry.ts +234 -27
  304. package/src/card-organize.ts +69 -75
  305. package/src/client/AgentBehaviorRulesCard.tsx +65 -0
  306. package/src/client/AttributionEventGuide.tsx +41 -39
  307. package/src/client/AxisRegistrySection.tsx +204 -164
  308. package/src/client/CompileDialogs.tsx +44 -29
  309. package/src/client/DeleteDocumentDialog.tsx +36 -5
  310. package/src/client/DirectoryPicker.tsx +0 -10
  311. package/src/client/EnvironmentSetup.tsx +243 -0
  312. package/src/client/ExpansionGraph.tsx +13 -7
  313. package/src/client/ExtractionTasksPage.tsx +578 -0
  314. package/src/client/GuideArchitectureCanvas.tsx +470 -0
  315. package/src/client/ImportFilesDialog.tsx +2 -13
  316. package/src/client/IntentLogic.tsx +2 -2
  317. package/src/client/IntentTab.tsx +118 -47
  318. package/src/client/KnowledgeBaseTab.tsx +277 -197
  319. package/src/client/KnowledgeLayerSection.tsx +24 -6
  320. package/src/client/KnowledgePanel.tsx +58 -93
  321. package/src/client/KnowledgeSettingsDrawer.tsx +90 -0
  322. package/src/client/ListPager.tsx +15 -5
  323. package/src/client/MaterializeTrajectoryView.tsx +124 -0
  324. package/src/client/NodeSettings.tsx +210 -89
  325. package/src/client/NormalizeTrajectoryView.tsx +136 -0
  326. package/src/client/PipelineNotice.tsx +26 -0
  327. package/src/client/PreviewSections.tsx +118 -51
  328. package/src/client/RecallPanel.tsx +89 -85
  329. package/src/client/TabGuide.tsx +159 -184
  330. package/src/client/TrialReportView.tsx +391 -214
  331. package/src/client/TypeDefinitionDrawer.tsx +150 -23
  332. package/src/client/WikiCardPreview.tsx +62 -16
  333. package/src/client/WikiFlowPanel.tsx +4 -4
  334. package/src/client/arch/NodeLogicPanel.tsx +3 -4
  335. package/src/client/arch/model.ts +6 -9
  336. package/src/client/architecture.tsx +23 -33
  337. package/src/client/attribution/AttributionGraph.tsx +10 -6
  338. package/src/client/attribution/AttributionTab.tsx +136 -84
  339. package/src/client/attribution/CaseView.tsx +3 -1
  340. package/src/client/attribution/EventView.tsx +108 -0
  341. package/src/client/attribution/RunView.tsx +2 -2
  342. package/src/client/attribution/StageChrome.tsx +34 -3
  343. package/src/client/attribution/ViewSwitch.tsx +20 -5
  344. package/src/client/attribution/graph-options.ts +47 -39
  345. package/src/client/attribution/model.ts +17 -10
  346. package/src/client/config-scope.ts +3 -3
  347. package/src/client/graph/palette.ts +165 -0
  348. package/src/client/index.ts +49 -42
  349. package/src/client/pages.css +459 -135
  350. package/src/client/pages.tsx +37 -9
  351. package/src/client/problem-domains.ts +1 -1
  352. package/src/client/session-remote.ts +9 -0
  353. package/src/client/styles.css +205 -62
  354. package/src/client/wiki-trial.ts +44 -3
  355. package/src/compiler/embedding-identity.ts +21 -0
  356. package/src/compiler/snapshot.ts +17 -0
  357. package/src/config-schema.ts +8 -3
  358. package/src/convert/host.ts +56 -21
  359. package/src/convert/ingest.ts +74 -10
  360. package/src/derive-contract.ts +14 -0
  361. package/src/diagnosis/cards.ts +13 -8
  362. package/src/diagnosis/run.ts +27 -17
  363. package/src/diagnosis/schema.ts +2 -2
  364. package/src/diagnosis/seed-source.ts +5 -4
  365. package/src/diagnosis/seed.ts +6 -8
  366. package/src/diagnosis/store.ts +138 -69
  367. package/src/diagnosis/types.ts +34 -15
  368. package/src/environment/dsh-python.ts +156 -0
  369. package/src/environment/install.ts +244 -0
  370. package/src/environment/manifest.ts +28 -0
  371. package/src/environment/model-catalog.ts +147 -0
  372. package/src/environment/process.ts +54 -0
  373. package/src/environment/selection.ts +29 -0
  374. package/src/environment/service.ts +348 -0
  375. package/src/environment/types.ts +45 -0
  376. package/src/events.ts +108 -0
  377. package/src/extract-contract.ts +42 -0
  378. package/src/extract-model.ts +10 -1
  379. package/src/extract-table-contract.ts +26 -0
  380. package/src/extract-table.ts +132 -0
  381. package/src/extraction-runs.ts +70 -11
  382. package/src/fs-atomic.ts +19 -2
  383. package/src/images.ts +203 -0
  384. package/src/index.ts +553 -205
  385. package/src/intent/README.md +8 -6
  386. package/src/intent/engine.ts +44 -6
  387. package/src/intent/host.ts +59 -18
  388. package/src/intent/scope.ts +125 -0
  389. package/src/intent/tools.ts +70 -28
  390. package/src/intent/types.ts +11 -4
  391. package/src/knowledge-bases.ts +56 -20
  392. package/src/knowledge-contract.ts +114 -0
  393. package/src/knowledge.ts +138 -69
  394. package/src/layout.ts +17 -37
  395. package/src/materialize-snapshot.ts +46 -0
  396. package/src/migrate.ts +75 -2
  397. package/src/model-text.ts +109 -4
  398. package/src/oplog.ts +7 -0
  399. package/src/organize-contract.ts +83 -0
  400. package/src/pipeline/engine.ts +323 -0
  401. package/src/pipeline/store.ts +147 -0
  402. package/src/pipeline/types.ts +93 -0
  403. package/src/present.ts +10 -4
  404. package/src/preset-ids.ts +6 -0
  405. package/src/python/embedding_worker.py +66 -2
  406. package/src/query-analysis.ts +68 -8
  407. package/src/recall-rank.ts +5 -5
  408. package/src/retention.ts +76 -0
  409. package/src/retrieval/vector-index.ts +45 -0
  410. package/src/retrieval/visibility.ts +14 -0
  411. package/src/runtime.ts +2708 -567
  412. package/src/settings-schema.ts +11 -8
  413. package/src/settings-volatile.ts +4 -4
  414. package/src/source-evidence.ts +37 -0
  415. package/src/store/axis-references.ts +96 -0
  416. package/src/store/derived.ts +70 -12
  417. package/src/store/knowledge-db.ts +248 -17
  418. package/src/store/migrate.ts +16 -6
  419. package/src/trajectory-types.ts +142 -0
  420. package/src/types.ts +61 -35
  421. package/src/wiki-finalize.ts +28 -0
  422. package/src/wiki-materialize.ts +25 -6
  423. package/src/wiki-trial-types.ts +83 -1
  424. package/src/wiki-trial.ts +357 -185
  425. package/lib/types/intent/preset-tools.d.ts +0 -37
  426. package/lib/types/intent/preset-tools.d.ts.map +0 -1
  427. package/lib/types/intent/preset-tools.js +0 -45
  428. package/lib/types/intent/preset-tools.js.map +0 -1
  429. package/preset/tita-data-agent/agent.cordis.yml +0 -394
  430. package/preset/tita-data-agent/preset.yml +0 -3
  431. package/scripts/install-agent-preset.mjs +0 -92
  432. package/scripts/sync-agent-preset.mjs +0 -188
  433. package/src/client/AgentPresetCard.tsx +0 -247
  434. package/src/client/agent-preset.ts +0 -121
  435. package/src/client/convert/ConvertPanel.tsx +0 -583
  436. package/src/client/convert/styles.css +0 -138
  437. package/src/client/convert/styles.ts +0 -49
  438. package/src/intent/preset-tools.ts +0 -48
@@ -1,53 +1,6 @@
1
- /**
2
- * Wiki 抽取试跑(0063):**调一次模型**按新方案判一遍,不落盘。
3
- *
4
- * ## 五层
5
- *
6
- * ```
7
- * Document ──▶ Knowledge ──▶ Canonical Knowledge ──▶ Wiki Card ──▶ 索引
8
- * ```
9
- *
10
- * - **Knowledge** 是知识:一条可独立检索、验证或执行的最小知识单元。
11
- * **只有 `text` 是内容**;`object` / `action` / `scene` / `sources` 都是索引与出处。
12
- * 把索引当知识,是这套模型最常见的误解。
13
- * - **Coordinate** 是 `(object, action, scene)` 这个位置。它是**复合键,不是实体** ——
14
- * 所以没有 Coordinate 表,也没有"坐标实体"这一层。一条 Knowledge 只有一个坐标,
15
- * 那是它的「家」。别的卡可以引用它,那是卡的事,不是坐标的事。
16
- * - **Wiki Card** 是交付视图:一个坐标 + 至少一条 Knowledge 就物化成一张。
17
- * 标题是**坐标的自然语言投影**,由系统推导 —— 坐标是判重键,模型不参与命名。
18
- * - **索引**有三个:轴 / Knowledge / Wiki Card。前两个装内容,第三个装任务。
19
- *
20
- * ## 四个阶段,七个动作
21
- *
22
- * | 阶段 | 动作 |
23
- * |---|---|
24
- * | ① Extract | 1 Semantic Extraction |
25
- * | ② Resolve | 2 Entity Resolution · 3 Knowledge Resolution · 4 Coordinate Assignment |
26
- * | ③ Materialize | 5 Card Materialization · 6 Card Organization |
27
- * | ④ Index | 7 Build Index |
28
- *
29
- * 顺序里有一条硬规矩:**先把"知识是什么"搞清楚,再决定"这些知识怎么组织成 Wiki Card"。**
30
- * Wiki Card 是组织结果,不是知识合并结果。
31
- *
32
- * ## 只调一次
33
- *
34
- * 七步是给人 review 的,不是给模型分的工。一次调用输入全文,输出一个 JSON:
35
- * `subject` / `knowledge` / `objects` / `actions` / `scenes` / `dropped`。
36
- * 分块只在文档塞不进上下文时才做。
37
- *
38
- * ## 对象 × 动作矩阵
39
- *
40
- * 矩阵**不让模型再填一遍**。它是 Knowledge 坐标的二维排布,本地算出来的:行是对象,列是动作,
41
- * 多一行「无对象」收只有动作的知识,多一列「无动作」收只有对象的知识。
42
- *
43
- * **坐标是三维的,矩阵是它的二维投影。** 场景落在格子**内部**,不进坐标轴 ——
44
- * 一格里有几个场景,就有几张卡。
45
- *
46
- * ## 只读
47
- *
48
- * 它不写 SourceRaw、不建卡、不进索引。给一段正文,返回四个阶段的判定结果与矩阵。
49
- */
50
- import { AXIS_CONTRACT_LINES } from './axis-contract.js';
1
+ import { normalizeKnowledgeExtraction } from './knowledge-contract.js';
2
+ import { buildTrialSystem } from './extract-contract.js';
3
+ import { decodeExtractionTable } from './extract-table.js';
51
4
  /**
52
5
  * 抽取契约(0063 §5.6)。**这是契约,不是要抄进代码的字符串。**
53
6
  *
@@ -58,101 +11,8 @@ import { AXIS_CONTRACT_LINES } from './axis-contract.js';
58
11
  * 2. 三个分量**可以全空** —— §九 明写"允许 Knowledge 没有领域坐标"。
59
12
  * 文档 §5.6 里"每条至少挂一个 object 或一个 action"与它冲突。
60
13
  */
61
- /**
62
- * 把骨架允许的小节拼成提示词里那一条。
63
- *
64
- * §5.3.2 说「`section` 的合法取值来自类型定义」—— 那就应当**下发**给它,帮助模型
65
- * 使用一致的小节名。不下发的话,那句「合法取值来自类型定义」只是一句写在文档里的愿望。
66
- */
67
- function sectionRule(sections) {
68
- const legal = (sections ?? []).map(section => section.trim()).filter(Boolean);
69
- if (legal.length === 0) {
70
- return ['- section 是这条知识在卡片里的位置。拿不准就填「字段」。'];
71
- }
72
- return [
73
- `- section 只能填这几个之一:${legal.join(' / ')},或者「字段」。`,
74
- '- 拿不准就填「字段」。**不要自创小节名** —— 卡片是按骨架校验的,编出来的名字对不上。',
75
- ];
76
- }
77
- /**
78
- * 抽取契约的 system 段。**骨架的小节随知识库变化,所以它是拼出来的,不是常量。**
79
- *
80
- * 编译链路用 `buildTrialSystem(profileSections)`;试跑面板用默认实例(不下发小节清单),
81
- * 因为那一层没有「本库骨架」这个概念。
82
- */
83
- export function buildTrialSystem(sections) {
84
- return trialSystemBody(sectionRule(sections));
85
- }
86
- const trialSystemBody = (positionRule) => [
87
- '你在把一份业务文档拆成知识库要用的内容。知识以 Knowledge 为单位:',
88
- '一条可独立检索、验证或执行的最小知识单元。',
89
- '',
90
- '只回一个 JSON 对象,不要散文,不要代码围栏。',
91
- '',
92
- '输出形状:',
93
- '{',
94
- ' "subject": "这份文档讲的业务主体",',
95
- ' "knowledge": [',
96
- ' { "id": "k1",',
97
- ' "text": "一条可独立检索、验证或执行的最小知识单元",',
98
- ' "object": "对象名或 null", "action": "动作名或 null", "scene": "场景名或 null",',
99
- ' "section": "步骤", "order": 1,',
100
- ' "sources": [ { "quote": "原文里原样复制的一段", "heading_path": ["一级", "二级"] } ] }',
101
- ' ],',
102
- ' "objects": [ { "mention": "原文中的对象叫法", "definition": "一句话说清它指什么、边界在哪", "evidence": "支持它的原文短引文", "existing": "已有对象的名字(没有就省略这个键)" } ],',
103
- ' "actions": [ { "mention": "原文中的动作叫法", "definition": "同上", "evidence": "支持它的原文短引文", "existing": "…" } ],',
104
- ' "scenes": [ { "mention": "原文中的场景叫法", "definition": "同上", "evidence": "支持它的原文短引文", "existing": "…" } ],',
105
- ' "dropped": [ { "quote": "原文片段", "why": "为什么丢掉" } ]',
106
- '}',
107
- '',
108
- '# 知识:一条只讲一个单元',
109
- '- text 是一条能脱离上下文独立阅读的最小知识单元。事实要能判断真假,操作步骤要能被执行。',
110
- '- 一段原文里有几个独立单元就写几条。不要压成一条,也不要拆碎。',
111
- ' 不该拆:「SPM 由 spm_b、spm_c、spm_d 三部分构成」是一个完整事实。',
112
- ' 该拆:「spm_c 是楼层 ID」「楼层拖拽后 ID 会变化」「取数不能写死楼层 ID」是三条。',
113
- '- 不许推理出原文没有的事实。只做压缩、归一化、结构化。不许编原文没有的步骤。',
114
- '- 不要写「该字段」「上述」这种指代 —— 读者看不到上下文。',
115
- '',
116
- ...AXIS_CONTRACT_LINES,
117
- '',
118
- '- 一条 Knowledge 只挂一个 object、一个 action、一个 scene。那是它的家。',
119
- ' 别的卡片可以引用它 —— 那是卡片的事,不是坐标的事,不要为它多挂几个坐标。',
120
- '- 三个都留 null 是允许的。它不进矩阵、不成卡,但仍然可被全库命中。',
121
- ' 不要为了让它成卡而编一个坐标。',
122
- '- 不要造"动作实例"。「通天塔spm取数」不是动作,它是坐标(通天塔 × 取数 × SPM)推出来的卡名。',
123
- '',
124
- '# 坐标:定义与证据',
125
- '- 每个 object / action / scene 都写 `definition`:一句话说清**它指什么、边界在哪**。',
126
- ' 它是下一次抽取的参考 —— 名字只能让人认出写法相同的东西,定义才能认出「换了说法但同一个」。',
127
- ' 写「通天塔坑位click:通天塔投放位上的一次点击上报」这种能判断的句子,不要写「一个对象」这种空话。',
128
- '- 每个 object / action / scene 都写 `evidence`:从原文复制支持该坐标及其定义的最短片段。没有证据就不要抽这个坐标。',
129
- '- `definition` 只能总结原文和已有坐标定义能支持的范围,不要补造原文没有的属性、状态或因果。',
130
- '',
131
- '# 坐标:先看用户消息里的「已有坐标」',
132
- '- 你讲的东西如果就是清单里的某一个(哪怕原文用的是另一个说法),就写**它的名字**,',
133
- ' 并把 `existing` 写成那个名字。别造一个近似的名字 —— 那会让库里长出两个只在写法上不同的实体。',
134
- '- 清单里没有的才写新名字(`existing` 留空)。拿不准就写新名字:解析那一步会兜底。',
135
- '- 清单是**参考**,不是限制:库里没有的东西照样可以抽出来。',
136
- '',
137
- '# 来源:原样,别改写',
138
- '- quote 必须一个字都不改,从原文原样复制。',
139
- '- 挑最短的必要片段,不要整段照抄。',
140
- '- 一段原文支撑多条知识时,每条都要各自写上它的 quote。',
141
- '- heading_path 是从外到内的标题路径,只作定位线索。',
142
- '',
143
- '# 位置:这条知识在卡里排哪',
144
- ...positionRule,
145
- '- order 是同一小节内的第几位,从 1 开始。',
146
- '- 不要写卡片正文,也不要写导语、备注、警告。你只给"哪条知识放在哪个小节、排第几"。',
147
- '',
148
- '# 别把排版当结构',
149
- '- 原文里的小节标题只是作者写给"人顺着读"的排版,不是知识边界。',
150
- '- 一个标题里可以装几件事,一件事也可以跨几个标题。不要按标题切。',
151
- '',
152
- '- 不含知识的片段放 dropped,写清 why。不许悄悄丢。',
153
- '',
154
- '每条 quote 必须从原文原样复制,一个字都不要改。没有 quote 的判断一律不要。',
155
- ].join('\n');
14
+ /** 抽取契约的 system 段搬到了 `extract-contract.ts`(说明页要显示它,而这里进不了浏览器)。 */
15
+ export { buildTrialSystem } from './extract-contract.js';
156
16
  /** 默认的 system 段(不下发骨架小节)。试跑面板用它。 */
157
17
  export const TRIAL_SYSTEM = buildTrialSystem();
158
18
  /** 组装提示词。全文进去 —— 标题本来就在正文里,不必再列一遍。 */
@@ -172,7 +32,7 @@ export function buildTrialPrompt(input) {
172
32
  const note = (input.note ?? '').trim();
173
33
  if (note !== '')
174
34
  sections.push('# 本库的坐标约定(人写的,优先听它)', note, '');
175
- sections.push('# 输出', '按 system 里说的形状,回一个 JSON 对象。');
35
+ sections.push('# 输出', `按 system 中的版本协议返回${input.outputFormat === 'json' ? ' JSON 对象' : ' TOON 表格'},不要混用格式。`);
176
36
  return sections.join('\n');
177
37
  }
178
38
  const AXIS_BLOCK_TITLE = { object: '对象', action: '动作', scene: '场景' };
@@ -235,6 +95,11 @@ function renderAxisBlock(block) {
235
95
  /** 从可能带 ``` 围栏的文本里取出 JSON。与 `extract-model.ts` 同构。 */
236
96
  function parseJsonObject(raw) {
237
97
  const trimmed = raw.trim();
98
+ // Parse the transport first: code fences inside JSON string values are source data.
99
+ try {
100
+ return JSON.parse(trimmed);
101
+ }
102
+ catch { /* tolerate an outer Markdown wrapper */ }
238
103
  const fenced = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/);
239
104
  const body = (fenced ? fenced[1] : trimmed).trim();
240
105
  try {
@@ -269,7 +134,7 @@ function plainRecord(value) {
269
134
  * 被误报为「清单外」并置空,最终整批 Knowledge 都变成「无坐标」。先把它们补回
270
135
  * 抽取清单,再走同一套 Entity Resolution,既不猜坐标,也不绕过注册表。
271
136
  */
272
- function axisMentionsFromKnowledge(raw) {
137
+ function axisMentionsFromItems(raw) {
273
138
  const out = { object: [], action: [], scene: [] };
274
139
  if (!Array.isArray(raw))
275
140
  return out;
@@ -292,6 +157,12 @@ function axisMentionsFromKnowledge(raw) {
292
157
  }
293
158
  return out;
294
159
  }
160
+ function axisMentionsFromKnowledge(raw) {
161
+ return axisMentionsFromItems(raw);
162
+ }
163
+ function axisMentionsFromEvents(raw) {
164
+ return axisMentionsFromItems(raw);
165
+ }
295
166
  /** 顶层轴清单优先,Knowledge 坐标只补缺项;readAxes 会按归一化名称去重。 */
296
167
  function mergeAxisMentions(raw, supplements) {
297
168
  return [...(Array.isArray(raw) ? raw : []), ...supplements];
@@ -581,6 +452,9 @@ function readKnowledge(raw, options) {
581
452
  const order = typeof rawOrder === 'number' && Number.isFinite(rawOrder) ? Math.trunc(rawOrder) : 1;
582
453
  knowledge.push({
583
454
  id,
455
+ kind: record.kind === 'procedure' ? 'procedure' : 'fact',
456
+ ...(record.scope_identity === true ? { scopeIdentity: true } : {}),
457
+ ...(record.data && typeof record.data === 'object' ? { data: record.data } : {}),
584
458
  text,
585
459
  object,
586
460
  action,
@@ -593,6 +467,141 @@ function readKnowledge(raw, options) {
593
467
  }
594
468
  return { knowledge, problems };
595
469
  }
470
+ function readTrialSources(raw, options) {
471
+ if (!Array.isArray(raw))
472
+ return [];
473
+ const sources = [];
474
+ for (const item of raw) {
475
+ if (item === null || typeof item !== 'object')
476
+ continue;
477
+ const source = item;
478
+ const quote = str(source.quote);
479
+ if (!quote)
480
+ continue;
481
+ const located = locateQuote(options.text, quote);
482
+ sources.push({
483
+ documentId: options.documentId,
484
+ quote,
485
+ ...(located.locator ? { locator: located.locator } : {}),
486
+ headingPath: strList(source.heading_path),
487
+ found: located.found,
488
+ });
489
+ }
490
+ return sources;
491
+ }
492
+ /** 读取一次具体事件;缺失字段保留为空,不用模型补猜。 */
493
+ function readEvents(raw, options) {
494
+ if (!Array.isArray(raw))
495
+ return { events: [], problems: [] };
496
+ const objectMap = new Map(options.objects.flatMap(axis => [axis.name, ...axis.aliases].map(name => [normalizeAxisName(name), axis.name])));
497
+ const actionMap = new Map(options.actions.flatMap(axis => [axis.name, ...axis.aliases].map(name => [normalizeAxisName(name), axis.name])));
498
+ const sceneMap = new Map(options.scenes.flatMap(axis => [axis.name, ...axis.aliases].map(name => [normalizeAxisName(name), axis.name])));
499
+ const events = [];
500
+ const problems = [];
501
+ const ids = new Set();
502
+ for (const entry of raw) {
503
+ if (entry === null || typeof entry !== 'object')
504
+ continue;
505
+ const record = entry;
506
+ const id = str(record.id) || `e${events.length + 1}`;
507
+ if (ids.has(id)) {
508
+ problems.push(`Event id「${id}」重复,后续条目已跳过`);
509
+ continue;
510
+ }
511
+ ids.add(id);
512
+ const title = str(record.title);
513
+ const summary = str(record.summary) || title;
514
+ if (!title && !summary) {
515
+ problems.push(`Event「${id}」没有标题或摘要,已跳过`);
516
+ continue;
517
+ }
518
+ const coordinate = plainRecord(record.coordinate);
519
+ const resolve = (value, map, axis) => {
520
+ const mention = str(value);
521
+ if (!mention)
522
+ return null;
523
+ const canonical = map.get(normalizeAxisName(mention));
524
+ if (canonical)
525
+ return canonical;
526
+ problems.push(`Event「${id}」的${axis}「${mention}」没有进入轴清单,已置空`);
527
+ return null;
528
+ };
529
+ const object = resolve(coordinate.object_mention ?? coordinate.object, objectMap, '对象');
530
+ const action = resolve(coordinate.action_mention ?? coordinate.action, actionMap, '动作');
531
+ const scene = resolve(coordinate.scene_mention ?? coordinate.scene, sceneMap, '场景');
532
+ const timeline = [];
533
+ if (Array.isArray(record.timeline)) {
534
+ for (const [index, rawStep] of record.timeline.entries()) {
535
+ if (rawStep === null || typeof rawStep !== 'object')
536
+ continue;
537
+ const step = rawStep;
538
+ const description = str(step.description);
539
+ if (!description)
540
+ continue;
541
+ const candidateType = str(step.type);
542
+ const type = ['observation', 'check', 'action', 'result', 'conclusion'].includes(candidateType)
543
+ ? candidateType
544
+ : 'observation';
545
+ const sources = readTrialSources(step.sources, options);
546
+ if (!sources.some(source => source.found))
547
+ problems.push(`Event「${id}」时间线第 ${index + 1} 项没有可核验的原文引文`);
548
+ timeline.push({
549
+ id: str(step.id) || `${id}.t${index + 1}`,
550
+ type,
551
+ description,
552
+ result: str(step.result) || null,
553
+ at: str(step.at) || null,
554
+ sources,
555
+ });
556
+ }
557
+ }
558
+ const sources = readTrialSources(record.sources, options);
559
+ const evidence = [...sources, ...timeline.flatMap(step => step.sources)];
560
+ if (!evidence.some(source => source.found)) {
561
+ problems.push(`Event「${id}」没有可核验的原文引文,已留在抽取轨迹但不进入 Event 真源`);
562
+ continue;
563
+ }
564
+ const rawRootCause = record.root_cause;
565
+ const root = typeof rawRootCause === 'string' ? { text: rawRootCause, status: 'suspected' } : plainRecord(rawRootCause);
566
+ const rootCause = str(root.text) || null;
567
+ const rootStatus = str(root.status);
568
+ const rootCauseStatus = rootCause && (rootStatus === 'confirmed' || rootStatus === 'suspected')
569
+ ? rootStatus
570
+ : null;
571
+ const missing = strList(record.missing);
572
+ const addMissing = (label, missingValue) => {
573
+ if (!str(missingValue) && !missing.includes(label))
574
+ missing.push(label);
575
+ };
576
+ const occurredAt = str(record.occurred_at) || null;
577
+ const symptom = str(record.symptom) || null;
578
+ const outcome = str(record.outcome) || null;
579
+ addMissing('发生时间', occurredAt);
580
+ addMissing('问题现象', symptom);
581
+ addMissing('根因', rootCause);
582
+ addMissing('处理结果', outcome);
583
+ addMissing('问题坐标', object || action || scene);
584
+ events.push({
585
+ id,
586
+ externalId: str(record.external_id) || null,
587
+ title: title || summary,
588
+ summary,
589
+ object,
590
+ action,
591
+ scene,
592
+ occurredAt,
593
+ symptom,
594
+ timeline,
595
+ rootCause,
596
+ rootCauseStatus,
597
+ outcome,
598
+ missing,
599
+ sources,
600
+ noCoordinate: !object && !action && !scene,
601
+ });
602
+ }
603
+ return { events, problems };
604
+ }
596
605
  // ------------------------------------------------------------ 本地推导
597
606
  /**
598
607
  * 物化 Wiki Card(第 5 步)。**系统做,确定性。**
@@ -606,27 +615,40 @@ function readKnowledge(raw, options) {
606
615
  * **没有"要不要建卡"这个问题。** 一个坐标 + 至少一条知识,就天然要建。
607
616
  * 三个分量全空的知识不成卡 —— 它没有坐标。
608
617
  */
609
- export function materialize(knowledge) {
618
+ export function materialize(knowledge, events = []) {
610
619
  const groups = new Map();
611
- for (const item of knowledge) {
612
- if (item.noCoordinate)
613
- continue;
614
- const key = `${item.object ?? ''}\u0001${item.action ?? ''}\u0001${item.scene ?? ''}`;
620
+ const groupOf = (object, action, scene) => {
621
+ const key = `${object ?? ''}\u0001${action ?? ''}\u0001${scene ?? ''}`;
615
622
  let card = groups.get(key);
616
623
  if (!card) {
617
624
  card = {
618
- object: item.object,
619
- action: item.action,
620
- scene: item.scene,
621
- name: cardNameFor(item.object, item.action, item.scene),
625
+ object,
626
+ action,
627
+ scene,
628
+ name: cardNameFor(object, action, scene),
622
629
  placements: [],
630
+ events: [],
623
631
  };
624
632
  groups.set(key, card);
625
633
  }
634
+ return card;
635
+ };
636
+ for (const item of knowledge) {
637
+ if (item.noCoordinate)
638
+ continue;
639
+ const card = groupOf(item.object, item.action, item.scene);
626
640
  card.placements.push({ item: item.id, section: item.section, order: item.order });
627
641
  }
642
+ for (const event of events) {
643
+ if (event.noCoordinate)
644
+ continue;
645
+ const key = `${event.object ?? ''}\u0001${event.action ?? ''}\u0001${event.scene ?? ''}`;
646
+ // A WikiCard is created by Knowledge. Event only adds a reference to an existing knowledge group.
647
+ groups.get(key)?.events.push(event.id);
648
+ }
628
649
  for (const card of groups.values()) {
629
650
  card.placements.sort((left, right) => left.section.localeCompare(right.section) || left.order - right.order || left.item.localeCompare(right.item));
651
+ card.events.sort((left, right) => left.localeCompare(right));
630
652
  }
631
653
  return [...groups.values()];
632
654
  }
@@ -644,7 +666,7 @@ export function materialize(knowledge) {
644
666
  *
645
667
  * 组是**最小的可点单位**:点一个数字要看到的就是那一组的知识。
646
668
  */
647
- export function buildMatrix(objects, actions, knowledge, wikiCards) {
669
+ export function buildMatrix(objects, actions, knowledge, wikiCards, events = []) {
648
670
  /** 一组一组的桶。键是 `object\u0001action\u0001scene`。 */
649
671
  const buckets = new Map();
650
672
  const bucketOf = (object, action, scene) => {
@@ -652,7 +674,7 @@ export function buildMatrix(objects, actions, knowledge, wikiCards) {
652
674
  const hit = buckets.get(key);
653
675
  if (hit)
654
676
  return hit;
655
- const created = { object, action, scene, knowledge: 0, items: [] };
677
+ const created = { object, action, scene, knowledge: 0, events: 0, items: [], eventItems: [] };
656
678
  buckets.set(key, created);
657
679
  return created;
658
680
  };
@@ -663,6 +685,13 @@ export function buildMatrix(objects, actions, knowledge, wikiCards) {
663
685
  bucket.knowledge += 1;
664
686
  bucket.items.push(item.id);
665
687
  }
688
+ for (const event of events) {
689
+ if (event.noCoordinate)
690
+ continue;
691
+ const bucket = bucketOf(event.object, event.action, event.scene ?? '');
692
+ bucket.events += 1;
693
+ bucket.eventItems.push(event.id);
694
+ }
666
695
  // 卡名叠进它自己那一组。一个 `(object, action, scene)` 至多一张卡,所以是赋值不是追加。
667
696
  const cardOf = new Map();
668
697
  for (const card of wikiCards) {
@@ -676,8 +705,10 @@ export function buildMatrix(objects, actions, knowledge, wikiCards) {
676
705
  out.push({
677
706
  scene: bucket.scene,
678
707
  knowledge: bucket.knowledge,
708
+ events: bucket.events,
679
709
  card: cardOf.get(`${object ?? '\u0000'}\u0001${action ?? '\u0000'}\u0001${bucket.scene}`) ?? '',
680
710
  items: bucket.items,
711
+ eventItems: bucket.eventItems,
681
712
  });
682
713
  }
683
714
  // 场景名的阅读顺序:先空场景(它是「没有细分」的那一组),再按名字。
@@ -689,7 +720,7 @@ export function buildMatrix(objects, actions, knowledge, wikiCards) {
689
720
  const groups = groupsFor(object, action);
690
721
  if (groups.length === 0)
691
722
  continue;
692
- cells.push({ object, action, groups, knowledge: groups.reduce((sum, group) => sum + group.knowledge, 0) });
723
+ cells.push({ object, action, groups, knowledge: groups.reduce((sum, group) => sum + group.knowledge, 0), events: groups.reduce((sum, group) => sum + group.events, 0) });
693
724
  }
694
725
  }
695
726
  // 行头:这一行里「有对象、没动作」的那些知识。列头同理。
@@ -697,13 +728,13 @@ export function buildMatrix(objects, actions, knowledge, wikiCards) {
697
728
  for (const object of objects) {
698
729
  const groups = groupsFor(object, null);
699
730
  if (groups.length > 0)
700
- noAction.push({ name: object, groups, knowledge: groups.reduce((sum, group) => sum + group.knowledge, 0) });
731
+ noAction.push({ name: object, groups, knowledge: groups.reduce((sum, group) => sum + group.knowledge, 0), events: groups.reduce((sum, group) => sum + group.events, 0) });
701
732
  }
702
733
  const noObject = [];
703
734
  for (const action of actions) {
704
735
  const groups = groupsFor(null, action);
705
736
  if (groups.length > 0)
706
- noObject.push({ name: action, groups, knowledge: groups.reduce((sum, group) => sum + group.knowledge, 0) });
737
+ noObject.push({ name: action, groups, knowledge: groups.reduce((sum, group) => sum + group.knowledge, 0), events: groups.reduce((sum, group) => sum + group.events, 0) });
707
738
  }
708
739
  return {
709
740
  objects,
@@ -712,6 +743,7 @@ export function buildMatrix(objects, actions, knowledge, wikiCards) {
712
743
  noAction,
713
744
  noObject,
714
745
  noCoordinate: knowledge.filter(item => item.noCoordinate).length,
746
+ noCoordinateEvents: events.filter(item => item.noCoordinate).length,
715
747
  withKnowledge: cells.filter(cell => cell.knowledge > 0).length,
716
748
  filled: cells.length,
717
749
  slots: objects.length * actions.length,
@@ -761,10 +793,10 @@ function findTwins(knowledge) {
761
793
  * 每一步给两样:`rows`(按什么判、缺什么)和 `items`(**逐条判出的实际值**)。
762
794
  * 试跑面板是给人逐步 review 的,只有统计没有值就没法 review。
763
795
  *
764
- * 第 2、3 步里如实写明单文档试跑缺什么:归一缺库内注册表,同义与冲突缺第二次模型调用。
796
+ * 第 2、3 步里如实写明能力边界:轴归一需要库内注册表,候选歧义可在编译时补判;知识同义与冲突仍不做模型裁决。
765
797
  */
766
798
  export function buildReport(input) {
767
- const { objects, actions, scenes, knowledge, wikiCards, matrix, dropped } = input;
799
+ const { objects, actions, scenes, knowledge, events, wikiCards, matrix, dropped } = input;
768
800
  const headings = scanHeadings(input.text);
769
801
  const axes = [...objects, ...actions, ...scenes];
770
802
  const aliased = axes.filter(axis => axis.aliases.length > 0);
@@ -781,8 +813,15 @@ export function buildReport(input) {
781
813
  invented.push({ id: item.id, quote: source.quote });
782
814
  }
783
815
  }
816
+ for (const event of events) {
817
+ for (const source of [...event.sources, ...event.timeline.flatMap(step => step.sources)]) {
818
+ if (!source.found)
819
+ invented.push({ id: event.id, quote: source.quote });
820
+ }
821
+ }
784
822
  const noSource = knowledge.filter(item => item.sources.length === 0);
785
823
  const noCoordinate = knowledge.filter(item => item.noCoordinate);
824
+ const noCoordinateEvents = events.filter(item => item.noCoordinate);
786
825
  const twins = findTwins(knowledge);
787
826
  const collisions = findCollisions(wikiCards);
788
827
  const sections = new Set(knowledge.flatMap(item => item.section));
@@ -790,25 +829,28 @@ export function buildReport(input) {
790
829
  const steps = [
791
830
  {
792
831
  id: 'extract', order: 1, name: '语义抽取', phase: '① Extract · 抽取', actor: '模型',
793
- needsHuman: noCoordinate.length > 0 || noSource.length > 0 || knowledge.length === 0,
794
- summary: `${knowledge.length} 条知识 · ${objects.length} 对象 · ${actions.length} 动作 · ${scenes.length} 场景 · 一次调用`,
832
+ needsHuman: noCoordinate.length > 0 || noSource.length > 0 || knowledge.length === 0 || events.some(event => event.missing.length > 0),
833
+ summary: `${knowledge.length} 条 Knowledge · ${events.length} 个 Event · ${objects.length} 对象 · ${actions.length} 动作 · ${scenes.length} 场景 · 一次调用`,
795
834
  rows: [
796
835
  { label: '输入', value: `${input.text.split(/\r?\n/).length} 行 / ${countChars(input.text)} 字 / ${headings.length} 个标题,全文进去,不切块` },
797
- { label: '一次调用出全部', value: '不拆成"先抽对象再抽动作再抽知识" —— 拆开要把全文重发多遍,判"这段讲什么"时手上没有原话' },
836
+ { label: '一次调用出全部', value: '同一份 Document 并行抽取 Knowledge 与 Event,再提取 Object / Action / Scene mentions' },
798
837
  { label: '这一步不解决', value: '这是不是已有知识(第 3 步)· 这些名字是不是已有实体(第 2 步)· 应该生成哪张卡(第 5 步)' },
799
838
  { label: '五条规则', value: '一条只讲一个单元 · 不推理出原文没有的事实 · 不写「该字段」这种指代 · 坐标各一个 · quote 原样复制' },
800
- { label: '没有出处', value: noSource.length > 0 ? `${noSource.length} 条知识一个 quote 都没给` : '无' },
839
+ { label: '没有出处', value: noSource.length > 0 ? `${noSource.length} 条 Knowledge 一个 quote 都没给` : 'Knowledge / Event 都有可核验出处' },
840
+ ],
841
+ items: [
842
+ ...knowledge.map(item => makeItem(item.id, shortQuote(item.text), `${coordLabel(item.object, item.action, item.scene)} · ${item.sources.length} 条出处`, item.noCoordinate || item.sources.length === 0 ? 'warn' : undefined)),
843
+ ...events.map(event => makeItem(`Event ${event.id}`, event.title, `${coordLabel(event.object, event.action, event.scene)} · ${event.timeline.length} 个时间线节点 · ${event.missing.length} 项待补`, event.noCoordinate || event.missing.length > 0 ? 'warn' : undefined)),
801
844
  ],
802
- items: knowledge.map(item => makeItem(item.id, shortQuote(item.text), `${coordLabel(item.object, item.action, item.scene)} · ${item.sources.length} 条出处`, item.noCoordinate || item.sources.length === 0 ? 'warn' : undefined)),
803
845
  },
804
846
  {
805
847
  id: 'entity', order: 2, name: '轴实体归一', phase: '② Resolve · 归一', actor: '系统',
806
848
  needsHuman: aliased.length > 0 || ambiguous.length > 0 || created.length > 0,
807
849
  summary: `${axes.length} 个轴实体 · 命中 ${matched.length} · 新建候选 ${created.length} · 不唯一 ${ambiguous.length}`,
808
850
  rows: [
809
- { label: '顺序', value: '归一化(大小写 / 空格 / 符号)→ 作用域内 canonical → 作用域内 alias → 全局唯一 → 新建候选 + 例外上报' },
851
+ { label: '顺序', value: '注册表直接命中 → 对有候选的歧义坐标合并一次模型补判 → 未命中时新建候选' },
810
852
  { label: '三个轴同一套', value: 'Object / Action / Scene 走同一套流程,没有哪个更特殊' },
811
- { label: '不唯一就不猜', value: '一个 mention 在多个作用域里都命中时保留原样并报出来。猜错等于把知识挂到错误的对象上,而那个错误会一路传到卡名' },
853
+ { label: '不唯一就不猜', value: '模型只在给定候选中选择;证据不足时保留歧义。猜错等于把知识挂到错误的对象上,而那个错误会一路传到卡名' },
812
854
  { label: '不机械拼前缀', value: '只有原文、章节、SourceRaw 元数据提供了作用域证据,才生成全限定名 —— 「通天塔」+ 每个对象会把「楼层」错加成「通天塔楼层」。人写的指导随已有坐标一起下发,由模型据此判断' },
813
855
  /*
814
856
  * 「这一次发了多少参考」必须露出来(0068)。模型看不到某条坐标时会以为库里没有它,
@@ -817,8 +859,10 @@ export function buildReport(input) {
817
859
  { label: '已有坐标', value: input.axesContext === undefined
818
860
  ? '这一次没有下发(没接注册表,或者库里还没有实体)—— 模型只能自己造名字'
819
861
  : `下发 ${input.axesContext.injected} / 共 ${input.axesContext.totals} 条${input.axesContext.truncated > 0 ? ` · 未下发 ${input.axesContext.truncated} 条` : ''}${input.axesContext.selection === 'relevant' ? ' · 当前文档相关候选' : input.axesContext.selection === 'full' ? ' · 全集' : ''},含名字、别名、定义与人写的指导` },
820
- { label: '模型可以指认', value: '模型说「这就是已有的某个」,代码会验(查得到 / 同类 / 没被并);验不过就退回机械解析 —— 与卡片层 existing_id 同一条纪律' },
821
- { label: '新建的是候选', value: '没命中就建一个 status=candidate 的实体,等人确认。入库在前、确认在后 —— 与卡片 review 同一条纪律' },
862
+ { label: '模型补判', value: input.model.axisResolution
863
+ ? '本次对无法直接命中的坐标发出了一次合并请求;模型只能返回候选 ID,代码会验(查得到 / 同类 / 没被并)'
864
+ : '本次坐标都可直接解析,或没有可比较的候选,因此没有额外模型请求' },
865
+ { label: '新建的是候选', value: '模型确认没有匹配项后才建 status=candidate;证据不足时保留歧义,等人确认' },
822
866
  { label: '三类绝不进别名', value: '上位概念(「通天塔spm取数」不能含「通天塔」)· 组成部分(不能含「spm取数」)· 相关但不同(不能含「通天塔埋点」)' },
823
867
  { label: '注册表', value: axes.some(axis => axis.outcome === 'no-registry')
824
868
  ? '这次没有查到库内注册表(这个部署上没有,或调用方没给)。所以只判得动文档内的写法变体'
@@ -861,17 +905,17 @@ export function buildReport(input) {
861
905
  },
862
906
  {
863
907
  id: 'materialize', order: 5, name: '按坐标成卡', phase: '③ Materialize · 物化', actor: '系统',
864
- needsHuman: collisions.length > 0 || noCoordinate.length > 0,
865
- summary: `${wikiCards.length} 张 Wiki Card · ${placements} 条知识落位 · ${noCoordinate.length} 条无坐标不成卡`,
908
+ needsHuman: collisions.length > 0 || noCoordinate.length > 0 || events.some(event => event.noCoordinate),
909
+ summary: `${wikiCards.length} 张 Wiki Card · ${placements} 条 Knowledge · ${events.filter(event => !event.noCoordinate).length} 个 Event`,
866
910
  rows: [
867
911
  { label: '三步', value: '按 (object, action, scene) 分组 → 每组物化成一张 Wiki Card → 生成自然语言标题' },
868
912
  { label: '标题组织', value: '完整坐标写成「对象在场景下的动作」;缺少分量时退化为通顺的短标题;旧拼接标题保留为 alias' },
869
913
  { label: '为什么不让模型做', value: '坐标是卡片主键 · 标题是确定的展示投影 · 模型判会漂移(同一坐标每次给不同标题会污染召回)' },
870
- { label: '没有"要不要建卡"', value: '一个坐标 + 至少一条知识,就天然要建。模型只回答判断类问题,机械类问题交给系统' },
871
- { label: '不成卡的那些', value: noCoordinate.length > 0 ? `${noCoordinate.length} 条知识没有坐标,不进矩阵也不成卡 —— 它们仍然可被全库命中` : '无' },
914
+ { label: '卡片由 Knowledge 生成', value: '坐标下至少有一条 Knowledge 才物化 WikiCard;同坐标 Event 只建立引用,不单独建卡' },
915
+ { label: '不成卡的那些', value: noCoordinate.length + events.filter(event => event.noCoordinate).length > 0 ? `${noCoordinate.length} 条 Knowledge、${events.filter(event => event.noCoordinate).length} 个 Event 缺少坐标,不归入坐标卡` : '无' },
872
916
  ],
873
917
  items: wikiCards.length > 0
874
- ? wikiCards.map(card => makeItem(coordLabel(card.object, card.action, card.scene), card.name, `${card.placements.length} 条知识`))
918
+ ? wikiCards.map(card => makeItem(coordLabel(card.object, card.action, card.scene), card.name, `${card.placements.length} 条 Knowledge · ${card.events.length} 个 Event`))
875
919
  : [makeItem('—', '没有成卡', '知识一条都没有坐标,或者模型没给出知识', 'warn')],
876
920
  },
877
921
  {
@@ -907,7 +951,7 @@ export function buildReport(input) {
907
951
  ],
908
952
  items: [
909
953
  makeItem('召回单元', `${sections.size} 个 section`, '卡片按 ## 小节切成一节一条'),
910
- makeItem('Knowledge', `${knowledge.length} 条`, '落在这些 section 上的真源(试跑不建索引)'),
954
+ makeItem('Knowledge / Event', `${knowledge.length} / ${events.length}`, '两类并列真源;Knowledge 生成 WikiCard,Event 通过引用关联'),
911
955
  makeItem('轴注册表', `${axes.length} 条`, 'canonical name + aliases —— 不是索引'),
912
956
  ],
913
957
  },
@@ -950,6 +994,8 @@ export function buildReport(input) {
950
994
  }
951
995
  for (const item of noCoordinate)
952
996
  exceptions.push({ step: '无坐标', message: `「${shortQuote(item.text)}」三个坐标分量都空。它不进矩阵、不成卡,但仍可被全库命中 —— 要人决定补坐标还是单独归档` });
997
+ for (const event of noCoordinateEvents)
998
+ exceptions.push({ step: 'Event 无坐标', message: `Event「${shortQuote(event.title)}」没有坐标,因此没有归入 Wiki Card;Event 本身和出处仍保留` });
953
999
  for (const twin of twins)
954
1000
  exceptions.push({ step: '同义候选', message: `${twin.ids.join(' / ')} 文本归一化后相同,要人确认是不是同一条知识` });
955
1001
  for (const collision of collisions) {
@@ -968,6 +1014,7 @@ export function buildReport(input) {
968
1014
  actions,
969
1015
  scenes,
970
1016
  knowledge,
1017
+ events,
971
1018
  wikiCards,
972
1019
  matrix,
973
1020
  checks,
@@ -985,10 +1032,11 @@ function emptyReport(input) {
985
1032
  const actions = [];
986
1033
  const scenes = [];
987
1034
  const knowledge = [];
1035
+ const events = [];
988
1036
  const wikiCards = [];
989
1037
  return buildReport({
990
1038
  title: input.title, text: input.text, subject: input.subject,
991
- objects, actions, scenes, knowledge, wikiCards, dropped: [],
1039
+ objects, actions, scenes, knowledge, events, wikiCards, dropped: [],
992
1040
  matrix: buildMatrix([], [], [], []),
993
1041
  problems: [],
994
1042
  model: input.model, promptUser: input.promptUser,
@@ -1007,8 +1055,10 @@ export async function runWikiTrial(input) {
1007
1055
  const subject = (input.subject ?? '').trim();
1008
1056
  const docId = (input.docId ?? '').trim();
1009
1057
  // 提示词先组装好再走分支:模型不可用时它照样要回给界面 —— 用户要看的正是"本来会发出去什么"。
1010
- const promptUser = buildTrialPrompt({ title: input.title, text: input.text, ...(input.axes === undefined ? {} : { axes: input.axes }), ...(input.note ? { note: input.note } : {}) });
1011
- const system = buildTrialSystem(input.sections);
1058
+ const promptUser = buildTrialPrompt({ title: input.title, text: input.text, ...(input.axes === undefined ? {} : { axes: input.axes }), ...(input.note ? { note: input.note } : {}), outputFormat: input.outputFormat });
1059
+ const system = buildTrialSystem(input.sections, input.outputFormat);
1060
+ const sessionId = input.sessionId ?? 'knowledge:trial';
1061
+ const request = { ...input.modelRequest, sessionId };
1012
1062
  const axesContext = input.axes === undefined ? undefined : {
1013
1063
  injected: ['object', 'action', 'scene'].reduce((sum, kind) => sum + (input.axes.entries[kind]?.length ?? 0), 0),
1014
1064
  totals: ['object', 'action', 'scene'].reduce((sum, kind) => sum + (input.axes.totals[kind] ?? 0), 0),
@@ -1019,21 +1069,44 @@ export async function runWikiTrial(input) {
1019
1069
  return emptyReport({
1020
1070
  title: input.title, text: input.text, subject: subject || input.title, promptUser, system,
1021
1071
  axesContext,
1022
- model: { ok: false, why: input.callWhy ?? '模型不可用' },
1072
+ model: { ok: false, why: input.callWhy ?? '模型不可用', request },
1023
1073
  });
1024
1074
  }
1025
1075
  let raw = '';
1076
+ let usage;
1026
1077
  try {
1027
- raw = await input.call({ system, prompt: promptUser, sessionId: input.sessionId ?? 'knowledge:trial' });
1078
+ raw = await input.call({ system, prompt: promptUser, sessionId, onUsage: value => { usage = value; }, onDelta: text => { raw += text; input.onDelta?.(text); } });
1028
1079
  }
1029
1080
  catch (cause) {
1030
1081
  return emptyReport({
1031
1082
  title: input.title, text: input.text, subject: subject || input.title, promptUser, system,
1032
1083
  axesContext,
1033
- model: { ok: false, why: `调用模型失败:${cause instanceof Error ? cause.message : String(cause)}` },
1084
+ model: {
1085
+ ok: false,
1086
+ why: `调用模型失败:${cause instanceof Error ? cause.message : String(cause)}`,
1087
+ request,
1088
+ ...(raw ? { response: raw } : {}),
1089
+ ...(usage ? { usage } : {}),
1090
+ },
1034
1091
  });
1035
1092
  }
1036
- const parsed = parseJsonObject(raw);
1093
+ let parsed;
1094
+ let outputFormat = 'json';
1095
+ let parseError = '';
1096
+ const body = raw.trim().replace(/^```(?:toon|text)?\s*\n/, '').replace(/\n```\s*$/, '');
1097
+ try {
1098
+ if (/^format:\s*knowledge-table-v[12]\s*$/m.test(body)) {
1099
+ parsed = decodeExtractionTable(body);
1100
+ outputFormat = 'table';
1101
+ }
1102
+ else
1103
+ parsed = parseJsonObject(raw);
1104
+ if (parsed)
1105
+ parsed = normalizeKnowledgeExtraction(parsed);
1106
+ }
1107
+ catch (cause) {
1108
+ parseError = cause instanceof Error ? cause.message : String(cause);
1109
+ }
1037
1110
  const record = parsed !== null && typeof parsed === 'object' ? parsed : undefined;
1038
1111
  if (!record) {
1039
1112
  return emptyReport({
@@ -1041,7 +1114,10 @@ export async function runWikiTrial(input) {
1041
1114
  axesContext,
1042
1115
  model: {
1043
1116
  ok: false,
1044
- why: '模型的回答里没有 JSON',
1117
+ why: parseError || '模型返回不是有效的抽取表格或兼容 JSON',
1118
+ request,
1119
+ response: raw,
1120
+ ...(usage ? { usage } : {}),
1045
1121
  // 把模型实际说的那一段带上:只报「不是 JSON」的话,人不知道该去改什么。
1046
1122
  ...(raw.trim() ? { raw: raw.trim().replace(/\s+/g, ' ').slice(0, 160) } : {}),
1047
1123
  },
@@ -1054,9 +1130,10 @@ export async function runWikiTrial(input) {
1054
1130
  */
1055
1131
  const mentions = plainRecord(record.axis_mentions);
1056
1132
  const knowledgeAxes = axisMentionsFromKnowledge(record.knowledge);
1057
- const objectRead = readAxes(mergeAxisMentions(mentions.objects ?? record.objects, knowledgeAxes.object), 'object');
1058
- const actionRead = readAxes(mergeAxisMentions(mentions.actions ?? record.actions, knowledgeAxes.action), 'action');
1059
- const sceneRead = readAxes(mergeAxisMentions(mentions.scenes ?? record.scenes, knowledgeAxes.scene), 'scene');
1133
+ const eventAxes = axisMentionsFromEvents(record.events);
1134
+ const objectRead = readAxes(mergeAxisMentions(mentions.objects ?? record.objects, [...knowledgeAxes.object, ...eventAxes.object]), 'object');
1135
+ const actionRead = readAxes(mergeAxisMentions(mentions.actions ?? record.actions, [...knowledgeAxes.action, ...eventAxes.action]), 'action');
1136
+ const sceneRead = readAxes(mergeAxisMentions(mentions.scenes ?? record.scenes, [...knowledgeAxes.scene, ...eventAxes.scene]), 'scene');
1060
1137
  /**
1061
1138
  * Resolve 第 2 步:把 mention 交给**轴注册表**。
1062
1139
  *
@@ -1067,18 +1144,40 @@ export async function runWikiTrial(input) {
1067
1144
  * (`坑位click` → `通天塔坑位click`),而 Knowledge 的坐标写的是 mention。
1068
1145
  * 顺序反了,那条知识就会因为「坐标不在清单里」被当成编造的坐标丢掉。
1069
1146
  */
1070
- const objects = await resolveAxes('object', objectRead.axes, input.resolveAxis);
1071
- const actions = await resolveAxes('action', actionRead.axes, input.resolveAxis);
1072
- const scenes = await resolveAxes('scene', sceneRead.axes, input.resolveAxis);
1147
+ let objects;
1148
+ let actions;
1149
+ let scenes;
1150
+ let axisResolution;
1151
+ if (input.resolveAxisSet) {
1152
+ const resolved = await input.resolveAxisSet({
1153
+ objects: objectRead.axes,
1154
+ actions: actionRead.axes,
1155
+ scenes: sceneRead.axes,
1156
+ });
1157
+ objects = resolved.objects;
1158
+ actions = resolved.actions;
1159
+ scenes = resolved.scenes;
1160
+ axisResolution = resolved.trace;
1161
+ }
1162
+ else {
1163
+ objects = await resolveAxes('object', objectRead.axes, input.resolveAxis);
1164
+ actions = await resolveAxes('action', actionRead.axes, input.resolveAxis);
1165
+ scenes = await resolveAxes('scene', sceneRead.axes, input.resolveAxis);
1166
+ }
1073
1167
  const knowledgeRead = readKnowledge(record.knowledge, {
1074
1168
  text: input.text,
1075
1169
  // 有真文档就用它的 id:来源要指得回那份文档,而不是一个标题字符串。
1076
1170
  documentId: docId || input.title,
1077
1171
  objects, actions, scenes,
1078
1172
  });
1173
+ const eventRead = readEvents(record.events, {
1174
+ text: input.text,
1175
+ documentId: docId || input.title,
1176
+ objects, actions, scenes,
1177
+ });
1079
1178
  // `dropped` 在新契约里收在 `audit` 下 —— 它是审计,不是知识模型的一部分(§5.5)。
1080
1179
  const dropped = readDropped(plainRecord(record.audit).dropped ?? record.dropped);
1081
- const wikiCards = materialize(knowledgeRead.knowledge);
1180
+ const wikiCards = materialize(knowledgeRead.knowledge, eventRead.events);
1082
1181
  const modelSubject = str(record.subject) || subject || input.title;
1083
1182
  return buildReport({
1084
1183
  title: input.title, text: input.text, subject: modelSubject,
@@ -1086,13 +1185,25 @@ export async function runWikiTrial(input) {
1086
1185
  actions,
1087
1186
  scenes,
1088
1187
  knowledge: knowledgeRead.knowledge,
1188
+ events: eventRead.events,
1089
1189
  wikiCards,
1090
- matrix: buildMatrix(objects.map(axis => axis.name), actions.map(axis => axis.name), knowledgeRead.knowledge, wikiCards),
1091
- problems: [...objectRead.problems, ...actionRead.problems, ...sceneRead.problems, ...knowledgeRead.problems],
1190
+ matrix: buildMatrix(objects.map(axis => axis.name), actions.map(axis => axis.name), knowledgeRead.knowledge, wikiCards, eventRead.events),
1191
+ problems: [...objectRead.problems, ...actionRead.problems, ...sceneRead.problems, ...knowledgeRead.problems, ...eventRead.problems],
1092
1192
  dropped,
1093
- model: knowledgeRead.knowledge.length > 0
1094
- ? { ok: true }
1095
- : { ok: false, why: '模型没有给出任何知识' },
1193
+ model: {
1194
+ ok: knowledgeRead.knowledge.length > 0 || eventRead.events.length > 0,
1195
+ parsed: Array.isArray(record.knowledge) && Array.isArray(record.events ?? [])
1196
+ && knowledgeRead.knowledge.length === record.knowledge.length
1197
+ && eventRead.events.length === (Array.isArray(record.events) ? record.events.length : 0)
1198
+ && knowledgeRead.knowledge.every(item => item.sources.length > 0 && item.sources.every(source => source.found))
1199
+ && eventRead.events.every(item => [...item.sources, ...item.timeline.flatMap(step => step.sources)].every(source => source.found)),
1200
+ outputFormat,
1201
+ ...(!(knowledgeRead.knowledge.length > 0 || eventRead.events.length > 0) ? { why: '模型没有给出 Knowledge 或 Event' } : {}),
1202
+ request,
1203
+ response: raw,
1204
+ ...(usage ? { usage } : {}),
1205
+ ...(axisResolution ? { axisResolution } : {}),
1206
+ },
1096
1207
  promptUser, system,
1097
1208
  ...(axesContext === undefined ? {} : { axesContext }),
1098
1209
  });
@@ -1132,34 +1243,36 @@ async function resolveAxes(kind, axes, resolveAxis) {
1132
1243
  // `null` = 这个部署上没有注册表。那不是「没命中」,是「这一次没查过」。
1133
1244
  if (resolution === null)
1134
1245
  return axes;
1135
- if ((resolution.outcome === 'matched' || resolution.outcome === 'created') && resolution.entity) {
1136
- const entity = resolution.entity;
1137
- out.push({
1138
- name: entity.name,
1139
- id: entity.id,
1140
- // 原来的 mention 进别名:它可能只是这个实体的一种写法。
1141
- aliases: [...new Set([...axis.aliases, ...(entity.name === axis.name ? [] : [axis.name])])],
1142
- outcome: resolution.outcome === 'created' ? 'new' : 'matched',
1143
- how: describeHit(resolution),
1144
- // 报告里显示的是**库里那份**(模型这次给的可能没被采纳 —— 人写的定义不许覆盖)。
1145
- ...(entity.description ? { definition: entity.description } : axis.definition ? { definition: axis.definition } : {}),
1146
- ...(axis.evidence ? { evidence: axis.evidence } : {}),
1147
- });
1148
- continue;
1149
- }
1150
- if (resolution.outcome === 'ambiguous') {
1151
- const names = (resolution.candidates ?? []).map(candidate => candidate.name);
1152
- out.push({
1153
- ...axis,
1154
- outcome: 'ambiguous',
1155
- how: names.length > 0 ? `不唯一,候选:${names.join('、')}` : '不唯一,但注册表里没有候选',
1156
- });
1157
- continue;
1158
- }
1159
- out.push({ ...axis, outcome: 'no-registry', how: '只做了文档内的机械归一' });
1246
+ out.push(applyTrialAxisResolution(axis, resolution));
1160
1247
  }
1161
1248
  return out;
1162
1249
  }
1250
+ /** 将注册表结论变成报告里的坐标。供批量补判复用同一套字段处理。 */
1251
+ export function applyTrialAxisResolution(axis, resolution) {
1252
+ if (resolution === null)
1253
+ return { ...axis, outcome: 'no-registry', how: '只做了文档内的机械归一' };
1254
+ if ((resolution.outcome === 'matched' || resolution.outcome === 'created') && resolution.entity) {
1255
+ const entity = resolution.entity;
1256
+ return {
1257
+ name: entity.name,
1258
+ id: entity.id,
1259
+ aliases: [...new Set([...axis.aliases, ...(entity.name === axis.name ? [] : [axis.name])])],
1260
+ outcome: resolution.outcome === 'created' ? 'new' : 'matched',
1261
+ how: describeHit(resolution),
1262
+ ...(entity.description ? { definition: entity.description } : axis.definition ? { definition: axis.definition } : {}),
1263
+ ...(axis.evidence ? { evidence: axis.evidence } : {}),
1264
+ };
1265
+ }
1266
+ if (resolution.outcome === 'ambiguous') {
1267
+ const names = (resolution.candidates ?? []).map(candidate => candidate.name);
1268
+ return {
1269
+ ...axis,
1270
+ outcome: 'ambiguous',
1271
+ how: names.length > 0 ? `不唯一,候选:${names.join('、')}` : '不唯一,但注册表里没有候选',
1272
+ };
1273
+ }
1274
+ return { ...axis, outcome: 'ambiguous', how: '坐标为空,无法解析' };
1275
+ }
1163
1276
  /** 读 `dropped`。它是**审计轨迹**(§5.5),不进知识模型。 */
1164
1277
  function readDropped(raw) {
1165
1278
  if (!Array.isArray(raw))
@@ -1181,7 +1294,7 @@ export function trialSummary(report) {
1181
1294
  const pieces = [
1182
1295
  `${report.lines} 行`, `${report.chars} 字`,
1183
1296
  `${report.objects.length} 对象`, `${report.actions.length} 动作`, `${report.scenes.length} 场景`,
1184
- `${report.knowledge.length} 知识`, `${report.wikiCards.length} Wiki Card`,
1297
+ `${report.knowledge.length} Knowledge`, `${report.events.length} Event`, `${report.wikiCards.length} Wiki Card`,
1185
1298
  ];
1186
1299
  const dropped = report.audit.dropped.length;
1187
1300
  if (dropped > 0)