@marinoscar/kvox-eval 0.0.0-bootstrap → 0.1.0-next.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 (245) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +166 -0
  4. package/dist/ask/index.d.ts +6 -0
  5. package/dist/ask/index.js +28 -0
  6. package/dist/ask/question-schema.d.ts +121 -0
  7. package/dist/ask/question-schema.js +167 -0
  8. package/dist/ask/report.d.ts +88 -0
  9. package/dist/ask/report.js +170 -0
  10. package/dist/ask/scorer.d.ts +104 -0
  11. package/dist/ask/scorer.js +164 -0
  12. package/dist/ask-run/ask-command.d.ts +62 -0
  13. package/dist/ask-run/ask-command.js +254 -0
  14. package/dist/ask-run/host/app.d.ts +65 -0
  15. package/dist/ask-run/host/app.js +146 -0
  16. package/dist/ask-run/host/db.d.ts +38 -0
  17. package/dist/ask-run/host/db.js +126 -0
  18. package/dist/ask-run/host/ports.d.ts +35 -0
  19. package/dist/ask-run/host/ports.js +113 -0
  20. package/dist/ask-run/index.d.ts +13 -0
  21. package/dist/ask-run/index.js +35 -0
  22. package/dist/ask-run/replay.d.ts +128 -0
  23. package/dist/ask-run/replay.js +212 -0
  24. package/dist/ask-run/run-ask-eval.d.ts +125 -0
  25. package/dist/ask-run/run-ask-eval.js +193 -0
  26. package/dist/ask-run/seed-golden-graph.d.ts +64 -0
  27. package/dist/ask-run/seed-golden-graph.js +495 -0
  28. package/dist/cli/index.d.ts +3 -0
  29. package/dist/cli/index.js +12 -0
  30. package/dist/cli/kg-command.d.ts +66 -0
  31. package/dist/cli/kg-command.js +238 -0
  32. package/dist/cli/main.d.ts +18 -0
  33. package/dist/cli/main.js +69 -0
  34. package/dist/fixtures/domains.d.ts +16 -0
  35. package/dist/fixtures/domains.js +33 -0
  36. package/dist/fixtures/fixture-schema.d.ts +323 -0
  37. package/dist/fixtures/fixture-schema.js +199 -0
  38. package/dist/fixtures/index.d.ts +16 -0
  39. package/dist/fixtures/index.js +40 -0
  40. package/dist/fixtures/load.d.ts +73 -0
  41. package/dist/fixtures/load.js +137 -0
  42. package/dist/fixtures/questions.d.ts +15 -0
  43. package/dist/fixtures/questions.js +26 -0
  44. package/dist/index.d.ts +20 -0
  45. package/dist/index.js +36 -0
  46. package/dist/kg/gold-runner.d.ts +13 -0
  47. package/dist/kg/gold-runner.js +57 -0
  48. package/dist/kg/index.d.ts +17 -0
  49. package/dist/kg/index.js +65 -0
  50. package/dist/kg/internals.d.ts +7 -0
  51. package/dist/kg/internals.js +17 -0
  52. package/dist/kg/prediction-schema.d.ts +245 -0
  53. package/dist/kg/prediction-schema.js +102 -0
  54. package/dist/kg/predictions.d.ts +11 -0
  55. package/dist/kg/predictions.js +49 -0
  56. package/dist/kg/report.d.ts +84 -0
  57. package/dist/kg/report.js +125 -0
  58. package/dist/kg/run-kg-eval.d.ts +77 -0
  59. package/dist/kg/run-kg-eval.js +137 -0
  60. package/dist/kg/runner.d.ts +72 -0
  61. package/dist/kg/runner.js +51 -0
  62. package/dist/kg/runners/extract-resolve-runner.d.ts +40 -0
  63. package/dist/kg/runners/extract-resolve-runner.js +199 -0
  64. package/dist/kg/runners/extract-runner.d.ts +65 -0
  65. package/dist/kg/runners/extract-runner.js +243 -0
  66. package/dist/kg/scorer.d.ts +226 -0
  67. package/dist/kg/scorer.js +463 -0
  68. package/dist/kg/targets.d.ts +17 -0
  69. package/dist/kg/targets.js +16 -0
  70. package/dist/kg/text.d.ts +45 -0
  71. package/dist/kg/text.js +100 -0
  72. package/dist/live/adapters.d.ts +16 -0
  73. package/dist/live/adapters.js +58 -0
  74. package/dist/live/env.d.ts +39 -0
  75. package/dist/live/env.js +56 -0
  76. package/dist/live/index.d.ts +6 -0
  77. package/dist/live/index.js +16 -0
  78. package/dist/live/live-ai.d.ts +104 -0
  79. package/dist/live/live-ai.js +157 -0
  80. package/dist/parity/constants.d.ts +79 -0
  81. package/dist/parity/constants.js +104 -0
  82. package/dist/parity/index.d.ts +20 -0
  83. package/dist/parity/index.js +38 -0
  84. package/dist/parity/internals.d.ts +8 -0
  85. package/dist/parity/internals.js +16 -0
  86. package/dist/parity/scenario.d.ts +45 -0
  87. package/dist/parity/scenario.js +245 -0
  88. package/dist/parity/script.d.ts +44 -0
  89. package/dist/parity/script.js +136 -0
  90. package/dist/parity/snapshot.d.ts +43 -0
  91. package/dist/parity/snapshot.js +71 -0
  92. package/dist/real-data/index.d.ts +2 -0
  93. package/dist/real-data/index.js +12 -0
  94. package/dist/real-data/real-data.d.ts +76 -0
  95. package/dist/real-data/real-data.js +156 -0
  96. package/fixtures/kg-golden/README.md +136 -0
  97. package/fixtures/kg-golden/ask-questions.json +458 -0
  98. package/fixtures/kg-golden/meetings/m01-northwind-pilot-kickoff.json +792 -0
  99. package/fixtures/kg-golden/meetings/m02-halden-migration-planning.json +814 -0
  100. package/fixtures/kg-golden/meetings/m03-larkspur-weekly-sync.json +601 -0
  101. package/fixtures/kg-golden/meetings/m04-corvid-intake-discovery.json +690 -0
  102. package/fixtures/kg-golden/meetings/m05-hosting-vendor-selection.json +631 -0
  103. package/fixtures/kg-golden/meetings/m06-northwind-floor-data-review.json +649 -0
  104. package/fixtures/kg-golden/meetings/m07-gullwing-intro-notes.json +428 -0
  105. package/fixtures/kg-golden/meetings/m08-halden-migration-checkpoint.json +672 -0
  106. package/fixtures/kg-golden/meetings/m09-northwind-platform-org-update.json +711 -0
  107. package/fixtures/kg-golden/meetings/m10-corvid-prototype-review.json +623 -0
  108. package/fixtures/kg-golden/meetings/m11-solvane-grid-dashboard-scoping.json +689 -0
  109. package/fixtures/kg-golden/meetings/m12-northwind-pilot-replan.json +681 -0
  110. package/fixtures/kg-golden/meetings/m13-halden-cutover-go-no-go.json +721 -0
  111. package/fixtures/kg-golden/meetings/m14-gullwing-discovery-readout.json +719 -0
  112. package/fixtures/kg-golden/meetings/m15-halden-handover-ravi-leaving.json +716 -0
  113. package/fixtures/kg-golden/meetings/m16-varden-claims-portal-intro.json +704 -0
  114. package/fixtures/kg-golden/meetings/m17-corvid-usability-debrief.json +572 -0
  115. package/fixtures/kg-golden/meetings/m18-hosting-decision-revisited.json +655 -0
  116. package/fixtures/kg-golden/meetings/m19-solvane-integration-kickoff.json +726 -0
  117. package/fixtures/kg-golden/meetings/m20-northwind-go-live-retro.json +673 -0
  118. package/fixtures/kg-golden/meetings/m21-quarterly-account-review.json +449 -0
  119. package/fixtures/kg-golden/meetings/m22-halden-intro-call-2020.json +558 -0
  120. package/fixtures/kg-golden/meetings/m23-gullwing-model-review.json +702 -0
  121. package/fixtures/kg-golden/meetings/m24-varden-discovery-midpoint.json +643 -0
  122. package/fixtures/kg-golden/meetings/m25-corvid-rollout-planning.json +642 -0
  123. package/fixtures/kg-golden/meetings/m26-larkspur-engineering-prep.json +695 -0
  124. package/fixtures/kg-golden/meetings/m27-solvane-phase-one-demo.json +649 -0
  125. package/fixtures/kg-golden/meetings/m28-northwind-building-5-scoping.json +715 -0
  126. package/fixtures/kg-golden/meetings/m29-halden-southern-cutover-review.json +752 -0
  127. package/fixtures/kg-golden/meetings/m30-varden-portal-build-kickoff.json +697 -0
  128. package/fixtures/kg-golden/meetings/m31-gullwing-rollout-renewal.json +681 -0
  129. package/fixtures/kg-golden/meetings/m32-brambleway-weekly-sync.json +472 -0
  130. package/fixtures/kg-golden/meetings/m33-nina-oliver-one-on-one.json +342 -0
  131. package/fixtures/kg-golden/meetings/m34-coffee-with-dana.json +249 -0
  132. package/fixtures/kg-golden/meetings/m35-brambleway-june-sync.json +553 -0
  133. package/fixtures/kg-golden/meetings/m36-copenhagen-conference-planning.json +296 -0
  134. package/host/generated/client.d.ts +1 -0
  135. package/host/generated/client.js +5 -0
  136. package/host/generated/default.d.ts +1 -0
  137. package/host/generated/default.js +5 -0
  138. package/host/generated/edge.d.ts +1 -0
  139. package/host/generated/edge.js +1658 -0
  140. package/host/generated/index-browser.js +1684 -0
  141. package/host/generated/index.d.ts +192335 -0
  142. package/host/generated/index.js +1658 -0
  143. package/host/generated/package.json +139 -0
  144. package/host/generated/query_compiler_fast_bg.js +2 -0
  145. package/host/generated/query_compiler_fast_bg.wasm +0 -0
  146. package/host/generated/query_compiler_fast_bg.wasm-base64.js +2 -0
  147. package/host/generated/runtime/client.d.ts +3433 -0
  148. package/host/generated/runtime/client.js +110 -0
  149. package/host/generated/runtime/index-browser.d.ts +90 -0
  150. package/host/generated/runtime/index-browser.js +6 -0
  151. package/host/generated/runtime/wasm-compiler-edge.js +100 -0
  152. package/host/generated/schema.prisma +6312 -0
  153. package/host/generated/wasm-edge-light-loader.mjs +5 -0
  154. package/host/generated/wasm-worker-loader.mjs +5 -0
  155. package/host/prisma/fragments/kvox.ask.prisma +126 -0
  156. package/host/prisma/fragments/kvox.graph.prisma +1073 -0
  157. package/host/prisma/fragments/kvox.notes.prisma +787 -0
  158. package/host/prisma/fragments/kvox.search.prisma +211 -0
  159. package/host/prisma/fragments/kvox.transcripts.prisma +790 -0
  160. package/host/prisma/kvox.lock +101 -0
  161. package/host/prisma/migrations/20240101000000_initial/migration.sql +297 -0
  162. package/host/prisma/migrations/20240101000001_add_personal_access_tokens/migration.sql +31 -0
  163. package/host/prisma/migrations/20240101000002_add_credentials/migration.sql +20 -0
  164. package/host/prisma/migrations/20240101000003_add_notification_deliveries/migration.sql +27 -0
  165. package/host/prisma/migrations/20240101000004_drop_stale_uuid_defaults/migration.sql +35 -0
  166. package/host/prisma/migrations/20240101000005_add_notifications/migration.sql +22 -0
  167. package/host/prisma/migrations/20240101000006_add_push_subscriptions/migration.sql +25 -0
  168. package/host/prisma/migrations/20240101000007_add_jobs/migration.sql +110 -0
  169. package/host/prisma/migrations/20240101000008_add_worker_nodes/migration.sql +90 -0
  170. package/host/prisma/migrations/20240101000009_add_database_backup_runs/migration.sql +104 -0
  171. package/host/prisma/migrations/20240101000010_add_notification_broadcasts/migration.sql +57 -0
  172. package/host/prisma/migrations/20240101000011_add_backup_run_job_link/migration.sql +87 -0
  173. package/host/prisma/migrations/20240101000012_add_job_node_secrets/migration.sql +61 -0
  174. package/host/prisma/migrations/20240101000013_add_backup_run_pg_dump_version/migration.sql +26 -0
  175. package/host/prisma/migrations/20240101000014_add_job_claim_token/migration.sql +92 -0
  176. package/host/prisma/migrations/20240101000015_add_ai_platform/migration.sql +108 -0
  177. package/host/prisma/migrations/20240101000016_revoke_viewer_ai_use/migration.sql +32 -0
  178. package/host/prisma/migrations/20240101000017_add_user_credentials/migration.sql +29 -0
  179. package/host/prisma/migrations/20240101000018_add_device_session_credential_link/migration.sql +52 -0
  180. package/host/prisma/migrations/20240101000019_add_worker_node_vitals/migration.sql +3 -0
  181. package/host/prisma/migrations/20240101000020_add_job_trace_context/migration.sql +6 -0
  182. package/host/prisma/migrations/20240101000021_add_retention_created_at_indexes/migration.sql +13 -0
  183. package/host/prisma/migrations/20240101000022_add_organizations/migration.sql +142 -0
  184. package/host/prisma/migrations/20240101000023_split_system_org_roles/migration.sql +131 -0
  185. package/host/prisma/migrations/20240101000024_org_scoped_rls/migration.sql +215 -0
  186. package/host/prisma/migrations/20240101000025_add_groups/migration.sql +165 -0
  187. package/host/prisma/migrations/20240101000026_add_grants/migration.sql +117 -0
  188. package/host/prisma/migrations/20240101000027_add_org_settings/migration.sql +49 -0
  189. package/host/prisma/migrations/20240101000028_add_org_credentials/migration.sql +54 -0
  190. package/host/prisma/migrations/20240101000029_add_jobs_org_id/migration.sql +18 -0
  191. package/host/prisma/migrations/20240101000030_add_jobs_org_id_status_index/migration.sql +6 -0
  192. package/host/prisma/migrations/20240101000031_add_broadcast_target_org/migration.sql +21 -0
  193. package/host/prisma/migrations/20240101000032_add_android_app/migration.sql +60 -0
  194. package/host/prisma/migrations/20240101000033_open_job_reason/migration.sql +16 -0
  195. package/host/prisma/migrations/20240101000034_ai_usage_feature/migration.sql +37 -0
  196. package/host/prisma/migrations/20240101000035_add_app_metadata/migration.sql +49 -0
  197. package/host/prisma/migrations/20240101000036_open_sharing_vocabularies/migration.sql +97 -0
  198. package/host/prisma/migrations/20260914130000_kvox_add_transcripts/migration.sql +322 -0
  199. package/host/prisma/migrations/20260914140000_kvox_add_notes/migration.sql +311 -0
  200. package/host/prisma/migrations/20260915120000_kvox_add_search_vectors/migration.sql +150 -0
  201. package/host/prisma/migrations/20260915130000_kvox_add_search_embeddings/migration.sql +362 -0
  202. package/host/prisma/migrations/20260915210000_kvox_add_note_title_source/migration.sql +30 -0
  203. package/host/prisma/migrations/20260923120000_kvox_add_note_generation_context_snapshot/migration.sql +24 -0
  204. package/host/prisma/migrations/20260923130000_kvox_add_user_hidden_note_templates/migration.sql +35 -0
  205. package/host/prisma/migrations/20260923140000_kvox_add_transcript_speaker_identities/migration.sql +6 -0
  206. package/host/prisma/migrations/20260923150000_kvox_transcript_name_checks/migration.sql +95 -0
  207. package/host/prisma/migrations/20260923160000_kvox_add_note_body_format/migration.sql +27 -0
  208. package/host/prisma/migrations/20260923170000_kvox_add_note_version_body_format/migration.sql +23 -0
  209. package/host/prisma/migrations/20260926012548_kvox_add_knowledge_graph/migration.sql +680 -0
  210. package/host/prisma/migrations/20260926030000_kvox_fix_kg_relations_valid_precision_chk/migration.sql +29 -0
  211. package/host/prisma/migrations/20260926030100_kvox_add_transcript_recorded_at/migration.sql +9 -0
  212. package/host/prisma/migrations/20260926030200_kvox_kg_evidence_invariant/migration.sql +60 -0
  213. package/host/prisma/migrations/20260926040000_kvox_add_kg_graph_layouts/migration.sql +30 -0
  214. package/host/prisma/migrations/20260926050000_kvox_add_ask_conversations/migration.sql +99 -0
  215. package/host/prisma/migrations/20260926231512_kvox_add_kg_exports/migration.sql +52 -0
  216. package/host/prisma/migrations/20261016120000_kvox_transcripts_org_id/migration.sql +49 -0
  217. package/host/prisma/platform.lock +319 -0
  218. package/host/prisma/schema/app.kvox.ask.prisma +110 -0
  219. package/host/prisma/schema/app.kvox.graph.prisma +1030 -0
  220. package/host/prisma/schema/app.kvox.notes.prisma +746 -0
  221. package/host/prisma/schema/app.kvox.search.prisma +208 -0
  222. package/host/prisma/schema/app.kvox.transcripts.prisma +726 -0
  223. package/host/prisma/schema/platform.ai.prisma +419 -0
  224. package/host/prisma/schema/platform.android-app.prisma +46 -0
  225. package/host/prisma/schema/platform.base.prisma +15 -0
  226. package/host/prisma/schema/platform.credentials.prisma +156 -0
  227. package/host/prisma/schema/platform.db-backup.prisma +359 -0
  228. package/host/prisma/schema/platform.identity.prisma +638 -0
  229. package/host/prisma/schema/platform.jobs.prisma +824 -0
  230. package/host/prisma/schema/platform.notifications.prisma +641 -0
  231. package/host/prisma/schema/platform.settings.prisma +53 -0
  232. package/host/prisma/schema/platform.sharing.prisma +208 -0
  233. package/host/prisma/schema/platform.storage.prisma +118 -0
  234. package/package.json +112 -1
  235. package/parity/requests.ask.json +2681 -0
  236. package/parity/requests.m01.json +1554 -0
  237. package/parity/requests.m02.json +1554 -0
  238. package/parity/requests.m03.json +1554 -0
  239. package/parity/requests.m04.json +1554 -0
  240. package/parity/requests.m05.json +1554 -0
  241. package/parity/requests.m06.json +1554 -0
  242. package/parity/requests.m07.json +1554 -0
  243. package/parity/requests.m08.json +1554 -0
  244. package/parity/requests.m09.json +1554 -0
  245. package/parity/requests.m10.json +1554 -0
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeParitySnapshot = exports.paritySnapshotPath = exports.loadParitySnapshot = exports.PARITY_SNAPSHOT_DIR = exports.PARITY_ASK_SNAPSHOT = exports.goldExtractionAnswer = exports.createParityScript = exports.runParityScenario = exports.PARITY_QUESTIONS = exports.PARITY_FIXTURES = exports.parityTaskModelSource = exports.parityModelState = exports.PARITY_USER_ID = exports.PARITY_TASK_MODELS = exports.PARITY_PROVIDER = exports.PARITY_MODELS = exports.PARITY_DEFAULT_MODEL = exports.PARITY_DEFAULT_EFFORT = void 0;
4
+ /**
5
+ * `@marinoscar/kvox-eval/parity`: the harness-parity scenario.
6
+ *
7
+ * @remarks
8
+ * For the same input, two bindings of the model port (the web edition's, KVox
9
+ * Desktop's) must build byte-identical provider requests: system prompt, user
10
+ * prompt or input, JSON Schema, tool definitions, model, reasoning effort and output
11
+ * ceiling. `runParityScenario` drives the product's own notes, extraction,
12
+ * adjudication and Ask code through a port; the committed snapshots
13
+ * (`parity/requests.*.json`) are what each binding's recording must equal.
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+ var constants_js_1 = require("./constants.js");
18
+ Object.defineProperty(exports, "PARITY_DEFAULT_EFFORT", { enumerable: true, get: function () { return constants_js_1.PARITY_DEFAULT_EFFORT; } });
19
+ Object.defineProperty(exports, "PARITY_DEFAULT_MODEL", { enumerable: true, get: function () { return constants_js_1.PARITY_DEFAULT_MODEL; } });
20
+ Object.defineProperty(exports, "PARITY_MODELS", { enumerable: true, get: function () { return constants_js_1.PARITY_MODELS; } });
21
+ Object.defineProperty(exports, "PARITY_PROVIDER", { enumerable: true, get: function () { return constants_js_1.PARITY_PROVIDER; } });
22
+ Object.defineProperty(exports, "PARITY_TASK_MODELS", { enumerable: true, get: function () { return constants_js_1.PARITY_TASK_MODELS; } });
23
+ Object.defineProperty(exports, "PARITY_USER_ID", { enumerable: true, get: function () { return constants_js_1.PARITY_USER_ID; } });
24
+ Object.defineProperty(exports, "parityModelState", { enumerable: true, get: function () { return constants_js_1.parityModelState; } });
25
+ Object.defineProperty(exports, "parityTaskModelSource", { enumerable: true, get: function () { return constants_js_1.parityTaskModelSource; } });
26
+ var scenario_js_1 = require("./scenario.js");
27
+ Object.defineProperty(exports, "PARITY_FIXTURES", { enumerable: true, get: function () { return scenario_js_1.PARITY_FIXTURES; } });
28
+ Object.defineProperty(exports, "PARITY_QUESTIONS", { enumerable: true, get: function () { return scenario_js_1.PARITY_QUESTIONS; } });
29
+ Object.defineProperty(exports, "runParityScenario", { enumerable: true, get: function () { return scenario_js_1.runParityScenario; } });
30
+ var script_js_1 = require("./script.js");
31
+ Object.defineProperty(exports, "createParityScript", { enumerable: true, get: function () { return script_js_1.createParityScript; } });
32
+ Object.defineProperty(exports, "goldExtractionAnswer", { enumerable: true, get: function () { return script_js_1.goldExtractionAnswer; } });
33
+ var snapshot_js_1 = require("./snapshot.js");
34
+ Object.defineProperty(exports, "PARITY_ASK_SNAPSHOT", { enumerable: true, get: function () { return snapshot_js_1.PARITY_ASK_SNAPSHOT; } });
35
+ Object.defineProperty(exports, "PARITY_SNAPSHOT_DIR", { enumerable: true, get: function () { return snapshot_js_1.PARITY_SNAPSHOT_DIR; } });
36
+ Object.defineProperty(exports, "loadParitySnapshot", { enumerable: true, get: function () { return snapshot_js_1.loadParitySnapshot; } });
37
+ Object.defineProperty(exports, "paritySnapshotPath", { enumerable: true, get: function () { return snapshot_js_1.paritySnapshotPath; } });
38
+ Object.defineProperty(exports, "writeParitySnapshot", { enumerable: true, get: function () { return snapshot_js_1.writeParitySnapshot; } });
@@ -0,0 +1,8 @@
1
+ import { internals as extractionInternals } from '@marinoscar/kvox-api/graph-extraction/testing';
2
+ import { internals as askInternals } from '@marinoscar/kvox-api/ask/testing';
3
+ export declare const buildExtractionContext: typeof extractionInternals.buildExtractionContext;
4
+ export type ExtractionContext = extractionInternals.ExtractionContext;
5
+ export declare const AskRespondHandler: typeof askInternals.AskRespondHandler, AskToolset: typeof askInternals.AskToolset, EntityBriefTool: typeof askInternals.EntityBriefTool, EvidenceTool: typeof askInternals.EvidenceTool, GetEntityTool: typeof askInternals.GetEntityTool, ListCommitmentsTool: typeof askInternals.ListCommitmentsTool, NeighborsTool: typeof askInternals.NeighborsTool, SearchTool: typeof askInternals.SearchTool, TimelineTool: typeof askInternals.TimelineTool;
6
+ export type AskToolContext = askInternals.AskToolContext;
7
+ export type HandleRegistry = InstanceType<typeof askInternals.HandleRegistry>;
8
+ export declare const HandleRegistryClass: typeof askInternals.HandleRegistry;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ // =============================================================================
3
+ // The slices' internals the parity scenario runs (issue #580)
4
+ // =============================================================================
5
+ //
6
+ // Same rule as `kg/internals.ts`: the one place this slice names a function that
7
+ // `@marinoscar/kvox-api` keeps internal (tagged `@internal`, no stability
8
+ // promise). NOT EXPORTED from the package.
9
+ // =============================================================================
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.HandleRegistryClass = exports.TimelineTool = exports.SearchTool = exports.NeighborsTool = exports.ListCommitmentsTool = exports.GetEntityTool = exports.EvidenceTool = exports.EntityBriefTool = exports.AskToolset = exports.AskRespondHandler = exports.buildExtractionContext = void 0;
12
+ const testing_1 = require("@marinoscar/kvox-api/graph-extraction/testing");
13
+ const testing_2 = require("@marinoscar/kvox-api/ask/testing");
14
+ exports.buildExtractionContext = testing_1.internals.buildExtractionContext;
15
+ exports.AskRespondHandler = testing_2.internals.AskRespondHandler, exports.AskToolset = testing_2.internals.AskToolset, exports.EntityBriefTool = testing_2.internals.EntityBriefTool, exports.EvidenceTool = testing_2.internals.EvidenceTool, exports.GetEntityTool = testing_2.internals.GetEntityTool, exports.ListCommitmentsTool = testing_2.internals.ListCommitmentsTool, exports.NeighborsTool = testing_2.internals.NeighborsTool, exports.SearchTool = testing_2.internals.SearchTool, exports.TimelineTool = testing_2.internals.TimelineTool;
16
+ exports.HandleRegistryClass = testing_2.internals.HandleRegistry;
@@ -0,0 +1,45 @@
1
+ import type { KvoxAiPort } from '@marinoscar/kvox-api/ports';
2
+ import type { ParityScript } from './script.js';
3
+ /**
4
+ * The golden meetings the scenario covers by default.
5
+ *
6
+ * @stability experimental
7
+ */
8
+ export declare const PARITY_FIXTURES: readonly string[];
9
+ /**
10
+ * The Ask questions (ids in `ask-questions.json`) the scenario asks by default.
11
+ *
12
+ * @stability experimental
13
+ */
14
+ export declare const PARITY_QUESTIONS: readonly string[];
15
+ /**
16
+ * What {@link runParityScenario} covers.
17
+ *
18
+ * @stability experimental
19
+ */
20
+ export interface ParityScenarioOptions {
21
+ /** Golden meeting ids to run notes, extraction and adjudication for. Default {@link PARITY_FIXTURES}; `[]` runs none. */
22
+ fixtures?: string[];
23
+ /** Ask question ids to ask. Default {@link PARITY_QUESTIONS}; `[]` asks none. */
24
+ questions?: string[];
25
+ /** The scripted provider to tell which meeting is current (it answers extraction from that meeting's labels). */
26
+ script?: Pick<ParityScript, 'focus'>;
27
+ }
28
+ /**
29
+ * Drives the product's own harness through `ai`: the calls notes generation, entity
30
+ * extraction, adjudication and the Ask loop make, for the golden meetings and Ask
31
+ * questions chosen. Call it once per binding with the SAME scripted provider under
32
+ * the binding, record what reaches the provider, and compare.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const script = createParityScript();
37
+ * await runParityScenario(ai, { fixtures: ['m01'], questions: [], script });
38
+ * ```
39
+ *
40
+ * @param ai - the port under test (`createKvoxAi`, or a host's wrapper of it).
41
+ * @param opts - which meetings and questions.
42
+ * @throws when a stage cannot complete (a scripted answer failed validation): the scenario must run end to end, or a request could be missing from the comparison.
43
+ * @stability experimental
44
+ */
45
+ export declare function runParityScenario(ai: KvoxAiPort, opts?: ParityScenarioOptions): Promise<void>;
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PARITY_QUESTIONS = exports.PARITY_FIXTURES = void 0;
4
+ exports.runParityScenario = runParityScenario;
5
+ const ontology_1 = require("@marinoscar/kvox-contract/ontology");
6
+ const core_1 = require("@marinoscar/kvox-api/core");
7
+ const graph_1 = require("@marinoscar/kvox-api/graph");
8
+ const graph_extraction_1 = require("@marinoscar/kvox-api/graph-extraction");
9
+ const ask_1 = require("@marinoscar/kvox-api/ask");
10
+ const testing_1 = require("@marinoscar/kvox-api/ask/testing");
11
+ const templates_1 = require("@marinoscar/kvox-api/notes/templates");
12
+ const notes_1 = require("@marinoscar/kvox-api/notes");
13
+ const index_js_1 = require("../fixtures/index.js");
14
+ const index_js_2 = require("../kg/index.js");
15
+ const constants_js_1 = require("./constants.js");
16
+ const internals_js_1 = require("./internals.js");
17
+ // =============================================================================
18
+ // The parity scenario: the real harness, driven through the model port (issue #580, part 2)
19
+ // =============================================================================
20
+ //
21
+ // `runParityScenario(ai)` makes, through whatever `KvoxAiPort` it is handed, the
22
+ // calls the product makes for ten golden meetings and three Ask questions:
23
+ //
24
+ // notes.generate the notes slice's own prompt builder (`assemblePrompt`) over a
25
+ // built-in template and the meeting's transcript, sized with the
26
+ // slice's own budget (`budgetFromTarget`), then `generateText`.
27
+ // graph.extract the evaluation's own extraction call (`runExtraction`: the
28
+ // graph-extraction slice's prompt, output schema and validator).
29
+ // graph.adjudicate the graph-extraction slice's own `AdjudicationService`, over
30
+ // pairs built from the extracted entities and the known ones.
31
+ // ask.respond the Ask slice's own `AskRespondHandler`, with its real toolset
32
+ // definitions, over the in-memory Ask tables and a stub tool run.
33
+ //
34
+ // Nothing here copies a prompt, a schema or a parser (ADR-0001): every one of them is
35
+ // the package's. What differs between hosts is only the port, and that is the point.
36
+ // =============================================================================
37
+ /**
38
+ * The golden meetings the scenario covers by default.
39
+ *
40
+ * @stability experimental
41
+ */
42
+ exports.PARITY_FIXTURES = Object.freeze(['m01', 'm02', 'm03', 'm04', 'm05', 'm06', 'm07', 'm08', 'm09', 'm10']);
43
+ /**
44
+ * The Ask questions (ids in `ask-questions.json`) the scenario asks by default.
45
+ *
46
+ * @stability experimental
47
+ */
48
+ exports.PARITY_QUESTIONS = Object.freeze(['q01', 'q02', 'q03']);
49
+ /** The text of a transcript as a note source: one line per merged speaker turn, with its start time. */
50
+ function transcriptText(fixture) {
51
+ const speakerName = new Map(fixture.speakers.map((s) => [s.id, s.displayName ?? s.label]));
52
+ const lines = [];
53
+ let last = null;
54
+ for (const segment of fixture.segments) {
55
+ const seconds = Math.floor(segment.startMs / 1000);
56
+ const stamp = `${String(Math.floor(seconds / 60)).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`;
57
+ if (segment.speakerId === last && lines.length > 0) {
58
+ lines[lines.length - 1] += ` ${segment.text}`;
59
+ }
60
+ else {
61
+ lines.push(`[${stamp}] ${speakerName.get(segment.speakerId) ?? 'Unknown speaker'}: ${segment.text}`);
62
+ last = segment.speakerId;
63
+ }
64
+ }
65
+ return lines.join('\n');
66
+ }
67
+ /** `notes.generate`: assemble, size, stream. */
68
+ async function runNotes(ai, fixture) {
69
+ const ctx = { userId: constants_js_1.PARITY_USER_ID, orgId: null, feature: notes_1.NOTE_GENERATE_AI_FEATURE };
70
+ const target = await ai.resolveTask(ctx, notes_1.NOTE_GENERATE_AI_FEATURE);
71
+ const template = templates_1.NOTE_BUILTIN_TEMPLATES[0];
72
+ const prompt = (0, notes_1.assemblePrompt)({
73
+ templateInstructions: template.instructions,
74
+ templateOutputFormat: template.outputFormat,
75
+ templateBodyFormat: template.bodyFormat,
76
+ templateStructure: [...template.structure],
77
+ templateTone: template.tone,
78
+ templateLength: template.length,
79
+ contextText: fixture.contextText,
80
+ sourceText: transcriptText(fixture),
81
+ });
82
+ const budget = (0, notes_1.budgetFromTarget)(target, { maxInputTokens: null, maxOutputTokens: null });
83
+ if (budget === null)
84
+ throw new Error('The parity model reports no context window.');
85
+ const promptTokens = ai.countTokens(target, `${prompt.systemPrompt}\n${prompt.userContent}`);
86
+ let text = '';
87
+ for await (const event of ai.generateText(ctx, {
88
+ target,
89
+ system: prompt.systemPrompt,
90
+ user: prompt.userContent,
91
+ maxOutputTokens: (0, core_1.outputTokensForPrompt)(budget, promptTokens),
92
+ })) {
93
+ if (event.type === 'delta')
94
+ text += event.text;
95
+ }
96
+ if (text.length === 0)
97
+ throw new Error(`The scripted note for ${fixture.id} came back empty.`);
98
+ }
99
+ /** `graph.extract`: the evaluation's extraction call, on the model the task resolves to. */
100
+ async function runExtract(ai, fixture) {
101
+ const target = await ai.resolveTask({ userId: constants_js_1.PARITY_USER_ID, orgId: null, feature: 'graph.extract' }, 'graph.extract');
102
+ const extracted = await (0, index_js_2.runExtraction)(ai, fixture, { model: target.model, provider: target.provider });
103
+ if (extracted === null)
104
+ throw new Error(`The scripted extraction for ${fixture.id} failed validation.`);
105
+ return extracted;
106
+ }
107
+ /** `graph.adjudicate`: the real service, over pairs of one extracted mention and one known entity of its type. */
108
+ async function runAdjudicate(ai, fixture, rows) {
109
+ const known = fixture.knownEntities;
110
+ const pairs = [];
111
+ for (const row of rows) {
112
+ if (row.kind !== 'entity' || row.payload.ref === 'meeting')
113
+ continue;
114
+ const candidate = known.find((k) => k.type === row.payload.type && k.label !== row.payload.label);
115
+ if (candidate === undefined)
116
+ continue;
117
+ pairs.push({
118
+ pairId: `p${pairs.length + 1}`,
119
+ type: row.payload.type,
120
+ mention: {
121
+ label: row.payload.label,
122
+ aliases: row.payload.aliases,
123
+ props: {},
124
+ quotes: row.evidence.map((e) => e.quote),
125
+ },
126
+ candidate: {
127
+ entityId: candidate.id,
128
+ label: candidate.label,
129
+ aliases: candidate.aliases,
130
+ props: candidate.props,
131
+ quotes: [],
132
+ neighbourhood: fixture.knownRelations
133
+ .filter((r) => r.from === candidate.id || r.to === candidate.id)
134
+ .map((r) => `${r.type} ${r.from === candidate.id ? '→' : '←'} ${known.find((k) => k.id === (r.from === candidate.id ? r.to : r.from))?.label ?? 'unknown'}`),
135
+ },
136
+ });
137
+ if (pairs.length === 4)
138
+ break;
139
+ }
140
+ if (pairs.length === 0)
141
+ throw new Error(`${fixture.id} has no extracted entity with a same-type known entity to adjudicate.`);
142
+ const settings = {
143
+ readSystem: async () => ({ value: { graphEnabled: true, maxInputTokens: null, maxOutputTokens: null, reasoningEffort: constants_js_1.PARITY_DEFAULT_EFFORT }, version: 1 }),
144
+ };
145
+ const ontology = { effectiveSchemaFor: async () => (0, ontology_1.computeEffectiveSchema)({ enabledDomains: (0, index_js_1.fixtureDomains)(fixture), userAttributes: [] }) };
146
+ const service = new graph_extraction_1.AdjudicationService(undefined, new graph_1.GraphAiRunResolver(ai, settings), ai, ontology);
147
+ const verdicts = await service.adjudicate(constants_js_1.PARITY_USER_ID, pairs, { jobType: 'kg.resolve', jobId: 'parity-job' });
148
+ if (verdicts.size !== pairs.length)
149
+ throw new Error(`Expected ${pairs.length} adjudication verdicts, got ${verdicts.size}.`);
150
+ }
151
+ /** A dependency the tool never reaches: only a tool's definition is read, never its `run`. */
152
+ const NONE = undefined;
153
+ /** The real tool definitions, with a tool run that finds one entity. */
154
+ function parityToolset() {
155
+ const real = new internals_js_1.AskToolset(new internals_js_1.SearchTool(NONE, NONE, NONE, NONE), new internals_js_1.GetEntityTool(NONE, NONE, NONE), new internals_js_1.NeighborsTool(NONE, NONE), new internals_js_1.TimelineTool(NONE, NONE), new internals_js_1.EvidenceTool(NONE, NONE), new internals_js_1.EntityBriefTool(NONE, NONE), new internals_js_1.ListCommitmentsTool(NONE), NONE);
156
+ return {
157
+ definitions: () => real.definitions(),
158
+ createContext: async (user, opts = {}) => ({
159
+ user,
160
+ handles: new internals_js_1.HandleRegistryClass(),
161
+ personalFactsAllowed: false,
162
+ scopeEntityId: opts.scopeEntityId ?? null,
163
+ now: opts.now ?? new Date(0),
164
+ }),
165
+ execute: async (ctx) => {
166
+ ctx.handles.register({ kind: 'ent', id: '55555555-5555-4555-8555-555555555555', label: 'Parity Entity' });
167
+ return {
168
+ ok: true,
169
+ result: { data: { entities: [] }, resultCount: 1, summary: 'Found 1 thing', truncated: false },
170
+ json: '{"entities":[{"ref":"ent1","label":"Parity Entity"}],"truncated":false}',
171
+ };
172
+ },
173
+ };
174
+ }
175
+ /** `ask.respond`: the real handler over the in-memory tables, for one question. */
176
+ async function runAsk(ai, question) {
177
+ const mem = (0, testing_1.createInMemoryAskDb)();
178
+ const conversation = mem.addConversation({ ownerId: constants_js_1.PARITY_USER_ID });
179
+ mem.addMessage({ conversationId: conversation.id, role: 'user', content: question });
180
+ const assistant = mem.addMessage({ conversationId: conversation.id, role: 'assistant' });
181
+ const settings = {
182
+ readSystem: async () => ({ value: { graphEnabled: true, maxInputTokens: null, maxOutputTokens: null, reasoningEffort: constants_js_1.PARITY_DEFAULT_EFFORT }, version: 1 }),
183
+ };
184
+ const visibility = {
185
+ viewerFor: async (userId) => ({ userId }),
186
+ transcriptVisibleSql: () => core_1.Prisma.sql `true`,
187
+ run: (_viewer, fn) => fn(mem.db),
188
+ };
189
+ const handler = new internals_js_1.AskRespondHandler({ registerHandler: () => undefined }, mem.db, ai, { hasPermission: async () => true, authenticate: async () => null }, new graph_1.GraphAiRunResolver(ai, settings), parityToolset(), visibility, (0, ask_1.resolveAskOptions)());
190
+ // The system prompt carries today's date: a fixed clock keeps the request reproducible.
191
+ handler.clock = () => Date.UTC(2026, 8, 26, 12, 0, 0);
192
+ const payload = {
193
+ assistantMessageId: assistant.id,
194
+ conversationId: conversation.id,
195
+ userId: constants_js_1.PARITY_USER_ID,
196
+ model: 'gpt-parity-agent',
197
+ providerId: 'openai',
198
+ reasoningEffort: 'low',
199
+ };
200
+ const job = { id: 'parity-job', type: ask_1.ASK_RESPOND_JOB_TYPE, subjectType: 'ask_message', subjectId: assistant.id, payload, attempts: 0, orgId: null };
201
+ await handler.process(job);
202
+ const row = mem.messages.get(assistant.id);
203
+ if (row?.status !== 'complete')
204
+ throw new Error(`The Ask turn ended ${row?.status ?? 'missing'}: ${row?.errorClass ?? ''}`);
205
+ if (!Array.isArray(row.toolCalls) || row.toolCalls.length === 0)
206
+ throw new Error('The Ask turn called no tool.');
207
+ }
208
+ /**
209
+ * Drives the product's own harness through `ai`: the calls notes generation, entity
210
+ * extraction, adjudication and the Ask loop make, for the golden meetings and Ask
211
+ * questions chosen. Call it once per binding with the SAME scripted provider under
212
+ * the binding, record what reaches the provider, and compare.
213
+ *
214
+ * @example
215
+ * ```ts
216
+ * const script = createParityScript();
217
+ * await runParityScenario(ai, { fixtures: ['m01'], questions: [], script });
218
+ * ```
219
+ *
220
+ * @param ai - the port under test (`createKvoxAi`, or a host's wrapper of it).
221
+ * @param opts - which meetings and questions.
222
+ * @throws when a stage cannot complete (a scripted answer failed validation): the scenario must run end to end, or a request could be missing from the comparison.
223
+ * @stability experimental
224
+ */
225
+ async function runParityScenario(ai, opts = {}) {
226
+ const ids = opts.fixtures ?? [...exports.PARITY_FIXTURES];
227
+ const meetings = ids.length > 0 ? (0, index_js_1.loadGoldenMeetings)(ids) : [];
228
+ for (const fixture of meetings) {
229
+ opts.script?.focus(fixture.id);
230
+ await runNotes(ai, fixture);
231
+ const extracted = await runExtract(ai, fixture);
232
+ await runAdjudicate(ai, fixture, extracted.rows);
233
+ }
234
+ opts.script?.focus(null);
235
+ const wanted = opts.questions ?? [...exports.PARITY_QUESTIONS];
236
+ if (wanted.length > 0) {
237
+ const questions = (0, index_js_1.loadGoldenAskQuestions)();
238
+ for (const id of wanted) {
239
+ const question = questions.find((q) => q.id === id);
240
+ if (question === undefined)
241
+ throw new Error(`Unknown Ask question id ${id}.`);
242
+ await runAsk(ai, question.question);
243
+ }
244
+ }
245
+ }
@@ -0,0 +1,44 @@
1
+ import { type RecordingScript } from '@marinoscar/kvox-ai/testing';
2
+ import { type GoldenFixture } from '../fixtures/index.js';
3
+ import { type ExtractionContext } from './internals.js';
4
+ /**
5
+ * The scripted provider: a `RecordingScript` (of `@marinoscar/kvox-ai/testing`) that also needs to know which golden meeting the scenario is on.
6
+ *
7
+ * @stability experimental
8
+ */
9
+ export interface ParityScript extends Required<Pick<RecordingScript, 'stream' | 'create'>> {
10
+ /** The call id of the Ask tool call the script makes. */
11
+ readonly toolCallId: string;
12
+ /**
13
+ * Tells the script which meeting the scenario is on; its extraction answer is that meeting's gold labels.
14
+ *
15
+ * @param fixtureId - a golden meeting id, or `null` between meetings (the Ask questions).
16
+ */
17
+ focus(fixtureId: string | null): void;
18
+ }
19
+ /**
20
+ * The raw extraction answer a model that read the meeting perfectly would give: the
21
+ * fixture's gold entities, relations and items, with the prompt's own `s#`, `N` and
22
+ * `k#` ids. The Meeting entity and ATTENDED relations are the product's deterministic
23
+ * rows, never the model's, so they are left out.
24
+ *
25
+ * @param fixture - the golden meeting.
26
+ * @param ctx - the extraction context the prompt was built from.
27
+ * @returns the answer in the extraction output schema's shape.
28
+ * @stability experimental
29
+ */
30
+ export declare function goldExtractionAnswer(fixture: GoldenFixture, ctx: ExtractionContext): Record<string, unknown>;
31
+ /**
32
+ * Builds the scripted provider.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * const script = createParityScript();
37
+ * const adapter = createRecordingAdapter(script);
38
+ * await runParityScenario(ai, { fixtures: ['m01'], questions: [], script });
39
+ * ```
40
+ *
41
+ * @returns the script.
42
+ * @stability experimental
43
+ */
44
+ export declare function createParityScript(): ParityScript;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.goldExtractionAnswer = goldExtractionAnswer;
4
+ exports.createParityScript = createParityScript;
5
+ const testing_1 = require("@marinoscar/kvox-ai/testing");
6
+ const index_js_1 = require("../fixtures/index.js");
7
+ const internals_js_1 = require("./internals.js");
8
+ const index_js_2 = require("../kg/index.js");
9
+ /** The id of the one tool call the script makes. */
10
+ const TOOL_CALL_ID = 'call_parity_1';
11
+ /** The empty extraction answer. */
12
+ const EMPTY_ANSWER = { meeting: { topics: [] }, entities: [], relations: [], items: [] };
13
+ /**
14
+ * The raw extraction answer a model that read the meeting perfectly would give: the
15
+ * fixture's gold entities, relations and items, with the prompt's own `s#`, `N` and
16
+ * `k#` ids. The Meeting entity and ATTENDED relations are the product's deterministic
17
+ * rows, never the model's, so they are left out.
18
+ *
19
+ * @param fixture - the golden meeting.
20
+ * @param ctx - the extraction context the prompt was built from.
21
+ * @returns the answer in the extraction output schema's shape.
22
+ * @stability experimental
23
+ */
24
+ function goldExtractionAnswer(fixture, ctx) {
25
+ const aliasOfSegment = new Map(ctx.segments.map((s) => [s.segmentId, s.alias]));
26
+ const aliasOfKnown = new Map(ctx.knownEntities.map((k) => [k.id, k.alias]));
27
+ const refOf = new Map(fixture.labels.entities.map((e) => [e.key, e.existingId !== null && aliasOfKnown.has(e.existingId) ? aliasOfKnown.get(e.existingId) : e.key]));
28
+ refOf.set('meeting', 'meeting');
29
+ const end = (key) => (key === null ? null : (refOf.get(key) ?? key));
30
+ const cites = (evidence) => evidence.map((e) => ({ source: e.source === 'segment' ? (aliasOfSegment.get(e.segmentId) ?? 'N') : 'N', quote: e.quote }));
31
+ return {
32
+ meeting: { topics: [fixture.title] },
33
+ entities: fixture.labels.entities
34
+ .filter((e) => e.type !== 'Meeting')
35
+ .map((e) => ({ ref: refOf.get(e.key), type: e.type, label: e.label, aliases: [...e.aliases], props: e.props, evidence: cites(e.evidence) })),
36
+ relations: fixture.labels.relations
37
+ .filter((r) => r.type !== 'ATTENDED')
38
+ .map((r) => ({
39
+ type: r.type,
40
+ from: end(r.from),
41
+ to: end(r.to),
42
+ props: r.props,
43
+ validFrom: r.validFrom,
44
+ validTo: r.validTo,
45
+ precision: r.precision,
46
+ evidence: cites(r.evidence),
47
+ })),
48
+ items: fixture.labels.items.map((i) => ({
49
+ kind: i.kind,
50
+ title: i.title,
51
+ statement: i.statement,
52
+ subject: end(i.subject),
53
+ owner: end(i.owner),
54
+ counterparty: end(i.counterparty),
55
+ status: i.status,
56
+ occurredAt: i.occurredAt,
57
+ dueAt: i.dueAt,
58
+ validFrom: null,
59
+ validTo: null,
60
+ precision: 'unknown',
61
+ sensitivity: i.sensitivity,
62
+ props: {},
63
+ evidence: cites(i.evidence),
64
+ })),
65
+ };
66
+ }
67
+ /** The text of the last user message of an Ask request. */
68
+ function lastUserText(req) {
69
+ if (typeof req.input === 'string')
70
+ return req.input;
71
+ for (let i = req.input.length - 1; i >= 0; i -= 1) {
72
+ const item = req.input[i];
73
+ if (item.type === 'message' && item.role === 'user') {
74
+ return item.content.map((part) => ('text' in part ? String(part.text) : '')).join('');
75
+ }
76
+ }
77
+ return '';
78
+ }
79
+ /**
80
+ * Builds the scripted provider.
81
+ *
82
+ * @example
83
+ * ```ts
84
+ * const script = createParityScript();
85
+ * const adapter = createRecordingAdapter(script);
86
+ * await runParityScenario(ai, { fixtures: ['m01'], questions: [], script });
87
+ * ```
88
+ *
89
+ * @returns the script.
90
+ * @stability experimental
91
+ */
92
+ function createParityScript() {
93
+ const fixtures = new Map();
94
+ let focused = null;
95
+ const extractionAnswer = () => {
96
+ if (focused === null)
97
+ return EMPTY_ANSWER;
98
+ if (!fixtures.has(focused))
99
+ for (const f of (0, index_js_1.loadGoldenMeetings)([focused]))
100
+ fixtures.set(f.id, f);
101
+ const fixture = fixtures.get(focused);
102
+ return goldExtractionAnswer(fixture, (0, internals_js_1.buildExtractionContext)((0, index_js_2.fixtureToInput)(fixture)));
103
+ };
104
+ return {
105
+ toolCallId: TOOL_CALL_ID,
106
+ focus(fixtureId) {
107
+ focused = fixtureId;
108
+ },
109
+ create(req) {
110
+ const name = req.structuredOutput?.name;
111
+ let parsed = { ok: true };
112
+ if (name === 'kg_extraction') {
113
+ parsed = extractionAnswer();
114
+ }
115
+ else if (name === 'kg_adjudication') {
116
+ const text = typeof req.input === 'string' ? req.input : '';
117
+ const ids = [...text.matchAll(/^## Pair (p\d+)/gm)].map((m) => m[1]);
118
+ const verdicts = ['same', 'different', 'uncertain'];
119
+ parsed = { verdicts: ids.map((pairId, i) => ({ pairId, verdict: verdicts[i % verdicts.length], rationale: `Parity verdict for ${pairId}.` })) };
120
+ }
121
+ return { parsed, outputText: JSON.stringify(parsed) };
122
+ },
123
+ stream(req) {
124
+ if (req.tools === undefined || req.tools.length === 0) {
125
+ return (0, testing_1.textAnswer)(`Parity note for ${focused ?? 'no meeting'}.\n\n- Everything said was written down once.`);
126
+ }
127
+ const hasResult = typeof req.input !== 'string' && req.input.some((item) => item.type === 'function_call_output');
128
+ if (!hasResult) {
129
+ const query = lastUserText(req).slice(0, 200) || 'parity';
130
+ const item = { type: 'function_call', callId: TOOL_CALL_ID, name: 'search', arguments: JSON.stringify({ query }) };
131
+ return [(0, testing_1.functionCallEvent)(item.callId, item.name, item.arguments), (0, testing_1.completedEvent)({ output: [item], finishReason: 'tool_calls' })];
132
+ }
133
+ return (0, testing_1.textAnswer)('The graph answers this directly and the search found it.[^ent1] That is the whole of what the parity script says.');
134
+ },
135
+ };
136
+ }
@@ -0,0 +1,43 @@
1
+ import type { RecordedProviderRequest } from '@marinoscar/kvox-ai/testing';
2
+ /**
3
+ * The directory of the committed snapshots (`parity/` of the package).
4
+ *
5
+ * @stability experimental
6
+ */
7
+ export declare const PARITY_SNAPSHOT_DIR: string;
8
+ /**
9
+ * The name of the Ask snapshot, beside the fixture ids (`m01`...).
10
+ *
11
+ * @stability experimental
12
+ */
13
+ export declare const PARITY_ASK_SNAPSHOT = "ask";
14
+ /**
15
+ * The path of one snapshot file.
16
+ *
17
+ * @param name - a fixture id (`m01`) or {@link PARITY_ASK_SNAPSHOT}.
18
+ * @returns the absolute path of `requests.<name>.json`.
19
+ * @stability experimental
20
+ */
21
+ export declare function paritySnapshotPath(name: string): string;
22
+ /**
23
+ * Reads one committed snapshot: the provider-level requests a binding must build, in call order.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * expect(recorded).toEqual(loadParitySnapshot('m01'));
28
+ * ```
29
+ *
30
+ * @param name - a fixture id (`m01`) or {@link PARITY_ASK_SNAPSHOT}.
31
+ * @returns the records.
32
+ * @throws when the file is missing (run the direct spec with `KVOX_EVAL_UPDATE_PARITY=1` to write it).
33
+ * @stability experimental
34
+ */
35
+ export declare function loadParitySnapshot(name: string): RecordedProviderRequest[];
36
+ /**
37
+ * Writes one snapshot (the direct spec does, when `KVOX_EVAL_UPDATE_PARITY=1`).
38
+ *
39
+ * @param name - a fixture id (`m01`) or {@link PARITY_ASK_SNAPSHOT}.
40
+ * @param records - the provider-level records, normalized.
41
+ * @stability experimental
42
+ */
43
+ export declare function writeParitySnapshot(name: string, records: readonly RecordedProviderRequest[]): void;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PARITY_ASK_SNAPSHOT = exports.PARITY_SNAPSHOT_DIR = void 0;
4
+ exports.paritySnapshotPath = paritySnapshotPath;
5
+ exports.loadParitySnapshot = loadParitySnapshot;
6
+ exports.writeParitySnapshot = writeParitySnapshot;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ // =============================================================================
10
+ // The committed request snapshots (issue #580, part 2)
11
+ // =============================================================================
12
+ //
13
+ // `parity/requests.<fixture>.json` (one per golden meeting) and
14
+ // `parity/requests.ask.json`, at the package root, shipped in `files`. They are the
15
+ // single source of truth for "what the harness sends": the direct binding's spec
16
+ // here, the web binding's spec in `apps/api`, and the Desktop repository's own
17
+ // binding all compare against the same files.
18
+ // =============================================================================
19
+ /** `src/parity` and `dist/parity` both sit two levels below the package root. */
20
+ const PACKAGE_ROOT = (0, node_path_1.resolve)(__dirname, '..', '..');
21
+ /**
22
+ * The directory of the committed snapshots (`parity/` of the package).
23
+ *
24
+ * @stability experimental
25
+ */
26
+ exports.PARITY_SNAPSHOT_DIR = (0, node_path_1.join)(PACKAGE_ROOT, 'parity');
27
+ /**
28
+ * The name of the Ask snapshot, beside the fixture ids (`m01`...).
29
+ *
30
+ * @stability experimental
31
+ */
32
+ exports.PARITY_ASK_SNAPSHOT = 'ask';
33
+ /**
34
+ * The path of one snapshot file.
35
+ *
36
+ * @param name - a fixture id (`m01`) or {@link PARITY_ASK_SNAPSHOT}.
37
+ * @returns the absolute path of `requests.<name>.json`.
38
+ * @stability experimental
39
+ */
40
+ function paritySnapshotPath(name) {
41
+ if (!/^[a-z0-9]+$/i.test(name))
42
+ throw new Error(`Not a parity snapshot name: ${JSON.stringify(name)}`);
43
+ return (0, node_path_1.join)(exports.PARITY_SNAPSHOT_DIR, `requests.${name}.json`);
44
+ }
45
+ /**
46
+ * Reads one committed snapshot: the provider-level requests a binding must build, in call order.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * expect(recorded).toEqual(loadParitySnapshot('m01'));
51
+ * ```
52
+ *
53
+ * @param name - a fixture id (`m01`) or {@link PARITY_ASK_SNAPSHOT}.
54
+ * @returns the records.
55
+ * @throws when the file is missing (run the direct spec with `KVOX_EVAL_UPDATE_PARITY=1` to write it).
56
+ * @stability experimental
57
+ */
58
+ function loadParitySnapshot(name) {
59
+ return JSON.parse((0, node_fs_1.readFileSync)(paritySnapshotPath(name), 'utf8'));
60
+ }
61
+ /**
62
+ * Writes one snapshot (the direct spec does, when `KVOX_EVAL_UPDATE_PARITY=1`).
63
+ *
64
+ * @param name - a fixture id (`m01`) or {@link PARITY_ASK_SNAPSHOT}.
65
+ * @param records - the provider-level records, normalized.
66
+ * @stability experimental
67
+ */
68
+ function writeParitySnapshot(name, records) {
69
+ (0, node_fs_1.mkdirSync)(exports.PARITY_SNAPSHOT_DIR, { recursive: true });
70
+ (0, node_fs_1.writeFileSync)(paritySnapshotPath(name), `${JSON.stringify(records, null, 2)}\n`, 'utf8');
71
+ }
@@ -0,0 +1,2 @@
1
+ export { assertOutsideRepo, canonicalPath, isInside, nextRealFixtureId, REAL_DATA_REFUSAL, RealDataPathError, repositoryRoots, } from './real-data.js';
2
+ export type { AssertOutsideRepoOptions } from './real-data.js';