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,261 @@
1
+ import { assertProviderRunScope } from "../runtime/provider-run.js";
2
+ import { retrievalPolicyFingerprint } from "./retrieval-policy.js";
3
+ import { performance } from "node:perf_hooks";
4
+ import { captureEligibility } from "./bindings.js";
5
+ import { hasOnlyKeys, isRecord, lexicalConfiguration, nonblank, resolveDiscoveryConfiguration } from "./configuration.js";
6
+ import { buildCapabilitySearchCorpus, registrySourceFingerprint } from "./corpus.js";
7
+ import { DiscoveryError } from "./diagnostics.js";
8
+ import { checkEmbeddingTexts, invalidEmbeddingConfiguration, resolveEmbeddingConfiguration, resolveEmbeddingExecution, resolveIndexLimits } from "./embedding-configuration.js";
9
+ import { runEmbeddingAttempt, stopReason, validateProviderInvocation } from "./embeddings.js";
10
+ import { validateCapabilityEmbeddingIndex } from "./index-validation.js";
11
+ import { boundedJsonSnapshot, deepFreeze } from "./json-snapshot.js";
12
+ import { rankLexically, tokenizeDiscoveryText } from "./lexical.js";
13
+ import { rankHybridCandidates, shortlistCandidates, validateLexicalCandidates } from "./ranking.js";
14
+ import { aggregateDiscoveryUsage } from "./usage.js";
15
+ export { HYBRID_RANKER_VERSION, QUERY_EMBEDDING_PROJECTION_VERSION } from "./retrieval-policy.js";
16
+ export class CapabilityDiscoverer {
17
+ configuration;
18
+ ranker;
19
+ embedding;
20
+ constructor(configuration, options = {}) {
21
+ this.configuration = resolveDiscoveryConfiguration(configuration);
22
+ if (!isRecord(options) || !hasOnlyKeys(options, ["ranker", "embedding"])
23
+ || (options.ranker !== undefined && (!options.ranker || !nonblank(options.ranker.version) || typeof options.ranker.rank !== "function"))) {
24
+ throw new DiscoveryError({ code: "invalid_configuration", message: "A custom ranker requires a version and synchronous rank function." });
25
+ }
26
+ if (options.ranker)
27
+ this.ranker = Object.freeze({
28
+ version: options.ranker.version, rank: options.ranker.rank.bind(options.ranker)
29
+ });
30
+ if (this.configuration.mode === "hybrid") {
31
+ const embedding = options.embedding;
32
+ if (!embedding || !isRecord(embedding) || !hasOnlyKeys(embedding, ["client", "index", "indexLimits", "execution"])
33
+ || !embedding.client || typeof embedding.client.mock !== "boolean" || typeof embedding.client.embed !== "function")
34
+ throw invalidEmbeddingConfiguration();
35
+ const indexLimits = resolveIndexLimits(embedding.indexLimits);
36
+ let index = null;
37
+ try {
38
+ index = deepFreeze(boundedJsonSnapshot(embedding.index, indexLimits.maxArtifactBytes));
39
+ }
40
+ catch { /* Invalid artifacts yield per-query unavailable/fallback outcomes before any provider purchase. */ }
41
+ this.embedding = Object.freeze({
42
+ client: embedding.client, index, indexLimits, execution: resolveEmbeddingExecution(embedding.execution),
43
+ configuration: resolveEmbeddingConfiguration(embedding.client.configuration), mock: embedding.client.mock
44
+ });
45
+ }
46
+ else if (options.embedding !== undefined) {
47
+ throw new DiscoveryError({ code: "invalid_configuration", message: "Lexical discovery does not accept embedding dependencies." });
48
+ }
49
+ }
50
+ async discover(request) {
51
+ if (request.providerRun) {
52
+ const run = request.providerRun;
53
+ assertProviderRunScope(run, request.runId, request.budget ? { ledger: request.budget, policy: run.budget.policy } : undefined);
54
+ const signals = [request.signal, run.signal].filter((item) => !!item);
55
+ request = { ...request, budget: request.budget ?? run.budget.ledger, signal: signals.length ? AbortSignal.any(signals) : undefined,
56
+ deadlineAt: Math.min(request.deadlineAt ?? Infinity, run.deadlineAt) };
57
+ }
58
+ const configuration = this.invocationConfiguration(request);
59
+ const queries = validateQueries(request, configuration);
60
+ if (!queries.length)
61
+ return [];
62
+ const started = performance.now();
63
+ const corpus = buildCapabilitySearchCorpus(request.routeRequest.registry);
64
+ const eligibility = captureEligibility(request.routeRequest);
65
+ const eligibleIds = new Set(eligibility.eligible.map(({ manifest }) => manifest.id));
66
+ const documents = Object.freeze(corpus.documents.filter(document => eligibleIds.has(document.capabilityId)));
67
+ const lexical = lexicalConfiguration(configuration);
68
+ const policy = retrievalPolicyFingerprint(configuration, this.ranker?.version);
69
+ const current = () => {
70
+ try {
71
+ return captureEligibility(request.routeRequest).fingerprint === eligibility.fingerprint
72
+ && registrySourceFingerprint(request.routeRequest.registry) === corpus.registrySourceFingerprint;
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ };
78
+ const result = (queryId, status, code, usage = zeroDiscoveryUsage(performance.now() - started)) => ({
79
+ queryId, status, requestedMode: configuration.mode, actualMode: status === "cancelled" || status === "unavailable" ? null : configuration.mode,
80
+ candidates: [], corpusFingerprint: corpus.corpusFingerprint, eligibilityFingerprint: eligibility.fingerprint,
81
+ retrievalPolicyFingerprint: policy, policyVersion: configuration.policyVersion, usage,
82
+ diagnostics: code ? [{ code, queryId, message: diagnosticMessage(code) }] : []
83
+ });
84
+ const lexicalOutput = (query) => {
85
+ const input = Object.freeze({ query, documents, configuration: lexical });
86
+ return this.ranker ? this.ranker.rank(input) : rankLexically(input);
87
+ };
88
+ const lexicalResult = (query, usage, degradation) => {
89
+ try {
90
+ const candidates = shortlistCandidates(lexicalOutput(query), query, documents, lexical);
91
+ return {
92
+ ...result(query.id, candidates.length ? "matched" : "no_match", candidates.length ? undefined : "no_matching_candidates", usage),
93
+ actualMode: "lexical", candidates,
94
+ ...(degradation ? { degradedReason: degradation, diagnostics: [
95
+ { code: degradation, queryId: query.id, message: diagnosticMessage(degradation) },
96
+ { code: "lexical_fallback", queryId: query.id, message: "The whole query used the explicit lexical fallback policy." }
97
+ ] } : {})
98
+ };
99
+ }
100
+ catch {
101
+ return result(query.id, "unavailable", "invalid_ranker_output", usage);
102
+ }
103
+ };
104
+ const semanticFailure = (query, code, usage) => {
105
+ if (configuration.mode === "hybrid" && configuration.failurePolicy === "lexical_fallback"
106
+ && ["invalid_index", "embedding_configuration_mismatch", "invalid_embedding", "provider_unavailable"].includes(code)) {
107
+ if (!current())
108
+ return result(query.id, "unavailable", "stale_binding", usage);
109
+ return lexicalResult(query, usage, code);
110
+ }
111
+ return result(query.id, code === "cancelled" || code === "deadline_exceeded" ? "cancelled" : "unavailable", code, usage);
112
+ };
113
+ const hasWork = documents.length && queries.some(query => query.fragments.some(fragment => tokenizeDiscoveryText(fragment.text).length));
114
+ const embedding = this.embedding;
115
+ const index = embedding && hasWork ? validateCapabilityEmbeddingIndex(embedding.index, {
116
+ corpus, configuration: embedding.configuration, mock: embedding.mock, limits: embedding.indexLimits
117
+ }) : undefined;
118
+ if (embedding && index?.valid && !discoveryStopReason(request)) {
119
+ validateProviderInvocation(request);
120
+ for (const query of queries) {
121
+ if (query.fragments.some(fragment => tokenizeDiscoveryText(fragment.text).length)) {
122
+ checkEmbeddingTexts([query.fragments.map(fragment => fragment.text).join("\n")], embedding.execution.limits);
123
+ }
124
+ }
125
+ }
126
+ const results = [];
127
+ for (const query of queries) {
128
+ const stopped = discoveryStopReason(request);
129
+ if (stopped) {
130
+ results.push(result(query.id, "cancelled", stopped));
131
+ continue;
132
+ }
133
+ if (!query.fragments.some(fragment => tokenizeDiscoveryText(fragment.text).length)) {
134
+ results.push(result(query.id, "no_match", "empty_query"));
135
+ continue;
136
+ }
137
+ if (!documents.length) {
138
+ results.push(result(query.id, "no_match", "no_eligible_capabilities"));
139
+ continue;
140
+ }
141
+ if (!current()) {
142
+ results.push(result(query.id, "unavailable", "stale_binding"));
143
+ continue;
144
+ }
145
+ if (configuration.mode === "lexical") {
146
+ results.push(lexicalResult(query));
147
+ continue;
148
+ }
149
+ if (!index?.valid) {
150
+ results.push(semanticFailure(query, index?.diagnostics[0]?.code ?? "invalid_index"));
151
+ continue;
152
+ }
153
+ let candidates;
154
+ try {
155
+ candidates = validateLexicalCandidates(lexicalOutput(query), query, documents, true);
156
+ }
157
+ catch {
158
+ results.push(result(query.id, "unavailable", "invalid_ranker_output"));
159
+ continue;
160
+ }
161
+ if (!candidates.length) {
162
+ results.push(result(query.id, "no_match", "no_matching_candidates"));
163
+ continue;
164
+ }
165
+ const attempted = await runEmbeddingAttempt({
166
+ ...request, deadlineAt: request.deadlineAt, budget: request.budget, client: embedding.client,
167
+ configuration: embedding.configuration, mock: embedding.mock, execution: embedding.execution,
168
+ texts: [query.fragments.map(fragment => fragment.text).join("\n")], stage: "query_embedding",
169
+ maxVectorDimension: embedding.indexLimits.maxVectorDimension, expectedDimension: index.index.vectorDimension,
170
+ controls: request.routeRequest.controls, runtimeContext: request.routeRequest.builtContext.runtimeContext, isCurrent: current
171
+ });
172
+ if (attempted.status !== "completed") {
173
+ results.push(semanticFailure(query, attempted.diagnostics[0].code, attempted.usage));
174
+ continue;
175
+ }
176
+ const vectors = new Map(index.index.entries.map(entry => [entry.capabilityId, entry.vector]));
177
+ const selected = rankHybridCandidates(candidates, attempted.vectors[0], vectors, documents, configuration);
178
+ results.push({
179
+ ...result(query.id, selected.length ? "matched" : "no_match", selected.length ? undefined : "no_matching_candidates", attempted.usage),
180
+ candidates: selected, indexFingerprint: index.index.indexFingerprint
181
+ });
182
+ }
183
+ const valid = current();
184
+ return results.map(entry => {
185
+ const stopped = discoveryStopReason(request);
186
+ if (stopped || !valid && entry.status === "matched") {
187
+ const { indexFingerprint: _, ...retained } = entry;
188
+ const code = stopped ?? "stale_binding";
189
+ return { ...retained, status: stopped ? "cancelled" : "unavailable", actualMode: null, candidates: [],
190
+ diagnostics: [{ code, queryId: entry.queryId, message: diagnosticMessage(code) }] };
191
+ }
192
+ return entry;
193
+ });
194
+ }
195
+ invocationConfiguration(request) {
196
+ if (!isRecord(request) || !nonblank(request.runId) || !nonblank(request.requestId)
197
+ || (request.deadlineAt !== undefined && (typeof request.deadlineAt !== "number" || !Number.isFinite(request.deadlineAt)))
198
+ || (request.signal !== undefined && !(request.signal instanceof AbortSignal))) {
199
+ throw new DiscoveryError({ code: "invalid_input", message: "Discovery requires invocation identifiers and valid cancellation bounds." });
200
+ }
201
+ const limit = request.maxCandidates === undefined ? this.configuration.limits.maxCandidates : request.maxCandidates;
202
+ if (!Number.isInteger(limit) || limit < 1 || limit > this.configuration.limits.maxCandidates) {
203
+ throw new DiscoveryError({ code: "invalid_input", message: "The invocation candidate limit must lower or equal the configured limit." });
204
+ }
205
+ return Object.freeze({ ...this.configuration, limits: Object.freeze({
206
+ ...this.configuration.limits, maxCandidates: limit, aliasDiversitySlots: limit === 1 ? 0 : this.configuration.limits.aliasDiversitySlots
207
+ }) });
208
+ }
209
+ }
210
+ export function validateQueries(request, configuration) {
211
+ const invalid = () => new DiscoveryError({ code: "invalid_input", message: "Discovery requires unique query IDs and string fragments." });
212
+ const exceeded = () => new DiscoveryError({ code: "input_limit_exceeded", message: "Discovery input exceeds the configured batch, fragment, or text limit." });
213
+ if (!Array.isArray(request.queries))
214
+ throw invalid();
215
+ if (request.queries.length > configuration.limits.maxQueries)
216
+ throw exceeded();
217
+ const ids = new Set();
218
+ return Object.freeze(Array.from(request.queries, query => {
219
+ if (!isRecord(query) || !hasOnlyKeys(query, ["id", "fragments"]) || !nonblank(query.id)
220
+ || ids.has(query.id) || !Array.isArray(query.fragments))
221
+ throw invalid();
222
+ ids.add(query.id);
223
+ if (query.fragments.length > configuration.limits.maxFragmentsPerQuery)
224
+ throw exceeded();
225
+ let characters = 0;
226
+ const fragments = Array.from(query.fragments, fragment => {
227
+ if (!isRecord(fragment) || !hasOnlyKeys(fragment, ["key", "text"])
228
+ || !nonblank(fragment.key) || typeof fragment.text !== "string")
229
+ throw invalid();
230
+ characters += fragment.text.length;
231
+ if (characters > configuration.limits.maxQueryCharacters)
232
+ throw exceeded();
233
+ return Object.freeze({ key: fragment.key, text: fragment.text });
234
+ });
235
+ return Object.freeze({ id: query.id, fragments: Object.freeze(fragments) });
236
+ }));
237
+ }
238
+ export function discoveryStopReason(request) {
239
+ return stopReason(request);
240
+ }
241
+ export function zeroDiscoveryUsage(elapsedMs) {
242
+ return aggregateDiscoveryUsage([], elapsedMs);
243
+ }
244
+ function diagnosticMessage(code) {
245
+ switch (code) {
246
+ case "cancelled": return "Discovery was cancelled.";
247
+ case "deadline_exceeded": return "The discovery deadline elapsed.";
248
+ case "empty_query": return "The query has no searchable tokens.";
249
+ case "no_eligible_capabilities": return "No capabilities are currently eligible.";
250
+ case "no_matching_candidates": return "No eligible candidates met the retrieval policy.";
251
+ case "stale_binding": return "Discovery bindings changed before candidates could be returned.";
252
+ case "invalid_index": return "The embedding index is invalid or stale.";
253
+ case "embedding_configuration_mismatch": return "Embedding configurations or dimensions were incompatible.";
254
+ case "invalid_embedding": return "The embedding client returned invalid semantic inputs.";
255
+ case "provider_unavailable": return "The embedding provider was unavailable.";
256
+ case "budget_denied": return "The shared embedding budget denied this attempt.";
257
+ case "control_denied": return "Runtime controls denied the embedding attempt.";
258
+ case "accounting_unavailable": return "Embedding reservation or settlement accounting was unavailable.";
259
+ default: return "The lexical ranker was unavailable or returned invalid output.";
260
+ }
261
+ }
@@ -0,0 +1,12 @@
1
+ import { DiscoveryError } from "./diagnostics.js";
2
+ import type { EmbeddingCallLimits, EmbeddingExecutionOptions, EmbeddingIndexLimits } from "./embedding-types.js";
3
+ import type { EmbeddingConfiguration } from "./types.js";
4
+ export declare function positiveInteger(value: unknown): value is number;
5
+ export declare function resolveEmbeddingConfiguration(value: EmbeddingConfiguration): Readonly<EmbeddingConfiguration>;
6
+ export declare function resolveIndexLimits(value: EmbeddingIndexLimits): Readonly<EmbeddingIndexLimits>;
7
+ export declare function resolveEmbeddingExecution(value: EmbeddingExecutionOptions): Readonly<EmbeddingExecutionOptions>;
8
+ export declare function nonnegative(value: unknown): value is number;
9
+ export declare function checkEmbeddingTexts(texts: readonly string[], limits: EmbeddingCallLimits): void;
10
+ export declare function invalidEmbeddingConfiguration(): DiscoveryError;
11
+ export declare function inputLimit(): DiscoveryError;
12
+ //# sourceMappingURL=embedding-configuration.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-configuration.d.ts","sourceRoot":"","sources":["../../src/discovery/embedding-configuration.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE/D;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,sBAAsB,GAAG,QAAQ,CAAC,sBAAsB,CAAC,CAU7G;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,oBAAoB,GAAG,QAAQ,CAAC,oBAAoB,CAAC,CAK9F;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,yBAAyB,GAAG,QAAQ,CAAC,yBAAyB,CAAC,CAiC/G;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE3D;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAO/F;AAED,wBAAgB,6BAA6B,IAAI,cAAc,CAE9D;AAED,wBAAgB,UAAU,IAAI,cAAc,CAE3C"}
@@ -0,0 +1,81 @@
1
+ import { hasOnlyKeys, isRecord, nonblank } from "./configuration.js";
2
+ import { DiscoveryError } from "./diagnostics.js";
3
+ export function positiveInteger(value) {
4
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
5
+ }
6
+ export function resolveEmbeddingConfiguration(value) {
7
+ if (!isRecord(value) || !hasOnlyKeys(value, ["provider", "model", "configurationId", "revision", "dimensions"])
8
+ || !nonblank(value.provider) || !nonblank(value.model) || !nonblank(value.configurationId)
9
+ || (value.revision !== undefined && !nonblank(value.revision))
10
+ || (value.dimensions !== undefined && !positiveInteger(value.dimensions)))
11
+ throw invalidEmbeddingConfiguration();
12
+ return Object.freeze({
13
+ provider: value.provider, model: value.model, configurationId: value.configurationId,
14
+ ...(value.revision === undefined ? {} : { revision: value.revision }),
15
+ ...(value.dimensions === undefined ? {} : { dimensions: value.dimensions })
16
+ });
17
+ }
18
+ export function resolveIndexLimits(value) {
19
+ if (!isRecord(value) || !hasOnlyKeys(value, ["maxArtifactBytes", "maxEntries", "maxVectorDimension"])
20
+ || !positiveInteger(value.maxArtifactBytes) || !positiveInteger(value.maxEntries)
21
+ || !positiveInteger(value.maxVectorDimension))
22
+ throw invalidEmbeddingConfiguration();
23
+ return Object.freeze({ ...value });
24
+ }
25
+ export function resolveEmbeddingExecution(value) {
26
+ if (!isRecord(value) || !hasOnlyKeys(value, ["limits", "budgetPolicy", "estimateCost"])
27
+ || !isRecord(value.limits) || !hasOnlyKeys(value.limits, ["maxInputTokens", "maxCharactersPerText", "maxCharactersPerCall", "maxEstimatedCostPerCall"])
28
+ || !positiveInteger(value.limits.maxInputTokens) || !positiveInteger(value.limits.maxCharactersPerText)
29
+ || !positiveInteger(value.limits.maxCharactersPerCall)
30
+ || (value.limits.maxEstimatedCostPerCall !== undefined && !nonnegative(value.limits.maxEstimatedCostPerCall))
31
+ || !isRecord(value.budgetPolicy) || !nonblank(value.budgetPolicy.id) || !isRecord(value.budgetPolicy.scope)
32
+ || !["global", "provider", "model", "capability", "domain", "risk_tier", "tenant", "autonomy_tier"].includes(value.budgetPolicy.scope.type)
33
+ || (value.estimateCost !== undefined && typeof value.estimateCost !== "function"))
34
+ throw invalidEmbeddingConfiguration();
35
+ const policy = value.budgetPolicy;
36
+ if (!hasOnlyKeys(policy, ["id", "scope", "mode", "maxEstimatedCostPerRun", "maxInputTokensPerRun",
37
+ "maxOutputTokensPerRun", "maxProviderCallsPerRun", "maxRetriesPerRun", "maxRuntimeMsPerRun", "maxToolCallsPerRun"])
38
+ || (policy.mode !== undefined && policy.mode !== "hard" && policy.mode !== "warn")
39
+ || !Number.isSafeInteger(policy.maxProviderCallsPerRun) || (policy.maxProviderCallsPerRun ?? -1) < 0)
40
+ throw invalidEmbeddingConfiguration();
41
+ for (const [key, amount] of Object.entries(policy)) {
42
+ if (!key.startsWith("max"))
43
+ continue;
44
+ if (!nonnegative(amount) || (key !== "maxEstimatedCostPerRun" && !Number.isSafeInteger(amount)))
45
+ throw invalidEmbeddingConfiguration();
46
+ }
47
+ const scopeFields = {
48
+ global: [], provider: ["providerId"], model: ["providerId", "model"], capability: ["capabilityId"],
49
+ domain: ["domain"], risk_tier: ["riskTier"], tenant: ["tenantId"], autonomy_tier: ["autonomyTier"]
50
+ };
51
+ const fields = scopeFields[policy.scope.type];
52
+ if (!hasOnlyKeys(policy.scope, ["type", ...fields]) || fields.some(key => !nonblank(policy.scope[key]))
53
+ || policy.scope.type === "risk_tier" && !["none", "low", "medium", "high", "critical"].includes(policy.scope.riskTier)
54
+ || policy.scope.type === "autonomy_tier" && !["A0", "A1", "A2", "A3", "A4", "A5"].includes(policy.scope.autonomyTier)
55
+ || (policy.maxEstimatedCostPerRun !== undefined && value.limits.maxEstimatedCostPerCall === undefined))
56
+ throw invalidEmbeddingConfiguration();
57
+ return Object.freeze({
58
+ limits: Object.freeze({ ...value.limits }),
59
+ budgetPolicy: Object.freeze({ ...policy, scope: Object.freeze({ ...policy.scope }) }),
60
+ ...(value.estimateCost ? { estimateCost: value.estimateCost } : {})
61
+ });
62
+ }
63
+ export function nonnegative(value) {
64
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
65
+ }
66
+ export function checkEmbeddingTexts(texts, limits) {
67
+ let characters = 0;
68
+ for (const text of texts) {
69
+ if (typeof text !== "string" || text.length > limits.maxCharactersPerText)
70
+ throw inputLimit();
71
+ characters += text.length;
72
+ if (characters > limits.maxCharactersPerCall)
73
+ throw inputLimit();
74
+ }
75
+ }
76
+ export function invalidEmbeddingConfiguration() {
77
+ return new DiscoveryError({ code: "invalid_configuration", message: "Embedding configuration, limits, and provider-call budget must be explicit and valid." });
78
+ }
79
+ export function inputLimit() {
80
+ return new DiscoveryError({ code: "input_limit_exceeded", message: "Embedding input or artifact exceeds the configured limits." });
81
+ }
@@ -0,0 +1,75 @@
1
+ import type { AicfRuntimeControls, BudgetPolicy } from "../controls/types.js";
2
+ import type { CapabilityEmbeddingIndexArtifact } from "../generated/manifest-types.js";
3
+ import type { AicfRuntimeContext } from "../runtime/types.js";
4
+ import type { DiscoveryDiagnostic } from "./diagnostics.js";
5
+ import type { CapabilitySearchCorpus, DiscoveryBudgetLedger, DiscoveryInvocation, DiscoveryUsage, EmbeddingClient, EmbeddingConfiguration, ModelUsage } from "./types.js";
6
+ export type DeepReadonly<T> = T extends object ? {
7
+ readonly [K in keyof T]: DeepReadonly<T[K]>;
8
+ } : T;
9
+ export type CapabilityEmbeddingIndex = DeepReadonly<CapabilityEmbeddingIndexArtifact>;
10
+ export interface EmbeddingIndexLimits {
11
+ maxArtifactBytes: number;
12
+ maxEntries: number;
13
+ maxVectorDimension: number;
14
+ }
15
+ export interface EmbeddingCallLimits {
16
+ maxInputTokens: number;
17
+ maxCharactersPerText: number;
18
+ maxCharactersPerCall: number;
19
+ maxEstimatedCostPerCall?: number;
20
+ }
21
+ export interface EmbeddingExecutionOptions {
22
+ limits: EmbeddingCallLimits;
23
+ budgetPolicy: BudgetPolicy;
24
+ /** Return undefined when the available reported usage cannot be priced. */
25
+ estimateCost?: (usage: Readonly<ModelUsage>, configuration: Readonly<EmbeddingConfiguration>) => number | undefined;
26
+ }
27
+ export interface HybridDiscoveryDependencies {
28
+ client: EmbeddingClient;
29
+ index: unknown;
30
+ indexLimits: EmbeddingIndexLimits;
31
+ execution: EmbeddingExecutionOptions;
32
+ }
33
+ export interface EmbeddingIndexExpected {
34
+ corpus: CapabilitySearchCorpus;
35
+ configuration: EmbeddingConfiguration;
36
+ mock: boolean;
37
+ limits: EmbeddingIndexLimits;
38
+ }
39
+ export type EmbeddingIndexValidationResult = {
40
+ valid: true;
41
+ index: CapabilityEmbeddingIndex;
42
+ diagnostics: readonly [];
43
+ } | {
44
+ valid: false;
45
+ diagnostics: readonly DiscoveryDiagnostic[];
46
+ };
47
+ export interface CapabilityEmbeddingIndexBuildRequest extends DiscoveryInvocation {
48
+ deadlineAt: number;
49
+ corpus: CapabilitySearchCorpus;
50
+ client: EmbeddingClient;
51
+ limits: EmbeddingIndexLimits;
52
+ execution: EmbeddingExecutionOptions;
53
+ batchSize: number;
54
+ maxProviderCalls: number;
55
+ budget: DiscoveryBudgetLedger;
56
+ controls?: AicfRuntimeControls;
57
+ runtimeContext?: AicfRuntimeContext;
58
+ }
59
+ export type CapabilityEmbeddingIndexBuildResult = {
60
+ status: "built";
61
+ index: CapabilityEmbeddingIndex;
62
+ usage: DiscoveryUsage;
63
+ diagnostics: readonly DiscoveryDiagnostic[];
64
+ } | {
65
+ status: "unavailable" | "cancelled";
66
+ index: null;
67
+ usage: DiscoveryUsage;
68
+ diagnostics: readonly DiscoveryDiagnostic[];
69
+ };
70
+ /** Host implementations replace complete values atomically; no partial artifact may become visible. */
71
+ export interface CapabilityEmbeddingIndexStore {
72
+ read(key: string): Promise<string | null>;
73
+ replace(key: string, serializedArtifact: string): Promise<void>;
74
+ }
75
+ //# sourceMappingURL=embedding-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding-types.d.ts","sourceRoot":"","sources":["../../src/discovery/embedding-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ import type { AicfRuntimeControls } from "../controls/types.js";
2
+ import type { AicfRuntimeContext } from "../runtime/types.js";
3
+ import { type DiscoveryDiagnostic } from "./diagnostics.js";
4
+ import type { EmbeddingExecutionOptions } from "./embedding-types.js";
5
+ import type { DiscoveryBudgetLedger, DiscoveryInvocation, DiscoveryUsage, EmbeddingClient, EmbeddingConfiguration } from "./types.js";
6
+ export interface EmbeddingAttemptRequest extends DiscoveryInvocation {
7
+ deadlineAt: number;
8
+ client: EmbeddingClient;
9
+ configuration: EmbeddingConfiguration;
10
+ mock: boolean;
11
+ texts: readonly string[];
12
+ stage: "embedding_build" | "query_embedding";
13
+ execution: EmbeddingExecutionOptions;
14
+ maxVectorDimension: number;
15
+ expectedDimension?: number;
16
+ budget: DiscoveryBudgetLedger;
17
+ controls?: AicfRuntimeControls;
18
+ runtimeContext?: AicfRuntimeContext;
19
+ /** Rechecks current source/authorization immediately after a reservation. */
20
+ isCurrent?: () => boolean;
21
+ }
22
+ export type EmbeddingAttemptResult = {
23
+ status: "completed";
24
+ vectors: readonly (readonly number[])[];
25
+ vectorDimension: number;
26
+ usage: DiscoveryUsage;
27
+ diagnostics: readonly [];
28
+ } | {
29
+ status: "unavailable" | "cancelled";
30
+ usage: DiscoveryUsage;
31
+ diagnostics: readonly DiscoveryDiagnostic[];
32
+ };
33
+ export { stopReason, stopGate } from "../runtime/provider-stop.js";
34
+ export declare function validateProviderInvocation(request: DiscoveryInvocation & {
35
+ budget?: DiscoveryBudgetLedger;
36
+ }): void;
37
+ export declare function runEmbeddingAttempt(request: EmbeddingAttemptRequest): Promise<EmbeddingAttemptResult>;
38
+ //# sourceMappingURL=embeddings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../src/discovery/embeddings.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAkB,KAAK,mBAAmB,EAAgC,MAAM,kBAAkB,CAAC;AAI1G,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAC;AAGtE,OAAO,KAAK,EACV,qBAAqB,EAAE,mBAAmB,EAAE,cAAc,EAAE,eAAe,EAAE,sBAAsB,EACpG,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;IACxB,aAAa,EAAE,sBAAsB,CAAC;IACtC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,KAAK,EAAE,iBAAiB,GAAG,iBAAiB,CAAC;IAC7C,SAAS,EAAE,yBAAyB,CAAC;IACrC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,sBAAsB,GAC9B;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,SAAS,EAAE,CAAA;CAAE,GAC1I;IAAE,MAAM,EAAE,aAAa,GAAG,WAAW,CAAC;IAAC,KAAK,EAAE,cAAc,CAAC;IAAC,WAAW,EAAE,SAAS,mBAAmB,EAAE,CAAA;CAAE,CAAC;AAEhH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACnE,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,mBAAmB,GAAG;IAAE,MAAM,CAAC,EAAE,qBAAqB,CAAA;CAAE,GAAG,IAAI,CAMlH;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmC3G"}
@@ -0,0 +1,71 @@
1
+ import { executeProviderAttempt } from "../runtime/provider-attempt.js";
2
+ import { assertProviderRunScope } from "../runtime/provider-run.js";
3
+ import { hasOnlyKeys, isRecord, nonblank } from "./configuration.js";
4
+ import { DiscoveryError } from "./diagnostics.js";
5
+ import { checkEmbeddingTexts, positiveInteger, resolveEmbeddingConfiguration, resolveEmbeddingExecution } from "./embedding-configuration.js";
6
+ import { fingerprintDiscoveryValue } from "./fingerprint.js";
7
+ import { deepFreeze } from "./json-snapshot.js";
8
+ import { validVectorBatch } from "./vectors.js";
9
+ export { stopReason, stopGate } from "../runtime/provider-stop.js";
10
+ export function validateProviderInvocation(request) {
11
+ if (!nonblank(request.runId) || !nonblank(request.requestId) || typeof request.deadlineAt !== "number"
12
+ || !Number.isFinite(request.deadlineAt) || request.signal !== undefined && !(request.signal instanceof AbortSignal)
13
+ || typeof request.budget?.reserve !== "function" || typeof request.budget?.settle !== "function") {
14
+ throw new DiscoveryError({ code: "invalid_configuration", message: "Embedding attempts require invocation IDs, a deadline, and a shared reservation ledger." });
15
+ }
16
+ }
17
+ export async function runEmbeddingAttempt(request) {
18
+ validateProviderInvocation(request);
19
+ const execution = resolveEmbeddingExecution(request.execution);
20
+ const configuration = resolveEmbeddingConfiguration(request.configuration);
21
+ checkEmbeddingTexts(request.texts, execution.limits);
22
+ const texts = Object.freeze([...request.texts]);
23
+ if (request.providerRun)
24
+ assertProviderRunScope(request.providerRun, request.runId, { ledger: request.budget, policy: execution.budgetPolicy });
25
+ const input = {
26
+ ...request, maxInputTokens: execution.limits.maxInputTokens, maxEstimatedCostPerCall: execution.limits.maxEstimatedCostPerCall,
27
+ protocolError: "invalid_embedding", estimateCost: execution.estimateCost,
28
+ guard: () => {
29
+ if (request.isCurrent && !request.isCurrent())
30
+ return "stale_binding";
31
+ if (request.client.mock !== request.mock
32
+ || fingerprintDiscoveryValue("embedding_configuration", resolveEmbeddingConfiguration(request.client.configuration))
33
+ !== fingerprintDiscoveryValue("embedding_configuration", configuration))
34
+ return "embedding_configuration_mismatch";
35
+ return undefined;
36
+ },
37
+ invoke: context => request.client.embed({ texts, configuration, maxInputTokens: execution.limits.maxInputTokens,
38
+ runId: request.runId, requestId: request.requestId, ...context }),
39
+ validate(response) {
40
+ if (!isRecord(response) || !hasOnlyKeys(response, ["vectors", "configuration", "vectorDimension", "usage", "providerAttempts"])
41
+ || !positiveInteger(response.vectorDimension) || response.vectorDimension > request.maxVectorDimension
42
+ || request.expectedDimension !== undefined && response.vectorDimension !== request.expectedDimension
43
+ || configuration.dimensions !== undefined && response.vectorDimension !== configuration.dimensions
44
+ || !validVectorBatch(response.vectors, texts.length, response.vectorDimension))
45
+ return { code: "invalid_embedding" };
46
+ if (fingerprintDiscoveryValue("embedding_configuration", resolveEmbeddingConfiguration(response.configuration))
47
+ !== fingerprintDiscoveryValue("embedding_configuration", configuration))
48
+ return { code: "embedding_configuration_mismatch" };
49
+ return { value: { vectors: deepFreeze(response.vectors.map(vector => [...vector])), vectorDimension: response.vectorDimension } };
50
+ }
51
+ };
52
+ const result = request.providerRun ? await request.providerRun.attempt(input)
53
+ : await executeProviderAttempt(input, { ledger: request.budget, policy: execution.budgetPolicy });
54
+ if (result.code)
55
+ return { status: result.code === "cancelled" || result.code === "deadline_exceeded" ? "cancelled" : "unavailable",
56
+ usage: result.usage, diagnostics: [{ code: result.code, message: safeMessage(result.code) }] };
57
+ return { status: "completed", ...result.value, usage: result.usage, diagnostics: [] };
58
+ }
59
+ function safeMessage(code) {
60
+ switch (code) {
61
+ case "cancelled": return "The embedding operation was cancelled.";
62
+ case "deadline_exceeded": return "The embedding deadline elapsed.";
63
+ case "budget_denied": return "The shared embedding budget denied this attempt.";
64
+ case "control_denied": return "Runtime controls denied the embedding attempt.";
65
+ case "stale_binding": return "Source or authorization bindings changed during embedding.";
66
+ case "embedding_configuration_mismatch": return "Embedding model configuration changed or did not match.";
67
+ case "invalid_embedding": return "The embedding client returned incompatible vectors or attempt counts.";
68
+ case "accounting_unavailable": return "Embedding reservation or settlement accounting is unavailable.";
69
+ default: return "The embedding provider was unavailable.";
70
+ }
71
+ }
@@ -0,0 +1,8 @@
1
+ import type { DiscoveryEvaluationObservations, DiscoveryEvaluationSuite } from "../generated/manifest-types.js";
2
+ export interface DiscoveryEvaluationDiagnostic {
3
+ code: string;
4
+ caseId?: string;
5
+ }
6
+ export declare const evaluationSuiteSnapshot: (value: unknown) => DiscoveryEvaluationSuite | null;
7
+ export declare const evaluationObservationsSnapshot: (value: unknown) => DiscoveryEvaluationObservations | null;
8
+ //# sourceMappingURL=evaluation-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-validation.d.ts","sourceRoot":"","sources":["../../src/discovery/evaluation-validation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,+BAA+B,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AAShH,MAAM,WAAW,6BAA6B;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAAE;AASjF,eAAO,MAAM,uBAAuB,GAAI,OAAO,OAAO,oCAA8D,CAAC;AACrH,eAAO,MAAM,8BAA8B,GAAI,OAAO,OAAO,2CAA4E,CAAC"}
@@ -0,0 +1,19 @@
1
+ import Ajv2020 from "ajv/dist/2020.js";
2
+ import { readFileSync } from "node:fs";
3
+ import { boundedJsonSnapshot } from "../runtime/bounded-json.js";
4
+ const ajv = new Ajv2020({ allErrors: true, strict: false });
5
+ const read = (name) => JSON.parse(readFileSync(new URL(`../../schemas/${name}.schema.json`, import.meta.url), "utf8"));
6
+ ajv.addSchema(read("capability-manifest"));
7
+ const suiteValidator = ajv.compile(read("discovery/eval-suite"));
8
+ const observationsValidator = ajv.compile(read("discovery/eval-observations"));
9
+ function snapshot(value, validate) {
10
+ try {
11
+ const detached = boundedJsonSnapshot(value, 16 * 1024 * 1024);
12
+ return validate(detached) ? detached : null;
13
+ }
14
+ catch {
15
+ return null;
16
+ }
17
+ }
18
+ export const evaluationSuiteSnapshot = (value) => snapshot(value, suiteValidator);
19
+ export const evaluationObservationsSnapshot = (value) => snapshot(value, observationsValidator);