ai-capability-framework 1.0.3 → 1.1.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 (246) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +38 -30
  3. package/ROADMAP.md +14 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +32 -1
  6. package/dist/discovery/bindings.d.ts +7 -0
  7. package/dist/discovery/bindings.d.ts.map +1 -0
  8. package/dist/discovery/bindings.js +24 -0
  9. package/dist/discovery/budget.d.ts +17 -0
  10. package/dist/discovery/budget.d.ts.map +1 -0
  11. package/dist/discovery/budget.js +77 -0
  12. package/dist/discovery/configuration.d.ts +10 -0
  13. package/dist/discovery/configuration.d.ts.map +1 -0
  14. package/dist/discovery/configuration.js +63 -0
  15. package/dist/discovery/corpus.d.ts +8 -0
  16. package/dist/discovery/corpus.d.ts.map +1 -0
  17. package/dist/discovery/corpus.js +64 -0
  18. package/dist/discovery/diagnostics.d.ts +15 -0
  19. package/dist/discovery/diagnostics.d.ts.map +1 -0
  20. package/dist/discovery/diagnostics.js +11 -0
  21. package/dist/discovery/discoverer.d.ts +23 -0
  22. package/dist/discovery/discoverer.d.ts.map +1 -0
  23. package/dist/discovery/discoverer.js +261 -0
  24. package/dist/discovery/embedding-configuration.d.ts +12 -0
  25. package/dist/discovery/embedding-configuration.d.ts.map +1 -0
  26. package/dist/discovery/embedding-configuration.js +81 -0
  27. package/dist/discovery/embedding-types.d.ts +75 -0
  28. package/dist/discovery/embedding-types.d.ts.map +1 -0
  29. package/dist/discovery/embedding-types.js +1 -0
  30. package/dist/discovery/embeddings.d.ts +38 -0
  31. package/dist/discovery/embeddings.d.ts.map +1 -0
  32. package/dist/discovery/embeddings.js +71 -0
  33. package/dist/discovery/evaluation-validation.d.ts +8 -0
  34. package/dist/discovery/evaluation-validation.d.ts.map +1 -0
  35. package/dist/discovery/evaluation-validation.js +19 -0
  36. package/dist/discovery/evaluation.d.ts +84 -0
  37. package/dist/discovery/evaluation.d.ts.map +1 -0
  38. package/dist/discovery/evaluation.js +310 -0
  39. package/dist/discovery/export.d.ts +14 -0
  40. package/dist/discovery/export.d.ts.map +1 -0
  41. package/dist/discovery/export.js +81 -0
  42. package/dist/discovery/facade.d.ts +82 -0
  43. package/dist/discovery/facade.d.ts.map +1 -0
  44. package/dist/discovery/facade.js +266 -0
  45. package/dist/discovery/fingerprint.d.ts +71 -0
  46. package/dist/discovery/fingerprint.d.ts.map +1 -0
  47. package/dist/discovery/fingerprint.js +67 -0
  48. package/dist/discovery/index-builder.d.ts +3 -0
  49. package/dist/discovery/index-builder.d.ts.map +1 -0
  50. package/dist/discovery/index-builder.js +129 -0
  51. package/dist/discovery/index-validation.d.ts +12 -0
  52. package/dist/discovery/index-validation.d.ts.map +1 -0
  53. package/dist/discovery/index-validation.js +117 -0
  54. package/dist/discovery/index.d.ts +32 -0
  55. package/dist/discovery/index.d.ts.map +1 -0
  56. package/dist/discovery/index.js +18 -0
  57. package/dist/discovery/json-snapshot.d.ts +3 -0
  58. package/dist/discovery/json-snapshot.d.ts.map +1 -0
  59. package/dist/discovery/json-snapshot.js +11 -0
  60. package/dist/discovery/lexical.d.ts +12 -0
  61. package/dist/discovery/lexical.d.ts.map +1 -0
  62. package/dist/discovery/lexical.js +26 -0
  63. package/dist/discovery/metadata.d.ts +4 -0
  64. package/dist/discovery/metadata.d.ts.map +1 -0
  65. package/dist/discovery/metadata.js +33 -0
  66. package/dist/discovery/ranking.d.ts +7 -0
  67. package/dist/discovery/ranking.d.ts.map +1 -0
  68. package/dist/discovery/ranking.js +68 -0
  69. package/dist/discovery/replay.d.ts +50 -0
  70. package/dist/discovery/replay.d.ts.map +1 -0
  71. package/dist/discovery/replay.js +175 -0
  72. package/dist/discovery/retrieval-policy.d.ts +5 -0
  73. package/dist/discovery/retrieval-policy.d.ts.map +1 -0
  74. package/dist/discovery/retrieval-policy.js +10 -0
  75. package/dist/discovery/router.d.ts +39 -0
  76. package/dist/discovery/router.d.ts.map +1 -0
  77. package/dist/discovery/router.js +98 -0
  78. package/dist/discovery/selection-attempt.d.ts +20 -0
  79. package/dist/discovery/selection-attempt.d.ts.map +1 -0
  80. package/dist/discovery/selection-attempt.js +39 -0
  81. package/dist/discovery/selection-cards.d.ts +12 -0
  82. package/dist/discovery/selection-cards.d.ts.map +1 -0
  83. package/dist/discovery/selection-cards.js +79 -0
  84. package/dist/discovery/selection-configuration.d.ts +18 -0
  85. package/dist/discovery/selection-configuration.d.ts.map +1 -0
  86. package/dist/discovery/selection-configuration.js +71 -0
  87. package/dist/discovery/selection-response.d.ts +13 -0
  88. package/dist/discovery/selection-response.d.ts.map +1 -0
  89. package/dist/discovery/selection-response.js +47 -0
  90. package/dist/discovery/selection-types.d.ts +18 -0
  91. package/dist/discovery/selection-types.d.ts.map +1 -0
  92. package/dist/discovery/selection-types.js +1 -0
  93. package/dist/discovery/selection.d.ts +6 -0
  94. package/dist/discovery/selection.d.ts.map +1 -0
  95. package/dist/discovery/selection.js +145 -0
  96. package/dist/discovery/types.d.ts +291 -0
  97. package/dist/discovery/types.d.ts.map +1 -0
  98. package/dist/discovery/types.js +1 -0
  99. package/dist/discovery/usage.d.ts +2 -0
  100. package/dist/discovery/usage.d.ts.map +1 -0
  101. package/dist/discovery/usage.js +1 -0
  102. package/dist/discovery/vectors.d.ts +5 -0
  103. package/dist/discovery/vectors.d.ts.map +1 -0
  104. package/dist/discovery/vectors.js +43 -0
  105. package/dist/discovery/versions.d.ts +37 -0
  106. package/dist/discovery/versions.d.ts.map +1 -0
  107. package/dist/discovery/versions.js +36 -0
  108. package/dist/evals-live/live-eval-runner.d.ts +1 -0
  109. package/dist/evals-live/live-eval-runner.d.ts.map +1 -1
  110. package/dist/evals-live/live-eval-runner.js +12 -1
  111. package/dist/evals-live/types.d.ts +3 -0
  112. package/dist/evals-live/types.d.ts.map +1 -1
  113. package/dist/generated/manifest-types.d.ts +3655 -0
  114. package/dist/generated/manifest-types.d.ts.map +1 -1
  115. package/dist/loader.d.ts.map +1 -1
  116. package/dist/loader.js +8 -0
  117. package/dist/mcp-server/server.d.ts.map +1 -1
  118. package/dist/mcp-server/server.js +11 -2
  119. package/dist/mcp-server/types.d.ts +4 -0
  120. package/dist/mcp-server/types.d.ts.map +1 -1
  121. package/dist/observability/redaction.d.ts.map +1 -1
  122. package/dist/observability/redaction.js +6 -2
  123. package/dist/observability/types.d.ts +1 -1
  124. package/dist/observability/types.d.ts.map +1 -1
  125. package/dist/openai/index.d.ts +2 -0
  126. package/dist/openai/index.d.ts.map +1 -1
  127. package/dist/openai/index.js +1 -0
  128. package/dist/openai/responses-runner.d.ts +1 -1
  129. package/dist/openai/responses-runner.d.ts.map +1 -1
  130. package/dist/openai/responses-runner.js +134 -7
  131. package/dist/openai/selection-client.d.ts +28 -0
  132. package/dist/openai/selection-client.d.ts.map +1 -0
  133. package/dist/openai/selection-client.js +95 -0
  134. package/dist/openai/tool-loop.js +1 -1
  135. package/dist/openai/types.d.ts +19 -2
  136. package/dist/openai/types.d.ts.map +1 -1
  137. package/dist/replay/discovery-snapshot.d.ts +10 -0
  138. package/dist/replay/discovery-snapshot.d.ts.map +1 -0
  139. package/dist/replay/discovery-snapshot.js +17 -0
  140. package/dist/replay/recorder.d.ts.map +1 -1
  141. package/dist/replay/recorder.js +4 -0
  142. package/dist/replay/redaction.js +5 -1
  143. package/dist/replay/replayer.d.ts.map +1 -1
  144. package/dist/replay/replayer.js +14 -1
  145. package/dist/replay/types.d.ts +3 -0
  146. package/dist/replay/types.d.ts.map +1 -1
  147. package/dist/replay/validation.d.ts.map +1 -1
  148. package/dist/replay/validation.js +6 -0
  149. package/dist/runtime/bounded-json.d.ts +4 -0
  150. package/dist/runtime/bounded-json.d.ts.map +1 -0
  151. package/dist/runtime/bounded-json.js +74 -0
  152. package/dist/runtime/eligibility.d.ts +4 -0
  153. package/dist/runtime/eligibility.d.ts.map +1 -0
  154. package/dist/runtime/eligibility.js +128 -0
  155. package/dist/runtime/index.d.ts +5 -1
  156. package/dist/runtime/index.d.ts.map +1 -1
  157. package/dist/runtime/index.js +2 -0
  158. package/dist/runtime/provider-attempt.d.ts +11 -0
  159. package/dist/runtime/provider-attempt.d.ts.map +1 -0
  160. package/dist/runtime/provider-attempt.js +221 -0
  161. package/dist/runtime/provider-run.d.ts +10 -0
  162. package/dist/runtime/provider-run.d.ts.map +1 -0
  163. package/dist/runtime/provider-run.js +123 -0
  164. package/dist/runtime/provider-stop.d.ts +9 -0
  165. package/dist/runtime/provider-stop.d.ts.map +1 -0
  166. package/dist/runtime/provider-stop.js +28 -0
  167. package/dist/runtime/provider-types.d.ts +189 -0
  168. package/dist/runtime/provider-types.d.ts.map +1 -0
  169. package/dist/runtime/provider-types.js +1 -0
  170. package/dist/runtime/provider-usage.d.ts +9 -0
  171. package/dist/runtime/provider-usage.d.ts.map +1 -0
  172. package/dist/runtime/provider-usage.js +69 -0
  173. package/dist/runtime/router.d.ts.map +1 -1
  174. package/dist/runtime/router.js +3 -118
  175. package/dist/runtime/types.d.ts +9 -0
  176. package/dist/runtime/types.d.ts.map +1 -1
  177. package/dist/types.d.ts +1 -1
  178. package/dist/types.d.ts.map +1 -1
  179. package/dist/validator.d.ts +3 -0
  180. package/dist/validator.d.ts.map +1 -1
  181. package/dist/validator.js +32 -0
  182. package/docs/api/public-api-policy.md +10 -0
  183. package/docs/api/stable-workflow.md +58 -0
  184. package/docs/api.md +7 -0
  185. package/docs/capability-manifests.md +24 -0
  186. package/docs/development.md +22 -0
  187. package/docs/discovery.md +186 -0
  188. package/docs/evals/discovery-live.md +199 -0
  189. package/docs/evals/discovery-qualification.md +158 -0
  190. package/docs/evals/overview.md +9 -0
  191. package/docs/getting-started/installation.md +11 -12
  192. package/docs/getting-started/openai-quickstart.md +16 -5
  193. package/docs/getting-started/provider-neutral-quickstart.md +247 -88
  194. package/docs/getting-started/quickstart.md +8 -30
  195. package/docs/index.md +10 -0
  196. package/docs/release.md +29 -5
  197. package/docs/runtime.md +27 -0
  198. package/docs/start-here.md +23 -134
  199. package/examples/12-capability-discovery-selection/README.md +346 -0
  200. package/examples/12-capability-discovery-selection/customer-cases.mjs +52 -0
  201. package/examples/12-capability-discovery-selection/customer-harness.mjs +91 -0
  202. package/examples/12-capability-discovery-selection/customer-request-example.mjs +320 -0
  203. package/examples/12-capability-discovery-selection/discovery-example.mjs +175 -0
  204. package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.suite.json +7887 -0
  205. package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.v2.suite.json +8167 -0
  206. package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.v3.suite.json +8342 -0
  207. package/examples/12-capability-discovery-selection/evaluation/application.mjs +305 -0
  208. package/examples/12-capability-discovery-selection/evaluation/campaign.mjs +248 -0
  209. package/examples/12-capability-discovery-selection/evaluation/clients.mjs +433 -0
  210. package/examples/12-capability-discovery-selection/evaluation/continuation.mjs +208 -0
  211. package/examples/12-capability-discovery-selection/evaluation/durable-budget.mjs +420 -0
  212. package/examples/12-capability-discovery-selection/evaluation/freeze.mjs +9 -0
  213. package/examples/12-capability-discovery-selection/evaluation/harness.mjs +618 -0
  214. package/examples/12-capability-discovery-selection/evaluation/mock-host.mjs +260 -0
  215. package/examples/12-capability-discovery-selection/evaluation/preflight.mjs +115 -0
  216. package/examples/12-capability-discovery-selection/evaluation/qualification-workflows.mjs +87 -0
  217. package/examples/12-capability-discovery-selection/evaluation/regrade.mjs +281 -0
  218. package/examples/12-capability-discovery-selection/evaluation/report.mjs +517 -0
  219. package/examples/12-capability-discovery-selection/evaluation/runner.mjs +613 -0
  220. package/examples/12-capability-discovery-selection/evaluation/saved-campaign.mjs +385 -0
  221. package/examples/12-capability-discovery-selection/evaluation/wording.mjs +115 -0
  222. package/examples/12-capability-discovery-selection/evaluation/workflow-application.mjs +378 -0
  223. package/examples/12-capability-discovery-selection/evaluation/workflow-cases.mjs +90 -0
  224. package/examples/12-capability-discovery-selection/evaluation-example.mjs +154 -0
  225. package/examples/12-capability-discovery-selection/hybrid-example.mjs +174 -0
  226. package/examples/12-capability-discovery-selection/mock-embeddings.mjs +101 -0
  227. package/examples/12-capability-discovery-selection/mock-selection.mjs +78 -0
  228. package/examples/12-capability-discovery-selection/pipeline-example.mjs +496 -0
  229. package/examples/12-capability-discovery-selection/retrieval-cases.mjs +31 -0
  230. package/examples/12-capability-discovery-selection/run-campaign-mock.mjs +40 -0
  231. package/examples/12-capability-discovery-selection/run-customer-mock.mjs +15 -0
  232. package/examples/12-capability-discovery-selection/run-evaluation-live.mjs +10 -0
  233. package/examples/12-capability-discovery-selection/run-evaluation-mock.mjs +3 -0
  234. package/examples/12-capability-discovery-selection/run-evaluation-regrade.mjs +71 -0
  235. package/examples/12-capability-discovery-selection/run-hybrid-mock.mjs +3 -0
  236. package/examples/12-capability-discovery-selection/run-mock.mjs +3 -0
  237. package/examples/12-capability-discovery-selection/run-pipeline-mock.mjs +2 -0
  238. package/examples/12-capability-discovery-selection/run-selector-mock.mjs +3 -0
  239. package/examples/12-capability-discovery-selection/selection-example.mjs +88 -0
  240. package/package.json +17 -4
  241. package/schemas/discovery/embedding-index.schema.json +71 -0
  242. package/schemas/discovery/eval-observations.schema.json +409 -0
  243. package/schemas/discovery/eval-suite.schema.json +375 -0
  244. package/schemas/discovery/metadata.schema.json +30 -0
  245. package/schemas/discovery/selection-response.schema.json +47 -0
  246. package/schemas/replay/discovery-snapshot.schema.json +335 -0
@@ -0,0 +1,117 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { fileURLToPath } from "node:url";
3
+ import Ajv2020 from "ajv/dist/2020.js";
4
+ import { ordinalCompare } from "./corpus.js";
5
+ import { DiscoveryError } from "./diagnostics.js";
6
+ import { resolveEmbeddingConfiguration, resolveIndexLimits } from "./embedding-configuration.js";
7
+ import { canonicalizeDiscoveryValue, fingerprintDiscoveryValue, hashDiscoveryContent } from "./fingerprint.js";
8
+ import { boundedJsonSnapshot, deepFreeze } from "./json-snapshot.js";
9
+ import { validVector } from "./vectors.js";
10
+ import { ownValue } from "./usage.js";
11
+ let schemaValidator;
12
+ export function embeddingIndexFingerprint(index) {
13
+ return fingerprintDiscoveryValue("index", {
14
+ schemaVersion: index.schemaVersion, projectionVersion: index.projectionVersion, mock: index.mock,
15
+ registrySourceFingerprint: index.registrySourceFingerprint, corpusFingerprint: index.corpusFingerprint,
16
+ embedding: index.embedding, embeddingConfigurationFingerprint: index.embeddingConfigurationFingerprint,
17
+ vectorDimension: index.vectorDimension,
18
+ entries: [...index.entries].sort((a, b) => ordinalCompare(a.capabilityId, b.capabilityId))
19
+ .map(({ capabilityId, capabilityVersion, documentHash, vectorHash }) => ({ capabilityId, capabilityVersion, documentHash, vectorHash }))
20
+ });
21
+ }
22
+ export function validateCapabilityEmbeddingIndex(value, expected) {
23
+ let code = "invalid_index";
24
+ try {
25
+ const limits = resolveIndexLimits(expected.limits);
26
+ const configuration = resolveEmbeddingConfiguration(expected.configuration);
27
+ const rawEntries = ownValue(value, "entries");
28
+ const rawDimension = ownValue(value, "vectorDimension");
29
+ if (!Array.isArray(rawEntries) || rawEntries.length > limits.maxEntries
30
+ || typeof rawDimension !== "number" || !Number.isSafeInteger(rawDimension) || rawDimension < 1
31
+ || rawDimension > limits.maxVectorDimension)
32
+ throw new Error();
33
+ for (const entry of rawEntries) {
34
+ const vector = ownValue(entry, "vector");
35
+ if (!Array.isArray(vector) || vector.length !== rawDimension)
36
+ throw new Error();
37
+ }
38
+ const snapshot = boundedJsonSnapshot(value, limits.maxArtifactBytes);
39
+ schemaValidator ??= new Ajv2020({ strict: false }).compile(JSON.parse(readFileSync(fileURLToPath(new URL("../../schemas/discovery/embedding-index.schema.json", import.meta.url)), "utf8")));
40
+ if (!schemaValidator(snapshot))
41
+ throw new Error();
42
+ const index = snapshot;
43
+ if (index.entries.length > limits.maxEntries || index.vectorDimension > limits.maxVectorDimension
44
+ || expected.corpus.documents.length !== index.entries.length
45
+ || new Date(index.builtAt).toISOString() !== index.builtAt
46
+ || index.projectionVersion !== expected.corpus.projectionVersion
47
+ || index.registrySourceFingerprint !== expected.corpus.registrySourceFingerprint
48
+ || index.corpusFingerprint !== expected.corpus.corpusFingerprint)
49
+ throw new Error();
50
+ const embeddingFingerprint = fingerprintDiscoveryValue("embedding_configuration", configuration);
51
+ if (canonicalizeDiscoveryValue(index.embedding) !== canonicalizeDiscoveryValue(configuration)
52
+ || index.embeddingConfigurationFingerprint !== embeddingFingerprint || index.mock !== expected.mock
53
+ || configuration.dimensions !== undefined && configuration.dimensions !== index.vectorDimension) {
54
+ code = "embedding_configuration_mismatch";
55
+ throw new Error();
56
+ }
57
+ const documents = new Map(expected.corpus.documents.map(document => [document.capabilityId, document]));
58
+ if (documents.size !== expected.corpus.documents.length)
59
+ throw new Error();
60
+ const seen = new Set();
61
+ for (const entry of index.entries) {
62
+ const document = documents.get(entry.capabilityId);
63
+ if (!document || seen.has(entry.capabilityId) || entry.capabilityVersion !== document.capabilityVersion
64
+ || entry.documentHash !== document.documentHash || !validVector(entry.vector, index.vectorDimension)
65
+ || entry.vectorHash !== hashDiscoveryContent(entry.vector))
66
+ throw new Error();
67
+ seen.add(entry.capabilityId);
68
+ }
69
+ if (index.indexFingerprint !== embeddingIndexFingerprint(index))
70
+ throw new Error();
71
+ index.entries.sort((a, b) => ordinalCompare(a.capabilityId, b.capabilityId));
72
+ return { valid: true, index: deepFreeze(index), diagnostics: [] };
73
+ }
74
+ catch {
75
+ return { valid: false, diagnostics: [{ code, message: code === "invalid_index"
76
+ ? "The embedding index is invalid, oversized, incomplete, or stale."
77
+ : "The embedding index and caller embedding configuration are incompatible." }] };
78
+ }
79
+ }
80
+ export function serializeCapabilityEmbeddingIndex(value, expected) {
81
+ const validated = validateCapabilityEmbeddingIndex(value, expected);
82
+ if (!validated.valid)
83
+ throw new DiscoveryError(validated.diagnostics[0]);
84
+ return canonicalizeDiscoveryValue(validated.index);
85
+ }
86
+ export function parseCapabilityEmbeddingIndex(text, expected) {
87
+ try {
88
+ const limits = resolveIndexLimits(expected.limits);
89
+ if (typeof text !== "string" || Buffer.byteLength(text) > limits.maxArtifactBytes)
90
+ throw new Error();
91
+ return validateCapabilityEmbeddingIndex(JSON.parse(text), expected);
92
+ }
93
+ catch {
94
+ return { valid: false, diagnostics: [{ code: "invalid_index", message: "The serialized embedding index is invalid or oversized." }] };
95
+ }
96
+ }
97
+ export async function loadCapabilityEmbeddingIndex(store, key, expected) {
98
+ try {
99
+ const value = await store.read(key);
100
+ return parseCapabilityEmbeddingIndex(value, expected);
101
+ }
102
+ catch {
103
+ return { valid: false, diagnostics: [{ code: "invalid_index", message: "The embedding index could not be loaded." }] };
104
+ }
105
+ }
106
+ export async function publishCapabilityEmbeddingIndex(store, key, value, expected) {
107
+ const result = validateCapabilityEmbeddingIndex(value, expected);
108
+ if (!result.valid)
109
+ return { published: false, diagnostics: result.diagnostics };
110
+ try {
111
+ await store.replace(key, canonicalizeDiscoveryValue(result.index));
112
+ return { published: true, diagnostics: [] };
113
+ }
114
+ catch {
115
+ return { published: false, diagnostics: [{ code: "invalid_index", message: "The complete embedding index could not be published." }] };
116
+ }
117
+ }
@@ -0,0 +1,32 @@
1
+ /** Stable lexical/native facade; advanced APIs retain their documented maturity. */
2
+ export { ModelCapabilitySelector } from "./selection.js";
3
+ export { buildCapabilitySelectionTasks } from "./selection-cards.js";
4
+ export type { BuildCapabilitySelectionTasksRequest } from "./selection-cards.js";
5
+ export type { CapabilitySelectRequest } from "./selection-types.js";
6
+ export { createCapabilityDiscovery, DISCOVERY_STANDARD_PROFILE } from "./facade.js";
7
+ export type { CapabilityDiscovery, CapabilityDiscoveryOptions, CapabilityDiscoveryEmbeddingOptions, CapabilitySearchRequest, CapabilityDiscoveryEligibility, CapabilityResultRouter } from "./facade.js";
8
+ export { createInMemoryDiscoveryBudget } from "./budget.js";
9
+ export type { DiscoveryBudgetScope, InMemoryDiscoveryBudgetOptions } from "./budget.js";
10
+ export { CapabilityDiscoverer } from "./discoverer.js";
11
+ export type { CapabilityDiscovererOptions } from "./discoverer.js";
12
+ export { buildCapabilityEmbeddingIndex } from "./index-builder.js";
13
+ export { validateCapabilityEmbeddingIndex, serializeCapabilityEmbeddingIndex, parseCapabilityEmbeddingIndex, loadCapabilityEmbeddingIndex, publishCapabilityEmbeddingIndex } from "./index-validation.js";
14
+ export { aggregateDiscoveryUsage } from "./usage.js";
15
+ export type { DeepReadonly, CapabilityEmbeddingIndex, EmbeddingIndexLimits, EmbeddingCallLimits, EmbeddingExecutionOptions, HybridDiscoveryDependencies, EmbeddingIndexExpected, EmbeddingIndexValidationResult, CapabilityEmbeddingIndexBuildRequest, CapabilityEmbeddingIndexBuildResult, CapabilityEmbeddingIndexStore } from "./embedding-types.js";
16
+ export { buildCapabilitySearchCorpus } from "./corpus.js";
17
+ export { RetrievalCapabilityRouter } from "./router.js";
18
+ export type { RetrievalCapabilityRouteRequest, RetrievalCapabilityRouterOptions } from "./router.js";
19
+ export { DiscoveryError } from "./diagnostics.js";
20
+ export type { DiscoveryDiagnostic, DiscoveryDiagnosticCode } from "./diagnostics.js";
21
+ export { resolveDiscoveryMetadata } from "./metadata.js";
22
+ export { canonicalizeDiscoveryValue, fingerprintDiscoveryValue, hashDiscoveryContent } from "./fingerprint.js";
23
+ export type { DiscoveryFingerprintKind, DiscoveryFingerprintPayloads, CapabilityVersionBinding } from "./fingerprint.js";
24
+ export { DISCOVERY_BINDING_VERSIONS, DISCOVERY_SCHEMA_VERSION, DISCOVERY_DEFAULT_LIMITS, DISCOVERY_HARD_LIMITS } from "./versions.js";
25
+ export { LEXICAL_TOKENIZER_VERSION, LEXICAL_RANKER_VERSION, tokenizeDiscoveryText } from "./lexical.js";
26
+ export type { DiscoveryLimits, LexicalDiscoveryConfiguration, HybridDiscoveryConfiguration, DiscoveryConfiguration, DiscoveryFragment, DiscoveryQuery, EmbeddingConfiguration, DiscoveryStage, DiscoveryInvocation, CapabilityDiscoveryRequest, RankedCapabilityCandidate, CapabilityDiscoveryResult, CapabilityRetrievalDocument, CapabilitySearchCorpus, ResolvedLexicalDiscoveryConfiguration, ResolvedHybridDiscoveryConfiguration, ResolvedDiscoveryConfiguration, LexicalRankerCandidate, CapabilityLexicalRanker, DiscoveryBudgetReservation, DiscoveryBudgetLedger, ProviderAttemptContext, EmbeddingClient, DiscoveryProviderFailure, DiscoveryProviderError, SelectionMessage, SelectionModelClient, CapabilityCandidateCard, CapabilitySelectionInputTask, SelectionTask, SelectionLimits, CapabilitySelectionRequest, SelectionDecision, SelectionResponse, CapabilitySelectionBatchResult, CapabilitySelectionOutcome, DiscoveryRouteResult, ResolvedDiscoveryMetadata, DiscoveryMetadata, ProviderModelConfiguration, ModelUsage, UsageQuantity, DiscoveryUsageTotals, DiscoveryStageUsage, DiscoveryUsage, ProviderAttemptReservation, ProviderAttemptSettlement } from "./types.js";
27
+ export { createDiscoverySnapshot, validateDiscoverySnapshot, replayDiscoverySnapshot, createDiscoveryReplayHandler } from "./replay.js";
28
+ export type { DiscoverySnapshotInput, DiscoveryReplayFixtures, DiscoveryReplayResult } from "./replay.js";
29
+ export type { CapabilityEmbeddingIndexArtifact, CapabilityDiscoverySnapshot } from "../generated/manifest-types.js";
30
+ export { evaluateCapabilityDiscovery, fingerprintDiscoveryEvaluationSuite } from "./evaluation.js";
31
+ export type { DiscoveryEvaluationSuite, DiscoveryEvaluationObservations, DiscoveryEvaluationRate, DiscoveryEvaluationDistribution, DiscoveryEvaluationReport, DiscoveryEvaluationResult, EvaluateCapabilityDiscoveryRequest, DiscoveryEvaluationDiagnostic } from "./evaluation.js";
32
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/discovery/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Stable lexical/native facade; advanced APIs retain their documented maturity. */
2
+ export { ModelCapabilitySelector } from "./selection.js";
3
+ export { buildCapabilitySelectionTasks } from "./selection-cards.js";
4
+ export { createCapabilityDiscovery, DISCOVERY_STANDARD_PROFILE } from "./facade.js";
5
+ export { createInMemoryDiscoveryBudget } from "./budget.js";
6
+ export { CapabilityDiscoverer } from "./discoverer.js";
7
+ export { buildCapabilityEmbeddingIndex } from "./index-builder.js";
8
+ export { validateCapabilityEmbeddingIndex, serializeCapabilityEmbeddingIndex, parseCapabilityEmbeddingIndex, loadCapabilityEmbeddingIndex, publishCapabilityEmbeddingIndex } from "./index-validation.js";
9
+ export { aggregateDiscoveryUsage } from "./usage.js";
10
+ export { buildCapabilitySearchCorpus } from "./corpus.js";
11
+ export { RetrievalCapabilityRouter } from "./router.js";
12
+ export { DiscoveryError } from "./diagnostics.js";
13
+ export { resolveDiscoveryMetadata } from "./metadata.js";
14
+ export { canonicalizeDiscoveryValue, fingerprintDiscoveryValue, hashDiscoveryContent } from "./fingerprint.js";
15
+ export { DISCOVERY_BINDING_VERSIONS, DISCOVERY_SCHEMA_VERSION, DISCOVERY_DEFAULT_LIMITS, DISCOVERY_HARD_LIMITS } from "./versions.js";
16
+ export { LEXICAL_TOKENIZER_VERSION, LEXICAL_RANKER_VERSION, tokenizeDiscoveryText } from "./lexical.js";
17
+ export { createDiscoverySnapshot, validateDiscoverySnapshot, replayDiscoverySnapshot, createDiscoveryReplayHandler } from "./replay.js";
18
+ export { evaluateCapabilityDiscovery, fingerprintDiscoveryEvaluationSuite } from "./evaluation.js";
@@ -0,0 +1,3 @@
1
+ export { deepFreeze } from "../runtime/bounded-json.js";
2
+ export declare function boundedJsonSnapshot(value: unknown, maxBytes: number): unknown;
3
+ //# sourceMappingURL=json-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-snapshot.d.ts","sourceRoot":"","sources":["../../src/discovery/json-snapshot.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAG7E"}
@@ -0,0 +1,11 @@
1
+ import { DiscoveryError } from "./diagnostics.js";
2
+ import { boundedJsonSnapshot as snapshot } from "../runtime/bounded-json.js";
3
+ export { deepFreeze } from "../runtime/bounded-json.js";
4
+ export function boundedJsonSnapshot(value, maxBytes) {
5
+ try {
6
+ return snapshot(value, maxBytes);
7
+ }
8
+ catch {
9
+ throw new DiscoveryError({ code: "invalid_index", message: "Embedding artifacts require bounded, finite JSON data." });
10
+ }
11
+ }
@@ -0,0 +1,12 @@
1
+ import type { CapabilityRetrievalDocument, DiscoveryQuery, LexicalRankerCandidate, ResolvedLexicalDiscoveryConfiguration } from "./types.js";
2
+ /** NFKC plus ECMAScript lowercase, not linguistic case folding or word segmentation. */
3
+ export declare const LEXICAL_TOKENIZER_VERSION = "nfkc-lower-unicode-letter-number.v1";
4
+ export declare const LEXICAL_RANKER_VERSION = "coverage-alias.v1";
5
+ export declare function tokenizeDiscoveryText(text: string): string[];
6
+ export declare function matchingAliases(query: DiscoveryQuery, document: CapabilityRetrievalDocument): string[];
7
+ export declare function rankLexically(input: {
8
+ query: DiscoveryQuery;
9
+ documents: readonly CapabilityRetrievalDocument[];
10
+ configuration: ResolvedLexicalDiscoveryConfiguration;
11
+ }): LexicalRankerCandidate[];
12
+ //# sourceMappingURL=lexical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexical.d.ts","sourceRoot":"","sources":["../../src/discovery/lexical.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,2BAA2B,EAAE,cAAc,EAAE,sBAAsB,EAAE,qCAAqC,EAC3G,MAAM,YAAY,CAAC;AAEpB,wFAAwF;AACxF,eAAO,MAAM,yBAAyB,wCAAwC,CAAC;AAC/E,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAE1D,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE5D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,2BAA2B,GAAG,MAAM,EAAE,CAOtG;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,SAAS,2BAA2B,EAAE,CAAC;IAClD,aAAa,EAAE,qCAAqC,CAAC;CACtD,GAAG,sBAAsB,EAAE,CAY3B"}
@@ -0,0 +1,26 @@
1
+ /** NFKC plus ECMAScript lowercase, not linguistic case folding or word segmentation. */
2
+ export const LEXICAL_TOKENIZER_VERSION = "nfkc-lower-unicode-letter-number.v1";
3
+ export const LEXICAL_RANKER_VERSION = "coverage-alias.v1";
4
+ export function tokenizeDiscoveryText(text) {
5
+ return text.normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
6
+ }
7
+ export function matchingAliases(query, document) {
8
+ const fragments = query.fragments.map((fragment) => tokenizeDiscoveryText(fragment.text));
9
+ return document.aliases.filter((alias) => {
10
+ const phrase = tokenizeDiscoveryText(alias);
11
+ return phrase.length >= 2 && fragments.some((fragment) => fragment.some((_, start) => phrase.every((token, offset) => fragment[start + offset] === token)));
12
+ });
13
+ }
14
+ export function rankLexically(input) {
15
+ const queryTokens = [...new Set(input.query.fragments.flatMap((fragment) => tokenizeDiscoveryText(fragment.text)))];
16
+ return input.documents.map((document) => {
17
+ const tokens = new Set(document.tokens);
18
+ const coverage = queryTokens.length ? queryTokens.filter((token) => tokens.has(token)).length / queryTokens.length : 0;
19
+ const phrase = matchingAliases(input.query, document).length ? 1 : 0;
20
+ const lexical = coverage + (1 - coverage) * input.configuration.aliasWeight * phrase;
21
+ return {
22
+ capabilityId: document.capabilityId,
23
+ scores: { lexical, aliasPhrase: phrase, semantic: null, final: lexical }
24
+ };
25
+ });
26
+ }
@@ -0,0 +1,4 @@
1
+ import type { CapabilityManifest } from "../types.js";
2
+ import type { ResolvedDiscoveryMetadata } from "./types.js";
3
+ export declare function resolveDiscoveryMetadata(manifest: CapabilityManifest): ResolvedDiscoveryMetadata;
4
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/discovery/metadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5D,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,kBAAkB,GAAG,yBAAyB,CAiChG"}
@@ -0,0 +1,33 @@
1
+ import { validateDiscoveryMetadata } from "../validator.js";
2
+ import { DiscoveryError } from "./diagnostics.js";
3
+ export function resolveDiscoveryMetadata(manifest) {
4
+ const extensions = manifest.extensions;
5
+ if (!extensions || !Object.prototype.hasOwnProperty.call(extensions, "discovery")) {
6
+ return { schemaVersion: "1.0", summary: manifest.summary, aliases: [] };
7
+ }
8
+ const value = extensions.discovery;
9
+ const errors = validateDiscoveryMetadata(value);
10
+ if (errors.length > 0) {
11
+ throw new DiscoveryError({
12
+ code: "invalid_metadata",
13
+ message: "Capability discovery metadata is invalid.",
14
+ capabilityId: manifest.id,
15
+ path: errors[0]?.instancePath ?? "/extensions/discovery"
16
+ });
17
+ }
18
+ const metadata = value;
19
+ const seen = new Set();
20
+ const aliases = [];
21
+ for (const alias of metadata.aliases ?? []) {
22
+ const key = alias.normalize("NFKC").toLowerCase().trim().replace(/\s+/gu, " ");
23
+ if (!seen.has(key)) {
24
+ seen.add(key);
25
+ aliases.push(alias);
26
+ }
27
+ }
28
+ return {
29
+ schemaVersion: metadata.schema_version,
30
+ summary: metadata.summary ?? manifest.summary,
31
+ aliases
32
+ };
33
+ }
@@ -0,0 +1,7 @@
1
+ import type { CapabilityRetrievalDocument, DiscoveryQuery, RankedCapabilityCandidate, ResolvedLexicalDiscoveryConfiguration } from "./types.js";
2
+ export declare function shortlistCandidates(output: unknown, query: DiscoveryQuery, documents: readonly CapabilityRetrievalDocument[], configuration: ResolvedLexicalDiscoveryConfiguration): RankedCapabilityCandidate[];
3
+ export declare function validateLexicalCandidates(output: unknown, query: DiscoveryQuery, documents: readonly CapabilityRetrievalDocument[], requireEqual?: boolean): RankedCapabilityCandidate[];
4
+ export declare function selectRankedCandidates(candidates: readonly RankedCapabilityCandidate[], documents: readonly CapabilityRetrievalDocument[], configuration: Pick<ResolvedLexicalDiscoveryConfiguration, "limits" | "minRetrievalScore">): RankedCapabilityCandidate[];
5
+ /** Pure semantic channel shared by serving and authorized offline ranking replay. */
6
+ export declare function rankHybridCandidates(candidates: readonly RankedCapabilityCandidate[], queryVector: readonly number[], vectors: ReadonlyMap<string, readonly number[]>, documents: readonly CapabilityRetrievalDocument[], configuration: import("./types.js").ResolvedHybridDiscoveryConfiguration): RankedCapabilityCandidate[];
7
+ //# sourceMappingURL=ranking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranking.d.ts","sourceRoot":"","sources":["../../src/discovery/ranking.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,2BAA2B,EAAE,cAAc,EAAE,yBAAyB,EAAE,qCAAqC,EAC9G,MAAM,YAAY,CAAC;AAIpB,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,2BAA2B,EAAE,EACzF,aAAa,EAAE,qCAAqC,GACnD,yBAAyB,EAAE,CAE7B;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,SAAS,2BAA2B,EAAE,EAAE,YAAY,UAAQ,GAC9G,yBAAyB,EAAE,CA8B7B;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,SAAS,yBAAyB,EAAE,EAAE,SAAS,EAAE,SAAS,2BAA2B,EAAE,EACnG,aAAa,EAAE,IAAI,CAAC,qCAAqC,EAAE,QAAQ,GAAG,mBAAmB,CAAC,GACzF,yBAAyB,EAAE,CAa7B;AAED,qFAAqF;AACrF,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,SAAS,yBAAyB,EAAE,EAAE,WAAW,EAAE,SAAS,MAAM,EAAE,EAChF,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,SAAS,2BAA2B,EAAE,EAClG,aAAa,EAAE,OAAO,YAAY,EAAE,oCAAoC,GACvE,yBAAyB,EAAE,CAO7B"}
@@ -0,0 +1,68 @@
1
+ import { semanticSimilarity } from "./vectors.js";
2
+ import { hasOnlyKeys, isRecord, unitScore } from "./configuration.js";
3
+ import { ordinalCompare } from "./corpus.js";
4
+ import { DiscoveryError } from "./diagnostics.js";
5
+ import { matchingAliases } from "./lexical.js";
6
+ const riskRank = { none: 0, low: 1, medium: 2, high: 3, critical: 4 };
7
+ export function shortlistCandidates(output, query, documents, configuration) {
8
+ return selectRankedCandidates(validateLexicalCandidates(output, query, documents), documents, configuration);
9
+ }
10
+ export function validateLexicalCandidates(output, query, documents, requireEqual = false) {
11
+ const invalid = () => new DiscoveryError({
12
+ code: "invalid_ranker_output", message: "The lexical ranker did not return valid eligible scores."
13
+ });
14
+ const byId = new Map(documents.map((document) => [document.capabilityId, document]));
15
+ if (!Array.isArray(output) || output.length > documents.length) {
16
+ // An invalid async implementation must not leave a rejected Promise unobserved.
17
+ if (output instanceof Promise)
18
+ void output.catch(() => undefined);
19
+ throw invalid();
20
+ }
21
+ const ids = new Set();
22
+ const admitted = [];
23
+ for (const entry of output) {
24
+ if (!isRecord(entry) || !hasOnlyKeys(entry, ["capabilityId", "scores"])
25
+ || typeof entry.capabilityId !== "string" || ids.has(entry.capabilityId))
26
+ throw invalid();
27
+ const document = byId.get(entry.capabilityId);
28
+ const scores = entry.scores;
29
+ if (!document || !isRecord(scores) || !hasOnlyKeys(scores, ["lexical", "aliasPhrase", "semantic", "final"])
30
+ || !unitScore(scores.lexical) || !unitScore(scores.final) || scores.semantic !== null
31
+ || (scores.aliasPhrase !== 0 && scores.aliasPhrase !== 1))
32
+ throw invalid();
33
+ const aliases = matchingAliases(query, document);
34
+ if (scores.aliasPhrase !== (aliases.length ? 1 : 0) || requireEqual && scores.final !== scores.lexical)
35
+ throw invalid();
36
+ ids.add(entry.capabilityId);
37
+ admitted.push({
38
+ capabilityId: document.capabilityId, capabilityVersion: document.capabilityVersion, rank: 0,
39
+ scores: { lexical: scores.lexical, aliasPhrase: scores.aliasPhrase, semantic: null, final: scores.final },
40
+ matchedAliases: aliases, inclusionReason: "aggregate_ranking"
41
+ });
42
+ }
43
+ return admitted;
44
+ }
45
+ export function selectRankedCandidates(candidates, documents, configuration) {
46
+ const byId = new Map(documents.map(document => [document.capabilityId, document]));
47
+ const admitted = candidates.filter(candidate => candidate.scores.final > 0 && candidate.scores.final >= configuration.minRetrievalScore);
48
+ admitted.sort((left, right) => right.scores.final - left.scores.final
49
+ || riskRank[byId.get(left.capabilityId).riskTier] - riskRank[byId.get(right.capabilityId).riskTier]
50
+ || ordinalCompare(left.capabilityId, right.capabilityId));
51
+ const limit = configuration.limits.maxCandidates;
52
+ const selected = admitted.slice(0, limit);
53
+ if (configuration.limits.aliasDiversitySlots === 1 && selected.length === limit) {
54
+ const alternative = admitted.slice(limit).find((candidate) => candidate.matchedAliases.length > 0);
55
+ if (alternative)
56
+ selected.splice(selected.length - 1, 1, { ...alternative, inclusionReason: "alias_diversity" });
57
+ }
58
+ return selected.map((candidate, index) => ({ ...candidate, rank: index + 1 }));
59
+ }
60
+ /** Pure semantic channel shared by serving and authorized offline ranking replay. */
61
+ export function rankHybridCandidates(candidates, queryVector, vectors, documents, configuration) {
62
+ const scored = candidates.map(candidate => {
63
+ const semantic = semanticSimilarity(queryVector, vectors.get(candidate.capabilityId));
64
+ const final = Math.max(0, Math.min(1, configuration.weights.semantic * semantic + configuration.weights.lexical * candidate.scores.lexical));
65
+ return { ...candidate, scores: { ...candidate.scores, semantic, final } };
66
+ });
67
+ return selectRankedCandidates(scored, documents, configuration);
68
+ }
@@ -0,0 +1,50 @@
1
+ import type { CapabilityDiscoverySnapshot } from "../generated/manifest-types.js";
2
+ import type { CapabilityRouteRequest } from "../runtime/types.js";
3
+ import type { ReplayProviderRunner, ReplayStepResult } from "../replay/types.js";
4
+ import type { CapabilityDiscoveryResult, CapabilityLexicalRanker, CapabilitySelectionBatchResult, DiscoveryConfiguration, DiscoveryQuery, EmbeddingConfiguration } from "./types.js";
5
+ import type { EmbeddingIndexLimits } from "./embedding-types.js";
6
+ export interface DiscoverySnapshotInput {
7
+ routeRequest: CapabilityRouteRequest;
8
+ configuration: DiscoveryConfiguration;
9
+ queries: readonly DiscoveryQuery[];
10
+ discovery: readonly CapabilityDiscoveryResult[];
11
+ selection?: CapabilitySelectionBatchResult;
12
+ ranker?: CapabilityLexicalRanker;
13
+ }
14
+ export interface DiscoveryReplayFixtures {
15
+ queries: readonly DiscoveryQuery[];
16
+ ranker?: CapabilityLexicalRanker;
17
+ index?: unknown;
18
+ embedding?: EmbeddingConfiguration;
19
+ mock?: boolean;
20
+ indexLimits?: EmbeddingIndexLimits;
21
+ queryVectors?: Readonly<Record<string, {
22
+ queryHash: string;
23
+ configurationFingerprint: string;
24
+ vector: readonly number[];
25
+ }>>;
26
+ }
27
+ export interface DiscoveryReplayResult {
28
+ status: "passed" | "failed" | "refused";
29
+ mode: "snapshot_validation" | "ranking";
30
+ semanticCorrectnessTested: false;
31
+ steps: readonly ReplayStepResult[];
32
+ }
33
+ export declare function createDiscoverySnapshot(input: DiscoverySnapshotInput): CapabilityDiscoverySnapshot;
34
+ export declare function validateDiscoverySnapshot(value: unknown, routeRequest: CapabilityRouteRequest): {
35
+ valid: true;
36
+ snapshot: CapabilityDiscoverySnapshot;
37
+ } | {
38
+ valid: false;
39
+ };
40
+ export declare function replayDiscoverySnapshot(value: unknown, options: {
41
+ mode: DiscoveryReplayResult["mode"];
42
+ routeRequest: CapabilityRouteRequest;
43
+ fixtures?: DiscoveryReplayFixtures;
44
+ }): DiscoveryReplayResult;
45
+ export declare function createDiscoveryReplayHandler(options: {
46
+ mode: DiscoveryReplayResult["mode"];
47
+ routeRequest: CapabilityRouteRequest;
48
+ fixtures?: DiscoveryReplayFixtures;
49
+ }): ReplayProviderRunner;
50
+ //# sourceMappingURL=replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/discovery/replay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAClF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAajF,OAAO,KAAK,EACV,yBAAyB,EAAE,uBAAuB,EAAE,8BAA8B,EAAE,sBAAsB,EAC1G,cAAc,EAAE,sBAAsB,EACvC,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAGjE,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,sBAAsB,CAAC;IACrC,aAAa,EAAE,sBAAsB,CAAC;IACtC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC,SAAS,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAChD,SAAS,CAAC,EAAE,8BAA8B,CAAC;IAC3C,MAAM,CAAC,EAAE,uBAAuB,CAAC;CAClC;AACD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IACnC,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,wBAAwB,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC,CAAC;CAC7H;AACD,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,IAAI,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACxC,yBAAyB,EAAE,KAAK,CAAC;IACjC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACpC;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,2BAA2B,CA8BlG;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,sBAAsB,GAC5F;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,2BAA2B,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAA;CAAE,CAyC1E;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;IAC/D,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAAC,YAAY,EAAE,sBAAsB,CAAC;IAAC,QAAQ,CAAC,EAAE,uBAAuB,CAAC;CAC/G,GAAG,qBAAqB,CA+CxB;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE;IAAE,IAAI,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC;IAAC,YAAY,EAAE,sBAAsB,CAAC;IAAC,QAAQ,CAAC,EAAE,uBAAuB,CAAA;CAAE,GAAG,oBAAoB,CAS7L"}
@@ -0,0 +1,175 @@
1
+ import { validateDiscoverySnapshotStructure } from "../replay/discovery-snapshot.js";
2
+ import { captureEligibility } from "./bindings.js";
3
+ import { lexicalConfiguration, resolveDiscoveryConfiguration } from "./configuration.js";
4
+ import { buildCapabilitySearchCorpus } from "./corpus.js";
5
+ import { validateQueries } from "./discoverer.js";
6
+ import { DiscoveryError } from "./diagnostics.js";
7
+ import { fingerprintDiscoveryValue, hashDiscoveryContent } from "./fingerprint.js";
8
+ import { validateCapabilityEmbeddingIndex } from "./index-validation.js";
9
+ import { deepFreeze } from "./json-snapshot.js";
10
+ import { LEXICAL_RANKER_VERSION, LEXICAL_TOKENIZER_VERSION, rankLexically, tokenizeDiscoveryText } from "./lexical.js";
11
+ import { rankHybridCandidates, shortlistCandidates, validateLexicalCandidates } from "./ranking.js";
12
+ import { retrievalPolicyFingerprint } from "./retrieval-policy.js";
13
+ import { validVectorBatch } from "./vectors.js";
14
+ export function createDiscoverySnapshot(input) {
15
+ const corpus = buildCapabilitySearchCorpus(input.routeRequest.registry);
16
+ const configuration = resolveDiscoveryConfiguration(input.configuration);
17
+ const queries = validateQueries({ queries: input.queries }, configuration);
18
+ if (queries.length !== input.discovery.length)
19
+ throw invalid();
20
+ const policy = retrievalPolicyFingerprint(configuration, input.ranker?.version);
21
+ const payload = {
22
+ schemaVersion: "1.0", projectionVersion: corpus.projectionVersion, tokenizerVersion: LEXICAL_TOKENIZER_VERSION,
23
+ rankerVersion: input.ranker ? "custom:" + input.ranker.version : LEXICAL_RANKER_VERSION,
24
+ registrySourceFingerprint: corpus.registrySourceFingerprint, corpusFingerprint: corpus.corpusFingerprint,
25
+ retrievalPolicyFingerprint: policy, configuration,
26
+ tasks: input.discovery.map((result, index) => {
27
+ const query = queries[index];
28
+ if (query.id !== result.queryId || result.corpusFingerprint !== corpus.corpusFingerprint || result.retrievalPolicyFingerprint !== policy)
29
+ throw invalid();
30
+ const decision = input.selection?.outcomes.find(outcome => outcome.queryId === query.id);
31
+ return { queryId: query.id, queryHash: queryHash(query), status: result.status, requestedMode: result.requestedMode,
32
+ actualMode: result.actualMode, eligibilityFingerprint: result.eligibilityFingerprint,
33
+ retrievalPolicyFingerprint: result.retrievalPolicyFingerprint,
34
+ ...(result.indexFingerprint ? { indexFingerprint: result.indexFingerprint } : {}),
35
+ ...(result.degradedReason ? { degradedReason: result.degradedReason } : {}),
36
+ reasonCodes: result.diagnostics.map(diagnostic => diagnostic.code), candidates: result.candidates.map(candidateProjection),
37
+ ...(decision ? { selection: { status: decision.status, capabilityId: decision.capabilityId,
38
+ ...(decision.status === "selected" ? { capabilityVersion: decision.capabilityVersion } : {}), reasonCode: decision.reasonCode,
39
+ selectorFingerprint: decision.selectorFingerprint, inputBindingHash: decision.inputBindingHash } } : {}) };
40
+ })
41
+ };
42
+ const result = { ...payload, snapshotFingerprint: snapshotHash(payload) };
43
+ const validated = validateDiscoverySnapshot(result, input.routeRequest);
44
+ if (!validated.valid)
45
+ throw invalid();
46
+ return validated.snapshot;
47
+ }
48
+ export function validateDiscoverySnapshot(value, routeRequest) {
49
+ const shape = validateDiscoverySnapshotStructure(value);
50
+ if (!shape.valid)
51
+ return shape;
52
+ try {
53
+ const snapshot = shape.snapshot, { snapshotFingerprint, ...payload } = snapshot;
54
+ if (snapshotHash(payload) !== snapshotFingerprint)
55
+ return { valid: false };
56
+ const corpus = buildCapabilitySearchCorpus(routeRequest.registry), eligibility = captureEligibility(routeRequest);
57
+ const configuration = resolveDiscoveryConfiguration(snapshot.configuration);
58
+ const custom = snapshot.rankerVersion.startsWith("custom:") ? snapshot.rankerVersion.slice(7) : undefined;
59
+ const policy = retrievalPolicyFingerprint(configuration, custom);
60
+ if (snapshot.registrySourceFingerprint !== corpus.registrySourceFingerprint || snapshot.corpusFingerprint !== corpus.corpusFingerprint
61
+ || snapshot.projectionVersion !== corpus.projectionVersion || snapshot.tokenizerVersion !== LEXICAL_TOKENIZER_VERSION
62
+ || !custom && snapshot.rankerVersion !== LEXICAL_RANKER_VERSION || snapshot.retrievalPolicyFingerprint !== policy)
63
+ return { valid: false };
64
+ const eligible = new Map(eligibility.eligible.map(item => [item.manifest.id, item.manifest.version]));
65
+ const tasks = new Set();
66
+ for (const task of snapshot.tasks) {
67
+ const ids = new Set();
68
+ if (tasks.has(task.queryId) || task.eligibilityFingerprint !== eligibility.fingerprint || task.retrievalPolicyFingerprint !== policy
69
+ || task.requestedMode !== configuration.mode || task.candidates.length > configuration.limits.maxCandidates
70
+ || task.status !== "matched" && task.candidates.length || task.status === "matched" && (!task.candidates.length || task.actualMode === null)
71
+ || ["unavailable", "cancelled"].includes(task.status) && task.actualMode !== null
72
+ || task.actualMode === "hybrid" && task.requestedMode !== "hybrid"
73
+ || task.requestedMode === "hybrid" && task.actualMode === "lexical" && configuration.mode === "hybrid"
74
+ && (configuration.failurePolicy !== "lexical_fallback" || !task.degradedReason))
75
+ return { valid: false };
76
+ tasks.add(task.queryId);
77
+ for (const [index, candidate] of task.candidates.entries()) {
78
+ if (ids.has(candidate.capabilityId) || eligible.get(candidate.capabilityId) !== candidate.capabilityVersion
79
+ || candidate.rank !== index + 1 || candidate.scores.final <= 0 || candidate.scores.final < configuration.minRetrievalScore
80
+ || task.actualMode === "lexical" && candidate.scores.semantic !== null
81
+ || task.actualMode === "hybrid" && (candidate.scores.semantic === null || !task.indexFingerprint))
82
+ return { valid: false };
83
+ ids.add(candidate.capabilityId);
84
+ }
85
+ const selection = task.selection;
86
+ if (selection?.status === "selected") {
87
+ if (!selection.capabilityId || !ids.has(selection.capabilityId) || eligible.get(selection.capabilityId) !== selection.capabilityVersion
88
+ || selection.reasonCode !== "supported_candidate")
89
+ return { valid: false };
90
+ }
91
+ else if (selection && (selection.capabilityId !== null || selection.capabilityVersion !== undefined
92
+ || selection.status === "abstained" && !["no_suitable_candidate", "ambiguous_request", "insufficient_context"].includes(selection.reasonCode)))
93
+ return { valid: false };
94
+ }
95
+ return { valid: true, snapshot };
96
+ }
97
+ catch {
98
+ return { valid: false };
99
+ }
100
+ }
101
+ export function replayDiscoverySnapshot(value, options) {
102
+ const steps = [];
103
+ const finish = (status) => deepFreeze({ status, mode: options.mode,
104
+ semanticCorrectnessTested: false, steps: [...steps, { name: "model_semantic_correctness", status: "skipped", message: "Stored decisions do not establish model semantic correctness." }] });
105
+ const validated = validateDiscoverySnapshot(value, options.routeRequest);
106
+ if (!validated.valid) {
107
+ steps.push({ name: "discovery_snapshot", status: "failed", message: "Snapshot structure, membership or current bindings are incompatible." });
108
+ return finish("failed");
109
+ }
110
+ steps.push({ name: "discovery_snapshot", status: "passed", message: "Snapshot structure, membership and supplied current bindings are valid." });
111
+ if (options.mode === "snapshot_validation") {
112
+ steps.push({ name: "discovery_ranking", status: "skipped", message: "Snapshot validation does not recompute ranking." });
113
+ return finish("passed");
114
+ }
115
+ const snapshot = validated.snapshot, fixtures = options.fixtures;
116
+ try {
117
+ if (!fixtures || snapshot.rankerVersion.startsWith("custom:") && "custom:" + fixtures.ranker?.version !== snapshot.rankerVersion)
118
+ throw invalid();
119
+ const configuration = resolveDiscoveryConfiguration(snapshot.configuration);
120
+ const queries = validateQueries({ queries: fixtures.queries }, configuration);
121
+ if (queries.length !== snapshot.tasks.length)
122
+ throw invalid();
123
+ const corpus = buildCapabilitySearchCorpus(options.routeRequest.registry), eligibility = captureEligibility(options.routeRequest);
124
+ const allowed = new Set(eligibility.eligible.map(item => item.manifest.id));
125
+ const documents = Object.freeze(corpus.documents.filter(document => allowed.has(document.capabilityId)));
126
+ for (const [index, task] of snapshot.tasks.entries()) {
127
+ const query = queries[index];
128
+ if (query.id !== task.queryId || queryHash(query) !== task.queryHash || task.actualMode === null)
129
+ throw invalid();
130
+ const lexical = lexicalConfiguration(configuration);
131
+ const output = () => fixtures.ranker ? fixtures.ranker.rank(Object.freeze({ query, documents, configuration: lexical })) : rankLexically({ query, documents, configuration: lexical });
132
+ let candidates = [];
133
+ if (documents.length && query.fragments.some(fragment => tokenizeDiscoveryText(fragment.text).length)) {
134
+ if (task.actualMode === "lexical")
135
+ candidates = shortlistCandidates(output(), query, documents, lexical);
136
+ else {
137
+ if (configuration.mode !== "hybrid" || !fixtures.embedding || fixtures.mock === undefined || !fixtures.indexLimits)
138
+ throw invalid();
139
+ const artifact = validateCapabilityEmbeddingIndex(fixtures.index, { corpus, configuration: fixtures.embedding, mock: fixtures.mock, limits: fixtures.indexLimits });
140
+ const vector = fixtures.queryVectors?.[query.id];
141
+ if (!artifact.valid || artifact.index.indexFingerprint !== task.indexFingerprint || !vector || vector.queryHash !== task.queryHash
142
+ || vector.configurationFingerprint !== fingerprintDiscoveryValue("embedding_configuration", fixtures.embedding)
143
+ || !validVectorBatch([vector.vector], 1, artifact.index.vectorDimension))
144
+ throw invalid();
145
+ candidates = rankHybridCandidates(validateLexicalCandidates(output(), query, documents, true), vector.vector, new Map(artifact.index.entries.map(entry => [entry.capabilityId, entry.vector])), documents, configuration);
146
+ }
147
+ }
148
+ const same = hashDiscoveryContent(candidates.map(candidateProjection)) === hashDiscoveryContent(task.candidates)
149
+ && (candidates.length ? "matched" : "no_match") === task.status;
150
+ steps.push({ name: "discovery_ranking:" + task.queryId, status: same ? "passed" : "failed", message: same ? "Task ranking matched the recorded candidates and scores." : "Task ranking differs from the recorded candidates or scores." });
151
+ }
152
+ return finish(steps.some(step => step.status === "failed") ? "failed" : "passed");
153
+ }
154
+ catch {
155
+ steps.push({ name: "discovery_ranking", status: "skipped", message: "Compatible authorized query, ranker or vector fixtures were not supplied." });
156
+ return finish("refused");
157
+ }
158
+ }
159
+ export function createDiscoveryReplayHandler(options) {
160
+ return trace => {
161
+ const replay = replayDiscoverySnapshot(trace.extensions?.discovery, options);
162
+ const steps = [...replay.steps];
163
+ return { schemaVersion: "1.0", traceId: trace.traceId, mode: "router_only", status: replay.status, diagnostics: [], steps,
164
+ extensions: { discoveryReplayMode: options.mode, semanticCorrectnessTested: false },
165
+ summary: { total: steps.length, passed: steps.filter(step => step.status === "passed").length,
166
+ failed: steps.filter(step => step.status === "failed").length, skipped: steps.filter(step => step.status === "skipped").length } };
167
+ };
168
+ }
169
+ function candidateProjection(candidate) {
170
+ return { capabilityId: candidate.capabilityId, capabilityVersion: candidate.capabilityVersion, rank: candidate.rank,
171
+ scores: { ...candidate.scores }, inclusionReason: candidate.inclusionReason, matchedAliasHashes: candidate.matchedAliases.map(alias => hashDiscoveryContent(alias)) };
172
+ }
173
+ function queryHash(query) { return hashDiscoveryContent({ query }); }
174
+ function snapshotHash(payload) { return hashDiscoveryContent({ kind: "discovery_snapshot", version: "1.0", payload }); }
175
+ function invalid() { return new DiscoveryError({ code: "replay_inputs_unavailable", message: "Discovery replay requires complete compatible bindings and authorized fixtures." }); }
@@ -0,0 +1,5 @@
1
+ import type { ResolvedDiscoveryConfiguration } from "./types.js";
2
+ export declare const HYBRID_RANKER_VERSION = "weighted-cosine-lexical.v1";
3
+ export declare const QUERY_EMBEDDING_PROJECTION_VERSION = "original-fragments-newline.v1";
4
+ export declare function retrievalPolicyFingerprint(configuration: ResolvedDiscoveryConfiguration, customRankerVersion?: string): string;
5
+ //# sourceMappingURL=retrieval-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retrieval-policy.d.ts","sourceRoot":"","sources":["../../src/discovery/retrieval-policy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AACjE,eAAO,MAAM,qBAAqB,+BAA+B,CAAC;AAClE,eAAO,MAAM,kCAAkC,kCAAkC,CAAC;AAClF,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,8BAA8B,EAAE,mBAAmB,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9H"}