@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.
- package/CHANGELOG.md +14 -0
- package/LICENSE +21 -0
- package/README.md +166 -0
- package/dist/ask/index.d.ts +6 -0
- package/dist/ask/index.js +28 -0
- package/dist/ask/question-schema.d.ts +121 -0
- package/dist/ask/question-schema.js +167 -0
- package/dist/ask/report.d.ts +88 -0
- package/dist/ask/report.js +170 -0
- package/dist/ask/scorer.d.ts +104 -0
- package/dist/ask/scorer.js +164 -0
- package/dist/ask-run/ask-command.d.ts +62 -0
- package/dist/ask-run/ask-command.js +254 -0
- package/dist/ask-run/host/app.d.ts +65 -0
- package/dist/ask-run/host/app.js +146 -0
- package/dist/ask-run/host/db.d.ts +38 -0
- package/dist/ask-run/host/db.js +126 -0
- package/dist/ask-run/host/ports.d.ts +35 -0
- package/dist/ask-run/host/ports.js +113 -0
- package/dist/ask-run/index.d.ts +13 -0
- package/dist/ask-run/index.js +35 -0
- package/dist/ask-run/replay.d.ts +128 -0
- package/dist/ask-run/replay.js +212 -0
- package/dist/ask-run/run-ask-eval.d.ts +125 -0
- package/dist/ask-run/run-ask-eval.js +193 -0
- package/dist/ask-run/seed-golden-graph.d.ts +64 -0
- package/dist/ask-run/seed-golden-graph.js +495 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +12 -0
- package/dist/cli/kg-command.d.ts +66 -0
- package/dist/cli/kg-command.js +238 -0
- package/dist/cli/main.d.ts +18 -0
- package/dist/cli/main.js +69 -0
- package/dist/fixtures/domains.d.ts +16 -0
- package/dist/fixtures/domains.js +33 -0
- package/dist/fixtures/fixture-schema.d.ts +323 -0
- package/dist/fixtures/fixture-schema.js +199 -0
- package/dist/fixtures/index.d.ts +16 -0
- package/dist/fixtures/index.js +40 -0
- package/dist/fixtures/load.d.ts +73 -0
- package/dist/fixtures/load.js +137 -0
- package/dist/fixtures/questions.d.ts +15 -0
- package/dist/fixtures/questions.js +26 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +36 -0
- package/dist/kg/gold-runner.d.ts +13 -0
- package/dist/kg/gold-runner.js +57 -0
- package/dist/kg/index.d.ts +17 -0
- package/dist/kg/index.js +65 -0
- package/dist/kg/internals.d.ts +7 -0
- package/dist/kg/internals.js +17 -0
- package/dist/kg/prediction-schema.d.ts +245 -0
- package/dist/kg/prediction-schema.js +102 -0
- package/dist/kg/predictions.d.ts +11 -0
- package/dist/kg/predictions.js +49 -0
- package/dist/kg/report.d.ts +84 -0
- package/dist/kg/report.js +125 -0
- package/dist/kg/run-kg-eval.d.ts +77 -0
- package/dist/kg/run-kg-eval.js +137 -0
- package/dist/kg/runner.d.ts +72 -0
- package/dist/kg/runner.js +51 -0
- package/dist/kg/runners/extract-resolve-runner.d.ts +40 -0
- package/dist/kg/runners/extract-resolve-runner.js +199 -0
- package/dist/kg/runners/extract-runner.d.ts +65 -0
- package/dist/kg/runners/extract-runner.js +243 -0
- package/dist/kg/scorer.d.ts +226 -0
- package/dist/kg/scorer.js +463 -0
- package/dist/kg/targets.d.ts +17 -0
- package/dist/kg/targets.js +16 -0
- package/dist/kg/text.d.ts +45 -0
- package/dist/kg/text.js +100 -0
- package/dist/live/adapters.d.ts +16 -0
- package/dist/live/adapters.js +58 -0
- package/dist/live/env.d.ts +39 -0
- package/dist/live/env.js +56 -0
- package/dist/live/index.d.ts +6 -0
- package/dist/live/index.js +16 -0
- package/dist/live/live-ai.d.ts +104 -0
- package/dist/live/live-ai.js +157 -0
- package/dist/parity/constants.d.ts +79 -0
- package/dist/parity/constants.js +104 -0
- package/dist/parity/index.d.ts +20 -0
- package/dist/parity/index.js +38 -0
- package/dist/parity/internals.d.ts +8 -0
- package/dist/parity/internals.js +16 -0
- package/dist/parity/scenario.d.ts +45 -0
- package/dist/parity/scenario.js +245 -0
- package/dist/parity/script.d.ts +44 -0
- package/dist/parity/script.js +136 -0
- package/dist/parity/snapshot.d.ts +43 -0
- package/dist/parity/snapshot.js +71 -0
- package/dist/real-data/index.d.ts +2 -0
- package/dist/real-data/index.js +12 -0
- package/dist/real-data/real-data.d.ts +76 -0
- package/dist/real-data/real-data.js +156 -0
- package/fixtures/kg-golden/README.md +136 -0
- package/fixtures/kg-golden/ask-questions.json +458 -0
- package/fixtures/kg-golden/meetings/m01-northwind-pilot-kickoff.json +792 -0
- package/fixtures/kg-golden/meetings/m02-halden-migration-planning.json +814 -0
- package/fixtures/kg-golden/meetings/m03-larkspur-weekly-sync.json +601 -0
- package/fixtures/kg-golden/meetings/m04-corvid-intake-discovery.json +690 -0
- package/fixtures/kg-golden/meetings/m05-hosting-vendor-selection.json +631 -0
- package/fixtures/kg-golden/meetings/m06-northwind-floor-data-review.json +649 -0
- package/fixtures/kg-golden/meetings/m07-gullwing-intro-notes.json +428 -0
- package/fixtures/kg-golden/meetings/m08-halden-migration-checkpoint.json +672 -0
- package/fixtures/kg-golden/meetings/m09-northwind-platform-org-update.json +711 -0
- package/fixtures/kg-golden/meetings/m10-corvid-prototype-review.json +623 -0
- package/fixtures/kg-golden/meetings/m11-solvane-grid-dashboard-scoping.json +689 -0
- package/fixtures/kg-golden/meetings/m12-northwind-pilot-replan.json +681 -0
- package/fixtures/kg-golden/meetings/m13-halden-cutover-go-no-go.json +721 -0
- package/fixtures/kg-golden/meetings/m14-gullwing-discovery-readout.json +719 -0
- package/fixtures/kg-golden/meetings/m15-halden-handover-ravi-leaving.json +716 -0
- package/fixtures/kg-golden/meetings/m16-varden-claims-portal-intro.json +704 -0
- package/fixtures/kg-golden/meetings/m17-corvid-usability-debrief.json +572 -0
- package/fixtures/kg-golden/meetings/m18-hosting-decision-revisited.json +655 -0
- package/fixtures/kg-golden/meetings/m19-solvane-integration-kickoff.json +726 -0
- package/fixtures/kg-golden/meetings/m20-northwind-go-live-retro.json +673 -0
- package/fixtures/kg-golden/meetings/m21-quarterly-account-review.json +449 -0
- package/fixtures/kg-golden/meetings/m22-halden-intro-call-2020.json +558 -0
- package/fixtures/kg-golden/meetings/m23-gullwing-model-review.json +702 -0
- package/fixtures/kg-golden/meetings/m24-varden-discovery-midpoint.json +643 -0
- package/fixtures/kg-golden/meetings/m25-corvid-rollout-planning.json +642 -0
- package/fixtures/kg-golden/meetings/m26-larkspur-engineering-prep.json +695 -0
- package/fixtures/kg-golden/meetings/m27-solvane-phase-one-demo.json +649 -0
- package/fixtures/kg-golden/meetings/m28-northwind-building-5-scoping.json +715 -0
- package/fixtures/kg-golden/meetings/m29-halden-southern-cutover-review.json +752 -0
- package/fixtures/kg-golden/meetings/m30-varden-portal-build-kickoff.json +697 -0
- package/fixtures/kg-golden/meetings/m31-gullwing-rollout-renewal.json +681 -0
- package/fixtures/kg-golden/meetings/m32-brambleway-weekly-sync.json +472 -0
- package/fixtures/kg-golden/meetings/m33-nina-oliver-one-on-one.json +342 -0
- package/fixtures/kg-golden/meetings/m34-coffee-with-dana.json +249 -0
- package/fixtures/kg-golden/meetings/m35-brambleway-june-sync.json +553 -0
- package/fixtures/kg-golden/meetings/m36-copenhagen-conference-planning.json +296 -0
- package/host/generated/client.d.ts +1 -0
- package/host/generated/client.js +5 -0
- package/host/generated/default.d.ts +1 -0
- package/host/generated/default.js +5 -0
- package/host/generated/edge.d.ts +1 -0
- package/host/generated/edge.js +1658 -0
- package/host/generated/index-browser.js +1684 -0
- package/host/generated/index.d.ts +192335 -0
- package/host/generated/index.js +1658 -0
- package/host/generated/package.json +139 -0
- package/host/generated/query_compiler_fast_bg.js +2 -0
- package/host/generated/query_compiler_fast_bg.wasm +0 -0
- package/host/generated/query_compiler_fast_bg.wasm-base64.js +2 -0
- package/host/generated/runtime/client.d.ts +3433 -0
- package/host/generated/runtime/client.js +110 -0
- package/host/generated/runtime/index-browser.d.ts +90 -0
- package/host/generated/runtime/index-browser.js +6 -0
- package/host/generated/runtime/wasm-compiler-edge.js +100 -0
- package/host/generated/schema.prisma +6312 -0
- package/host/generated/wasm-edge-light-loader.mjs +5 -0
- package/host/generated/wasm-worker-loader.mjs +5 -0
- package/host/prisma/fragments/kvox.ask.prisma +126 -0
- package/host/prisma/fragments/kvox.graph.prisma +1073 -0
- package/host/prisma/fragments/kvox.notes.prisma +787 -0
- package/host/prisma/fragments/kvox.search.prisma +211 -0
- package/host/prisma/fragments/kvox.transcripts.prisma +790 -0
- package/host/prisma/kvox.lock +101 -0
- package/host/prisma/migrations/20240101000000_initial/migration.sql +297 -0
- package/host/prisma/migrations/20240101000001_add_personal_access_tokens/migration.sql +31 -0
- package/host/prisma/migrations/20240101000002_add_credentials/migration.sql +20 -0
- package/host/prisma/migrations/20240101000003_add_notification_deliveries/migration.sql +27 -0
- package/host/prisma/migrations/20240101000004_drop_stale_uuid_defaults/migration.sql +35 -0
- package/host/prisma/migrations/20240101000005_add_notifications/migration.sql +22 -0
- package/host/prisma/migrations/20240101000006_add_push_subscriptions/migration.sql +25 -0
- package/host/prisma/migrations/20240101000007_add_jobs/migration.sql +110 -0
- package/host/prisma/migrations/20240101000008_add_worker_nodes/migration.sql +90 -0
- package/host/prisma/migrations/20240101000009_add_database_backup_runs/migration.sql +104 -0
- package/host/prisma/migrations/20240101000010_add_notification_broadcasts/migration.sql +57 -0
- package/host/prisma/migrations/20240101000011_add_backup_run_job_link/migration.sql +87 -0
- package/host/prisma/migrations/20240101000012_add_job_node_secrets/migration.sql +61 -0
- package/host/prisma/migrations/20240101000013_add_backup_run_pg_dump_version/migration.sql +26 -0
- package/host/prisma/migrations/20240101000014_add_job_claim_token/migration.sql +92 -0
- package/host/prisma/migrations/20240101000015_add_ai_platform/migration.sql +108 -0
- package/host/prisma/migrations/20240101000016_revoke_viewer_ai_use/migration.sql +32 -0
- package/host/prisma/migrations/20240101000017_add_user_credentials/migration.sql +29 -0
- package/host/prisma/migrations/20240101000018_add_device_session_credential_link/migration.sql +52 -0
- package/host/prisma/migrations/20240101000019_add_worker_node_vitals/migration.sql +3 -0
- package/host/prisma/migrations/20240101000020_add_job_trace_context/migration.sql +6 -0
- package/host/prisma/migrations/20240101000021_add_retention_created_at_indexes/migration.sql +13 -0
- package/host/prisma/migrations/20240101000022_add_organizations/migration.sql +142 -0
- package/host/prisma/migrations/20240101000023_split_system_org_roles/migration.sql +131 -0
- package/host/prisma/migrations/20240101000024_org_scoped_rls/migration.sql +215 -0
- package/host/prisma/migrations/20240101000025_add_groups/migration.sql +165 -0
- package/host/prisma/migrations/20240101000026_add_grants/migration.sql +117 -0
- package/host/prisma/migrations/20240101000027_add_org_settings/migration.sql +49 -0
- package/host/prisma/migrations/20240101000028_add_org_credentials/migration.sql +54 -0
- package/host/prisma/migrations/20240101000029_add_jobs_org_id/migration.sql +18 -0
- package/host/prisma/migrations/20240101000030_add_jobs_org_id_status_index/migration.sql +6 -0
- package/host/prisma/migrations/20240101000031_add_broadcast_target_org/migration.sql +21 -0
- package/host/prisma/migrations/20240101000032_add_android_app/migration.sql +60 -0
- package/host/prisma/migrations/20240101000033_open_job_reason/migration.sql +16 -0
- package/host/prisma/migrations/20240101000034_ai_usage_feature/migration.sql +37 -0
- package/host/prisma/migrations/20240101000035_add_app_metadata/migration.sql +49 -0
- package/host/prisma/migrations/20240101000036_open_sharing_vocabularies/migration.sql +97 -0
- package/host/prisma/migrations/20260914130000_kvox_add_transcripts/migration.sql +322 -0
- package/host/prisma/migrations/20260914140000_kvox_add_notes/migration.sql +311 -0
- package/host/prisma/migrations/20260915120000_kvox_add_search_vectors/migration.sql +150 -0
- package/host/prisma/migrations/20260915130000_kvox_add_search_embeddings/migration.sql +362 -0
- package/host/prisma/migrations/20260915210000_kvox_add_note_title_source/migration.sql +30 -0
- package/host/prisma/migrations/20260923120000_kvox_add_note_generation_context_snapshot/migration.sql +24 -0
- package/host/prisma/migrations/20260923130000_kvox_add_user_hidden_note_templates/migration.sql +35 -0
- package/host/prisma/migrations/20260923140000_kvox_add_transcript_speaker_identities/migration.sql +6 -0
- package/host/prisma/migrations/20260923150000_kvox_transcript_name_checks/migration.sql +95 -0
- package/host/prisma/migrations/20260923160000_kvox_add_note_body_format/migration.sql +27 -0
- package/host/prisma/migrations/20260923170000_kvox_add_note_version_body_format/migration.sql +23 -0
- package/host/prisma/migrations/20260926012548_kvox_add_knowledge_graph/migration.sql +680 -0
- package/host/prisma/migrations/20260926030000_kvox_fix_kg_relations_valid_precision_chk/migration.sql +29 -0
- package/host/prisma/migrations/20260926030100_kvox_add_transcript_recorded_at/migration.sql +9 -0
- package/host/prisma/migrations/20260926030200_kvox_kg_evidence_invariant/migration.sql +60 -0
- package/host/prisma/migrations/20260926040000_kvox_add_kg_graph_layouts/migration.sql +30 -0
- package/host/prisma/migrations/20260926050000_kvox_add_ask_conversations/migration.sql +99 -0
- package/host/prisma/migrations/20260926231512_kvox_add_kg_exports/migration.sql +52 -0
- package/host/prisma/migrations/20261016120000_kvox_transcripts_org_id/migration.sql +49 -0
- package/host/prisma/platform.lock +319 -0
- package/host/prisma/schema/app.kvox.ask.prisma +110 -0
- package/host/prisma/schema/app.kvox.graph.prisma +1030 -0
- package/host/prisma/schema/app.kvox.notes.prisma +746 -0
- package/host/prisma/schema/app.kvox.search.prisma +208 -0
- package/host/prisma/schema/app.kvox.transcripts.prisma +726 -0
- package/host/prisma/schema/platform.ai.prisma +419 -0
- package/host/prisma/schema/platform.android-app.prisma +46 -0
- package/host/prisma/schema/platform.base.prisma +15 -0
- package/host/prisma/schema/platform.credentials.prisma +156 -0
- package/host/prisma/schema/platform.db-backup.prisma +359 -0
- package/host/prisma/schema/platform.identity.prisma +638 -0
- package/host/prisma/schema/platform.jobs.prisma +824 -0
- package/host/prisma/schema/platform.notifications.prisma +641 -0
- package/host/prisma/schema/platform.settings.prisma +53 -0
- package/host/prisma/schema/platform.sharing.prisma +208 -0
- package/host/prisma/schema/platform.storage.prisma +118 -0
- package/package.json +112 -1
- package/parity/requests.ask.json +2681 -0
- package/parity/requests.m01.json +1554 -0
- package/parity/requests.m02.json +1554 -0
- package/parity/requests.m03.json +1554 -0
- package/parity/requests.m04.json +1554 -0
- package/parity/requests.m05.json +1554 -0
- package/parity/requests.m06.json +1554 -0
- package/parity/requests.m07.json +1554 -0
- package/parity/requests.m08.json +1554 -0
- package/parity/requests.m09.json +1554 -0
- package/parity/requests.m10.json +1554 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// The headless Ask evaluation's golden-graph seeder (issue #608; port of the web
|
|
4
|
+
// app's `apps/api/scripts/ask-eval/seed-graph.ts`, #382)
|
|
5
|
+
// =============================================================================
|
|
6
|
+
//
|
|
7
|
+
// Loads EVERY meeting of the golden set and writes it as the evaluation user's
|
|
8
|
+
// data: a `transcripts`/`transcript_speakers`/`transcript_segments` row per
|
|
9
|
+
// meeting with a transcript, a `notes`/`note_versions` row for every meeting,
|
|
10
|
+
// and the meeting's HAND LABELS (never a model's extraction) as `accepted`
|
|
11
|
+
// entities, relations and items with evidence pointing at the segments and the
|
|
12
|
+
// note it just created. That is what makes the evaluation ISOLATE the agent:
|
|
13
|
+
// extraction quality is `kvox-eval kg`'s question, not this one's.
|
|
14
|
+
//
|
|
15
|
+
// EVERY GRAPH ROW GOES THROUGH `GraphWriteService` (the one sanctioned write
|
|
16
|
+
// path): entities, their aliases, relations, items, evidence and supersession,
|
|
17
|
+
// inside one `prisma.$transaction` per fixture with the user's effective
|
|
18
|
+
// schema. So the type, endpoint, temporal, status and evidence-readability
|
|
19
|
+
// checks run, and the deferred `kg_assert_has_evidence` trigger checks every
|
|
20
|
+
// accepted row at COMMIT. Transcripts, segments, speakers, notes, note versions
|
|
21
|
+
// and storage objects are not graph rows; they are plain inserts.
|
|
22
|
+
//
|
|
23
|
+
// AN ENTITY THAT RECURS ACROSS MEETINGS BECOMES ONE ROW. A fixture's
|
|
24
|
+
// `knownEntities[].id` (`"g-person-sarah-chen"`) is the stable cross-fixture
|
|
25
|
+
// identity a later meeting's `existingId` links back to. Fixtures are seeded in
|
|
26
|
+
// id order, so a person's first mention creates the row; a later `existingId`,
|
|
27
|
+
// or a label/alias that matches what any fixture declares for that global id,
|
|
28
|
+
// resolves to it (and adds its evidence with `addEvidence`). A label no
|
|
29
|
+
// `knownEntities` list mentions stays a one-off row of its own meeting.
|
|
30
|
+
//
|
|
31
|
+
// A REFERENCE-ONLY ENTITY (a `knownEntities` id a relation or item names, with
|
|
32
|
+
// no label of its own anywhere yet) still needs evidence to be `accepted`. The
|
|
33
|
+
// web app's seeder wrote a quote-only filler row (no anchor); the write service
|
|
34
|
+
// refuses an unanchored citation, so the filler cites the referring meeting's
|
|
35
|
+
// note with the label as its quote, the shape of a note-Context citation. It is
|
|
36
|
+
// left OUT of `evidenceSource`, exactly as the unanchored filler was.
|
|
37
|
+
//
|
|
38
|
+
// WHAT THE WRITE SERVICE REFUSES IS REPORTED, NEVER DROPPED SILENTLY: each
|
|
39
|
+
// refusal lands in `refusals` (fixture, row, the service's message; type keys
|
|
40
|
+
// and paths only, never a label, statement or quote) and the row is skipped.
|
|
41
|
+
// The refusals the service raises happen before its insert, so the
|
|
42
|
+
// transaction stays usable.
|
|
43
|
+
// =============================================================================
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.seedGoldenGraph = seedGoldenGraph;
|
|
46
|
+
const node_crypto_1 = require("node:crypto");
|
|
47
|
+
const graph_1 = require("@marinoscar/kvox-api/graph");
|
|
48
|
+
const index_js_1 = require("../fixtures/index.js");
|
|
49
|
+
const normalize = (s) => s.trim().toLowerCase();
|
|
50
|
+
function buildGlobalCatalog(fixtures) {
|
|
51
|
+
const catalog = new Map();
|
|
52
|
+
for (const fixture of fixtures) {
|
|
53
|
+
for (const known of fixture.knownEntities) {
|
|
54
|
+
const existing = catalog.get(known.id);
|
|
55
|
+
if (existing) {
|
|
56
|
+
for (const alias of known.aliases)
|
|
57
|
+
existing.aliases.add(alias);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
catalog.set(known.id, { type: known.type, label: known.label, aliases: new Set(known.aliases) });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return catalog;
|
|
65
|
+
}
|
|
66
|
+
function buildLabelIndex(catalog) {
|
|
67
|
+
const index = new Map();
|
|
68
|
+
for (const [globalId, entry] of catalog) {
|
|
69
|
+
for (const name of [entry.label, ...entry.aliases]) {
|
|
70
|
+
index.set(`${entry.type}\u0000${normalize(name)}`, globalId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return index;
|
|
74
|
+
}
|
|
75
|
+
/** The global identity this label resolves to, if any: `existingId`, else a label/alias match against the catalog. */
|
|
76
|
+
function globalIdFor(ctx, entity) {
|
|
77
|
+
if (entity.existingId)
|
|
78
|
+
return entity.existingId;
|
|
79
|
+
const byLabel = ctx.labelToGlobalId.get(`${entity.type}\u0000${normalize(entity.label)}`);
|
|
80
|
+
if (byLabel)
|
|
81
|
+
return byLabel;
|
|
82
|
+
for (const alias of entity.aliases) {
|
|
83
|
+
const hit = ctx.labelToGlobalId.get(`${entity.type}\u0000${normalize(alias)}`);
|
|
84
|
+
if (hit)
|
|
85
|
+
return hit;
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
/** The refusal's message: the error's own text plus its issue paths (the service never puts data in either). */
|
|
90
|
+
function reasonOf(error) {
|
|
91
|
+
const e = error;
|
|
92
|
+
const issues = e.details?.issues?.map((i) => `${String(i.path)}: ${String(i.message)}`) ?? [];
|
|
93
|
+
const response = e.response;
|
|
94
|
+
const invalidEvidence = response?.details?.invalidEvidence;
|
|
95
|
+
const extra = [...issues, ...(invalidEvidence ? [`invalid evidence at ${invalidEvidence.join(', ')}`] : [])];
|
|
96
|
+
return `${typeof e.message === 'string' ? e.message : String(error)}${extra.length ? ` [${extra.join('; ')}]` : ''}`;
|
|
97
|
+
}
|
|
98
|
+
/** Runs one write; a refusal is recorded and answers `null`. */
|
|
99
|
+
async function attempt(ctx, row, write) {
|
|
100
|
+
try {
|
|
101
|
+
return await write();
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const name = error.name;
|
|
105
|
+
const status = error.getStatus?.();
|
|
106
|
+
const refusal = name === 'GraphValidationError' ||
|
|
107
|
+
name === 'GraphInvariantError' ||
|
|
108
|
+
name === 'GraphDuplicateError' ||
|
|
109
|
+
status === 400 ||
|
|
110
|
+
status === 404;
|
|
111
|
+
if (!refusal)
|
|
112
|
+
throw error;
|
|
113
|
+
ctx.refusals.push({ fixtureId: ctx.fixture.id, row, reason: reasonOf(error) });
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** A label's evidence as write-service input, anchored to the rows this run created. */
|
|
118
|
+
function toEvidence(ctx, labels) {
|
|
119
|
+
const out = [];
|
|
120
|
+
for (const ev of labels) {
|
|
121
|
+
const quote = ev.quote.slice(0, 400);
|
|
122
|
+
if (ev.source === 'segment') {
|
|
123
|
+
const segment = ctx.segmentRows.get(ev.segmentId);
|
|
124
|
+
if (!segment) {
|
|
125
|
+
ctx.warnings.push(`${ctx.fixture.id}: evidence cites unknown segment "${ev.segmentId}"`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
out.push(evidenceInput({ transcriptId: segment.transcriptId, segmentId: segment.id, startMs: segment.startMs, endMs: segment.endMs, quote }));
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const noteId = ctx.idMap.notes.get(ctx.fixture.id);
|
|
132
|
+
if (!noteId) {
|
|
133
|
+
ctx.warnings.push(`${ctx.fixture.id}: evidence cites the meeting's note, which it has none of`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
out.push(evidenceInput({ noteId, noteVersion: ctx.fixture.note.version, quote }));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
/** A full {@link EvidenceInput} (every anchor field `null` unless given). */
|
|
142
|
+
function evidenceInput(fields) {
|
|
143
|
+
return {
|
|
144
|
+
transcriptId: null,
|
|
145
|
+
segmentId: null,
|
|
146
|
+
segmentRev: null,
|
|
147
|
+
startMs: null,
|
|
148
|
+
endMs: null,
|
|
149
|
+
noteId: null,
|
|
150
|
+
noteVersion: null,
|
|
151
|
+
charStart: null,
|
|
152
|
+
charEnd: null,
|
|
153
|
+
importObjectId: null,
|
|
154
|
+
sourceIri: null,
|
|
155
|
+
...fields,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Maps the subject's evidence rows that are not mapped yet to their fixture
|
|
160
|
+
* source (`"m01-s009"`, `"m01#note"`). The write service's creates return the
|
|
161
|
+
* row, not its evidence, so the ids are read back by subject.
|
|
162
|
+
*/
|
|
163
|
+
async function mapEvidence(ctx, subjectKind, subjectId) {
|
|
164
|
+
const rows = await ctx.tx.kgEvidence.findMany({
|
|
165
|
+
where: { subjectKind, subjectId },
|
|
166
|
+
select: { id: true, segmentId: true, noteId: true },
|
|
167
|
+
});
|
|
168
|
+
for (const row of rows) {
|
|
169
|
+
if (ctx.idMap.evidenceSource.has(row.id))
|
|
170
|
+
continue;
|
|
171
|
+
const source = row.segmentId
|
|
172
|
+
? ctx.segmentSource.get(row.segmentId)
|
|
173
|
+
: row.noteId
|
|
174
|
+
? `${ctx.noteSource.get(row.noteId)}#note`
|
|
175
|
+
: undefined;
|
|
176
|
+
if (source)
|
|
177
|
+
ctx.idMap.evidenceSource.set(row.id, source);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** Creates one accepted entity with its aliases and evidence; maps the evidence. */
|
|
181
|
+
async function createEntity(ctx, row, entity, evidence, mapIt = true) {
|
|
182
|
+
const created = await attempt(ctx, row, () => ctx.writer.createEntity(ctx.tx, {
|
|
183
|
+
ownerId: ctx.ownerId,
|
|
184
|
+
type: entity.type,
|
|
185
|
+
label: entity.label,
|
|
186
|
+
props: {},
|
|
187
|
+
reviewStatus: 'accepted',
|
|
188
|
+
labelSource: 'extraction',
|
|
189
|
+
aliases: [...entity.aliases].map((alias) => ({ alias, source: 'extraction' })),
|
|
190
|
+
evidence,
|
|
191
|
+
}, ctx.schema));
|
|
192
|
+
if (!created)
|
|
193
|
+
return null;
|
|
194
|
+
ctx.counts.entities += 1;
|
|
195
|
+
ctx.counts.evidence += evidence.length;
|
|
196
|
+
if (mapIt)
|
|
197
|
+
await mapEvidence(ctx, 'entity', created.id);
|
|
198
|
+
return created.id;
|
|
199
|
+
}
|
|
200
|
+
/** Adds evidence to an entity an earlier label already created; maps the new rows. */
|
|
201
|
+
async function addEntityEvidence(ctx, row, entityId, evidence) {
|
|
202
|
+
if (evidence.length === 0)
|
|
203
|
+
return;
|
|
204
|
+
const added = await attempt(ctx, row, () => ctx.writer.addEvidence(ctx.tx, ctx.ownerId, 'entity', entityId, evidence));
|
|
205
|
+
if (!added)
|
|
206
|
+
return;
|
|
207
|
+
ctx.counts.evidence += added.length;
|
|
208
|
+
await mapEvidence(ctx, 'entity', entityId);
|
|
209
|
+
}
|
|
210
|
+
/** One entity label of one fixture → its `kg_entities.id`, creating it (or its global row) exactly once. */
|
|
211
|
+
async function resolveEntity(ctx, entity, row) {
|
|
212
|
+
const evidence = toEvidence(ctx, entity.evidence);
|
|
213
|
+
const globalId = globalIdFor(ctx, entity);
|
|
214
|
+
if (globalId) {
|
|
215
|
+
const already = ctx.globalEntityId.get(globalId);
|
|
216
|
+
if (already) {
|
|
217
|
+
ctx.localEntityId.set(entity.key, already);
|
|
218
|
+
await addEntityEvidence(ctx, row, already, evidence);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
const catalogEntry = ctx.globalCatalog.get(globalId);
|
|
222
|
+
const id = await createEntity(ctx, row, {
|
|
223
|
+
type: catalogEntry?.type ?? entity.type,
|
|
224
|
+
label: catalogEntry?.label ?? entity.label,
|
|
225
|
+
aliases: catalogEntry ? catalogEntry.aliases : entity.aliases,
|
|
226
|
+
}, evidence);
|
|
227
|
+
if (!id)
|
|
228
|
+
return;
|
|
229
|
+
ctx.globalEntityId.set(globalId, id);
|
|
230
|
+
ctx.idMap.entities.set(globalId, id);
|
|
231
|
+
ctx.localEntityId.set(entity.key, id);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const id = await createEntity(ctx, row, entity, evidence);
|
|
235
|
+
if (id)
|
|
236
|
+
ctx.localEntityId.set(entity.key, id);
|
|
237
|
+
}
|
|
238
|
+
/** A `knownEntities` id this fixture names without restating it as one of its labels: created once, from the catalog. */
|
|
239
|
+
async function resolveKnownEntityRef(ctx, globalId) {
|
|
240
|
+
const already = ctx.globalEntityId.get(globalId);
|
|
241
|
+
if (already)
|
|
242
|
+
return already;
|
|
243
|
+
const entry = ctx.globalCatalog.get(globalId);
|
|
244
|
+
if (!entry)
|
|
245
|
+
return null;
|
|
246
|
+
const noteId = ctx.idMap.notes.get(ctx.fixture.id);
|
|
247
|
+
if (!noteId) {
|
|
248
|
+
ctx.warnings.push(`${ctx.fixture.id}: reference-only entity "${globalId}" has no note to cite`);
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
// The filler citation (see the header): the referring meeting's note, the label as the quote.
|
|
252
|
+
const filler = [evidenceInput({ noteId, noteVersion: ctx.fixture.note.version, quote: entry.label.slice(0, 400) })];
|
|
253
|
+
const id = await createEntity(ctx, `reference-only entity ${globalId} (${entry.type})`, entry, filler, false);
|
|
254
|
+
if (!id)
|
|
255
|
+
return null;
|
|
256
|
+
ctx.globalEntityId.set(globalId, id);
|
|
257
|
+
ctx.idMap.entities.set(globalId, id);
|
|
258
|
+
return id;
|
|
259
|
+
}
|
|
260
|
+
/** A relation's `from`/`to`, an item's `subject`/`owner`/`counterparty`: a local key, or a global (`knownEntities`) id. */
|
|
261
|
+
async function resolveRef(ctx, ref) {
|
|
262
|
+
if (ref === null)
|
|
263
|
+
return null;
|
|
264
|
+
const local = ctx.localEntityId.get(ref);
|
|
265
|
+
if (local)
|
|
266
|
+
return local;
|
|
267
|
+
if (ctx.globalCatalog.has(ref))
|
|
268
|
+
return resolveKnownEntityRef(ctx, ref);
|
|
269
|
+
ctx.warnings.push(`${ctx.fixture.id}: unresolved entity reference "${ref}"`);
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
/** `YYYY-MM-DD` bounds → a range, or `null` when both are open. */
|
|
273
|
+
function toValidRange(validFrom, validTo) {
|
|
274
|
+
if (validFrom === null && validTo === null)
|
|
275
|
+
return null;
|
|
276
|
+
return { from: validFrom ? new Date(`${validFrom}T00:00:00Z`) : null, to: validTo ? new Date(`${validTo}T00:00:00Z`) : null };
|
|
277
|
+
}
|
|
278
|
+
async function seedTranscriptAndNote(ctx) {
|
|
279
|
+
const { tx, fixture } = ctx;
|
|
280
|
+
let transcriptId = null;
|
|
281
|
+
if (fixture.hasTranscript) {
|
|
282
|
+
const source = await tx.storageObject.create({
|
|
283
|
+
data: {
|
|
284
|
+
name: `${fixture.id}.m4a`,
|
|
285
|
+
size: BigInt(1),
|
|
286
|
+
mimeType: 'audio/mp4',
|
|
287
|
+
storageKey: `ask-eval/${(0, node_crypto_1.randomUUID)()}`,
|
|
288
|
+
orgId: ctx.orgId,
|
|
289
|
+
uploadedById: ctx.ownerId,
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
const transcript = await tx.transcript.create({
|
|
293
|
+
data: {
|
|
294
|
+
ownerId: ctx.ownerId,
|
|
295
|
+
orgId: ctx.orgId,
|
|
296
|
+
title: fixture.title,
|
|
297
|
+
sourceObjectId: source.id,
|
|
298
|
+
provider: 'assemblyai',
|
|
299
|
+
status: 'ready',
|
|
300
|
+
transcriptionStatus: 'completed',
|
|
301
|
+
playbackStatus: 'ready',
|
|
302
|
+
recordedAt: new Date(fixture.recordedAt),
|
|
303
|
+
},
|
|
304
|
+
});
|
|
305
|
+
transcriptId = transcript.id;
|
|
306
|
+
const speakerId = new Map();
|
|
307
|
+
for (const [i, speaker] of fixture.speakers.entries()) {
|
|
308
|
+
const row = await tx.transcriptSpeaker.create({
|
|
309
|
+
data: { transcriptId: transcript.id, label: speaker.label, displayName: speaker.displayName ?? speaker.label, colorIndex: i % 8 },
|
|
310
|
+
});
|
|
311
|
+
speakerId.set(speaker.id, row.id);
|
|
312
|
+
}
|
|
313
|
+
for (const segment of fixture.segments) {
|
|
314
|
+
const row = await tx.transcriptSegment.create({
|
|
315
|
+
data: {
|
|
316
|
+
transcriptId: transcript.id,
|
|
317
|
+
speakerId: speakerId.get(segment.speakerId) ?? [...speakerId.values()][0],
|
|
318
|
+
startMs: segment.startMs,
|
|
319
|
+
endMs: segment.endMs,
|
|
320
|
+
ordinal: segment.startMs,
|
|
321
|
+
text: segment.text,
|
|
322
|
+
words: [],
|
|
323
|
+
},
|
|
324
|
+
});
|
|
325
|
+
ctx.idMap.segments.set(segment.id, row.id);
|
|
326
|
+
ctx.segmentSource.set(row.id, segment.id);
|
|
327
|
+
ctx.segmentRows.set(segment.id, { id: row.id, transcriptId: transcript.id, startMs: segment.startMs, endMs: segment.endMs });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
let sourceObjectId = null;
|
|
331
|
+
if (!fixture.hasTranscript) {
|
|
332
|
+
const doc = await tx.storageObject.create({
|
|
333
|
+
data: {
|
|
334
|
+
name: `${fixture.id}.md`,
|
|
335
|
+
size: BigInt(fixture.note.body.length),
|
|
336
|
+
mimeType: 'text/markdown',
|
|
337
|
+
storageKey: `ask-eval/${(0, node_crypto_1.randomUUID)()}`,
|
|
338
|
+
orgId: ctx.orgId,
|
|
339
|
+
uploadedById: ctx.ownerId,
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
sourceObjectId = doc.id;
|
|
343
|
+
}
|
|
344
|
+
const note = await tx.note.create({
|
|
345
|
+
data: {
|
|
346
|
+
ownerId: ctx.ownerId,
|
|
347
|
+
title: fixture.title,
|
|
348
|
+
body: fixture.note.body,
|
|
349
|
+
status: 'ready',
|
|
350
|
+
currentVersion: fixture.note.version,
|
|
351
|
+
sourceType: transcriptId ? 'transcript' : 'document',
|
|
352
|
+
sourceTranscriptId: transcriptId,
|
|
353
|
+
sourceObjectId,
|
|
354
|
+
createdAt: new Date(fixture.recordedAt),
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
await tx.noteVersion.create({ data: { noteId: note.id, version: fixture.note.version, kind: 'ai_generated', body: fixture.note.body } });
|
|
358
|
+
ctx.idMap.notes.set(fixture.id, note.id);
|
|
359
|
+
ctx.noteSource.set(note.id, fixture.id);
|
|
360
|
+
}
|
|
361
|
+
async function seedRelations(ctx) {
|
|
362
|
+
for (const [index, relation] of ctx.fixture.labels.relations.entries()) {
|
|
363
|
+
const row = `relation #${index + 1} (${relation.type})`;
|
|
364
|
+
const fromId = await resolveRef(ctx, relation.from);
|
|
365
|
+
const toId = await resolveRef(ctx, relation.to);
|
|
366
|
+
if (!fromId || !toId) {
|
|
367
|
+
ctx.refusals.push({ fixtureId: ctx.fixture.id, row, reason: `an endpoint did not resolve (${!fromId ? 'from' : 'to'})` });
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const temporal = ctx.schema.relationType(relation.type)?.temporal ?? false;
|
|
371
|
+
const valid = toValidRange(relation.validFrom, relation.validTo);
|
|
372
|
+
// The label's precision travels with its range; a temporal relation with
|
|
373
|
+
// no range keeps `unknown` (the write service's "no range" spelling).
|
|
374
|
+
const validPrecision = valid ? relation.precision : temporal && relation.precision === 'unknown' ? 'unknown' : null;
|
|
375
|
+
const evidence = toEvidence(ctx, relation.evidence);
|
|
376
|
+
const created = await attempt(ctx, row, () => ctx.writer.createRelation(ctx.tx, { ownerId: ctx.ownerId, type: relation.type, fromId, toId, props: {}, valid, validPrecision, reviewStatus: 'accepted', evidence }, ctx.schema));
|
|
377
|
+
if (!created)
|
|
378
|
+
continue;
|
|
379
|
+
ctx.counts.relations += 1;
|
|
380
|
+
ctx.counts.evidence += evidence.length;
|
|
381
|
+
await mapEvidence(ctx, 'relation', created.id);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
/** The ontology type that stores items of `kind`. */
|
|
385
|
+
function itemTypeKey(schema, kind) {
|
|
386
|
+
return schema.entityTypes.find((t) => t.storage === 'item' && t.itemKind === kind)?.key ?? null;
|
|
387
|
+
}
|
|
388
|
+
async function seedItems(ctx, meetingId) {
|
|
389
|
+
const countByKind = new Map();
|
|
390
|
+
for (const item of ctx.fixture.labels.items) {
|
|
391
|
+
const n = countByKind.get(item.kind) ?? 0;
|
|
392
|
+
countByKind.set(item.kind, n + 1);
|
|
393
|
+
const address = (0, index_js_1.itemAddress)(ctx.fixture.id, item.kind, n);
|
|
394
|
+
const row = `item ${address}`;
|
|
395
|
+
const typeKey = itemTypeKey(ctx.schema, item.kind);
|
|
396
|
+
if (!typeKey) {
|
|
397
|
+
ctx.refusals.push({ fixtureId: ctx.fixture.id, row, reason: `no item type stores '${item.kind}'` });
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
const subjectId = await resolveRef(ctx, item.subject);
|
|
401
|
+
const ownerPersonId = await resolveRef(ctx, item.owner);
|
|
402
|
+
const counterpartyId = await resolveRef(ctx, item.counterparty);
|
|
403
|
+
let supersedesId = null;
|
|
404
|
+
if (item.supersedesLabel) {
|
|
405
|
+
supersedesId = ctx.itemByAddress.get(item.supersedesLabel) ?? null;
|
|
406
|
+
if (!supersedesId)
|
|
407
|
+
ctx.warnings.push(`${ctx.fixture.id}: ${address} supersedes unknown item address "${item.supersedesLabel}"`);
|
|
408
|
+
}
|
|
409
|
+
// The meeting column only where the ontology has one for this item type (a
|
|
410
|
+
// Commitment or Decision has `meeting_id`; a Claim or PersonFact does not):
|
|
411
|
+
// the web app's seeder stamped it on every item, which the write service refuses.
|
|
412
|
+
const meetingAllowed = ctx.schema.relationTypes.some((r) => r.representation.kind === 'item_column' && r.representation.column === 'meeting_id' && r.from.includes(typeKey));
|
|
413
|
+
const evidence = toEvidence(ctx, item.evidence);
|
|
414
|
+
const created = await attempt(ctx, row, () => ctx.writer.createItem(ctx.tx, {
|
|
415
|
+
ownerId: ctx.ownerId,
|
|
416
|
+
kind: item.kind,
|
|
417
|
+
typeKey,
|
|
418
|
+
subjectId,
|
|
419
|
+
meetingId: meetingAllowed ? meetingId : null,
|
|
420
|
+
ownerPersonId,
|
|
421
|
+
counterpartyId,
|
|
422
|
+
title: item.title,
|
|
423
|
+
statement: item.statement,
|
|
424
|
+
status: item.status ?? (item.kind === 'commitment' ? 'open' : 'active'),
|
|
425
|
+
occurredAt: item.occurredAt ? new Date(item.occurredAt) : null,
|
|
426
|
+
dueAt: item.dueAt ? new Date(item.dueAt) : null,
|
|
427
|
+
// The web app's seeder default (`business`), kept so the two seed the same graph;
|
|
428
|
+
// the write service's own default for an unlabelled person fact is `personal`.
|
|
429
|
+
sensitivity: item.kind === 'person_fact' ? (item.sensitivity ?? 'business') : null,
|
|
430
|
+
reviewStatus: 'accepted',
|
|
431
|
+
supersedesId,
|
|
432
|
+
evidence,
|
|
433
|
+
}, ctx.schema));
|
|
434
|
+
if (!created)
|
|
435
|
+
continue;
|
|
436
|
+
ctx.counts.items += 1;
|
|
437
|
+
ctx.counts.evidence += evidence.length;
|
|
438
|
+
ctx.itemByAddress.set(address, created.id);
|
|
439
|
+
await mapEvidence(ctx, 'item', created.id);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Seeds the evaluation user's entire gold graph from EVERY fixture in
|
|
444
|
+
* `fixtures` (pass the full loaded set: `loadGoldenSet()`), one transaction per
|
|
445
|
+
* fixture, in fixture id order, through `GraphWriteService`.
|
|
446
|
+
*
|
|
447
|
+
* @param host - the running host (its client, user and organization, and the write service).
|
|
448
|
+
* @param fixtures - the golden meetings.
|
|
449
|
+
* @returns the id map the scorer needs, the refusals and the warnings.
|
|
450
|
+
* @stability experimental
|
|
451
|
+
*/
|
|
452
|
+
async function seedGoldenGraph(host, fixtures) {
|
|
453
|
+
for (const f of fixtures)
|
|
454
|
+
index_js_1.goldenFixtureSchema.parse(f); // fail loudly on a malformed fixture before writing anything
|
|
455
|
+
const sorted = [...fixtures].sort((a, b) => a.id.localeCompare(b.id, 'en', { numeric: true }));
|
|
456
|
+
// The personal domain (Trip, Milestone, SPOUSE_OF, ...) is off by default; the
|
|
457
|
+
// golden set's personal meetings need it on, as `kvox-eval kg` extracts them
|
|
458
|
+
// (`fixtureDomains`). The Ask tools hide personal types whatever this says.
|
|
459
|
+
if (sorted.some((f) => (0, index_js_1.fixtureDomains)(f).includes('personal'))) {
|
|
460
|
+
await host.settings.patchUser(host.userId, 'graph', { domains: { work: true, personal: true } });
|
|
461
|
+
}
|
|
462
|
+
const writer = host.resolve(graph_1.GraphWriteService);
|
|
463
|
+
const schema = await host.resolve(graph_1.GraphOntologyService).effectiveSchemaFor(host.userId);
|
|
464
|
+
const idMap = { segments: new Map(), notes: new Map(), entities: new Map(), evidenceSource: new Map() };
|
|
465
|
+
const globalCatalog = buildGlobalCatalog(sorted);
|
|
466
|
+
const shared = {
|
|
467
|
+
writer,
|
|
468
|
+
schema,
|
|
469
|
+
ownerId: host.userId,
|
|
470
|
+
orgId: host.orgId,
|
|
471
|
+
idMap,
|
|
472
|
+
segmentSource: new Map(),
|
|
473
|
+
noteSource: new Map(),
|
|
474
|
+
globalEntityId: new Map(),
|
|
475
|
+
globalCatalog,
|
|
476
|
+
labelToGlobalId: buildLabelIndex(globalCatalog),
|
|
477
|
+
itemByAddress: new Map(),
|
|
478
|
+
refusals: [],
|
|
479
|
+
warnings: [],
|
|
480
|
+
counts: { entities: 0, relations: 0, items: 0, evidence: 0 },
|
|
481
|
+
};
|
|
482
|
+
for (const fixture of sorted) {
|
|
483
|
+
await host.prisma.$transaction(async (tx) => {
|
|
484
|
+
const ctx = { ...shared, tx, fixture, localEntityId: new Map(), segmentRows: new Map() };
|
|
485
|
+
await seedTranscriptAndNote(ctx);
|
|
486
|
+
for (const [index, entity] of fixture.labels.entities.entries()) {
|
|
487
|
+
await resolveEntity(ctx, entity, `entity #${index + 1} (${entity.type})`);
|
|
488
|
+
}
|
|
489
|
+
const meetingEntityId = ctx.localEntityId.get('meeting') ?? null;
|
|
490
|
+
await seedRelations(ctx);
|
|
491
|
+
await seedItems(ctx, meetingEntityId);
|
|
492
|
+
}, { timeout: 120_000, maxWait: 120_000 });
|
|
493
|
+
}
|
|
494
|
+
return { userId: host.userId, idMap, refusals: shared.refusals, warnings: shared.warnings, counts: shared.counts };
|
|
495
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.main = exports.KVOX_EVAL_USAGE = exports.runKgCommand = exports.KG_EVAL_EXIT = exports.KG_COMMAND_USAGE = void 0;
|
|
4
|
+
// The cli slice's public surface (re-exported by the package root). The `bin`
|
|
5
|
+
// is `dist/cli/main.js`.
|
|
6
|
+
var kg_command_js_1 = require("./kg-command.js");
|
|
7
|
+
Object.defineProperty(exports, "KG_COMMAND_USAGE", { enumerable: true, get: function () { return kg_command_js_1.KG_COMMAND_USAGE; } });
|
|
8
|
+
Object.defineProperty(exports, "KG_EVAL_EXIT", { enumerable: true, get: function () { return kg_command_js_1.KG_EVAL_EXIT; } });
|
|
9
|
+
Object.defineProperty(exports, "runKgCommand", { enumerable: true, get: function () { return kg_command_js_1.runKgCommand; } });
|
|
10
|
+
var main_js_1 = require("./main.js");
|
|
11
|
+
Object.defineProperty(exports, "KVOX_EVAL_USAGE", { enumerable: true, get: function () { return main_js_1.KVOX_EVAL_USAGE; } });
|
|
12
|
+
Object.defineProperty(exports, "main", { enumerable: true, get: function () { return main_js_1.main; } });
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { AiProviderAdapter } from '@marinoscar/platform-api/ai';
|
|
2
|
+
/**
|
|
3
|
+
* The exit codes of `kvox-eval kg` (and of the web app's `npm run kg:eval`).
|
|
4
|
+
*
|
|
5
|
+
* @stability experimental
|
|
6
|
+
*/
|
|
7
|
+
export declare const KG_EVAL_EXIT: Readonly<{
|
|
8
|
+
readonly ok: 0;
|
|
9
|
+
readonly targetsFailed: 1;
|
|
10
|
+
readonly usage: 2;
|
|
11
|
+
readonly pathRefused: 3;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Where a command writes, and the environment it reads.
|
|
15
|
+
*
|
|
16
|
+
* @stability experimental
|
|
17
|
+
*/
|
|
18
|
+
export interface EvalCommandIo {
|
|
19
|
+
/** One line to standard output. */
|
|
20
|
+
out: (line: string) => void;
|
|
21
|
+
/** One line to standard error. */
|
|
22
|
+
err: (line: string) => void;
|
|
23
|
+
/** The environment (`process.env`, or a test's own). */
|
|
24
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* How a host runs the kg command under its own name.
|
|
28
|
+
*
|
|
29
|
+
* @stability experimental
|
|
30
|
+
*/
|
|
31
|
+
export interface KgCommandOptions {
|
|
32
|
+
/** The prefix of every message (`kvox-eval kg`, `kg:eval`). */
|
|
33
|
+
name?: string;
|
|
34
|
+
/** The usage text printed with a usage error and for `--help`. */
|
|
35
|
+
usage?: string;
|
|
36
|
+
/**
|
|
37
|
+
* A git-ignored directory inside the repository that output of a run over the
|
|
38
|
+
* SYNTHETIC set may be written to, and the default `--out` root (the web app's
|
|
39
|
+
* `apps/api/.kg-eval/`). Default: none, and the output defaults to the system
|
|
40
|
+
* temporary directory.
|
|
41
|
+
*/
|
|
42
|
+
syntheticRunsDir?: string | null;
|
|
43
|
+
/** The provider adapters by id. Default: the platform's. A test passes a fake. */
|
|
44
|
+
adapters?: Readonly<Record<string, AiProviderAdapter>>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The usage text of `kvox-eval kg`.
|
|
48
|
+
*
|
|
49
|
+
* @stability experimental
|
|
50
|
+
*/
|
|
51
|
+
export declare const KG_COMMAND_USAGE = "usage: kvox-eval kg (--predictions <dir|gold> | --runner extract|extract-resolve --model <id>)\n [--provider openai|openai-compatible|copilot] [--base-url <url>] [--out <dir>]\n [--only m01,m07] [--tag <tag>] [--json <file>] [--enforce] [--real-dir <dir>]\n reads a live runner's API key from KVOX_EVAL_OPENAI_API_KEY (never a flag)";
|
|
52
|
+
/**
|
|
53
|
+
* Runs `kvox-eval kg` with the given arguments (everything after `kg`).
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* const code = await runKgCommand(['--predictions', 'gold'], { out: console.log, err: console.error, env: process.env });
|
|
58
|
+
* ```
|
|
59
|
+
*
|
|
60
|
+
* @param argv - the arguments.
|
|
61
|
+
* @param io - output streams and environment.
|
|
62
|
+
* @param options - the host's name, usage text, scratch directory and adapters.
|
|
63
|
+
* @returns the exit code ({@link KG_EVAL_EXIT}).
|
|
64
|
+
* @stability experimental
|
|
65
|
+
*/
|
|
66
|
+
export declare function runKgCommand(argv: string[], io: EvalCommandIo, options?: KgCommandOptions): Promise<number>;
|