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,174 @@
1
+ import {
2
+ buildCapabilitySearchCorpus,
3
+ buildCapabilityEmbeddingIndex,
4
+ CapabilityDiscoverer,
5
+ RetrievalCapabilityRouter,
6
+ aggregateDiscoveryUsage,
7
+ publishCapabilityEmbeddingIndex,
8
+ loadCapabilityEmbeddingIndex
9
+ } from "ai-capability-framework/discovery";
10
+ import { toOpenAIResponsesToolName } from "ai-capability-framework";
11
+ import {
12
+ MockOpenAIResponsesClient,
13
+ mockFunctionCallResponse,
14
+ mockTextResponse,
15
+ runOpenAIResponses
16
+ } from "ai-capability-framework/openai";
17
+ import { createDiscoveryExample } from "./discovery-example.mjs";
18
+ import {
19
+ DeterministicMockEmbeddingClient,
20
+ MockDiscoveryBudget,
21
+ embeddingIndexLimits,
22
+ embeddingExecution
23
+ } from "./mock-embeddings.mjs";
24
+
25
+ export async function runHybridExample() {
26
+ const harness = await createDiscoveryExample();
27
+ const corpus = buildCapabilitySearchCorpus(harness.registry);
28
+ const client = new DeterministicMockEmbeddingClient();
29
+ const budget = new MockDiscoveryBudget();
30
+ const deadlineAt = Date.now() + 30_000;
31
+ const built = await buildCapabilityEmbeddingIndex({
32
+ corpus,
33
+ client,
34
+ budget,
35
+ execution: embeddingExecution,
36
+ limits: embeddingIndexLimits,
37
+ batchSize: 3,
38
+ maxProviderCalls: 1,
39
+ runId: harness.runtimeContext.runId,
40
+ requestId: harness.runtimeContext.requestId,
41
+ deadlineAt
42
+ });
43
+ if (built.status !== "built") throw new Error("The mock index build must succeed.");
44
+
45
+ // The host chooses storage. This example never writes vectors to disk.
46
+ const artifacts = new Map();
47
+ const store = {
48
+ read: async (key) => artifacts.get(key) ?? null,
49
+ replace: async (key, value) => {
50
+ artifacts.set(key, value);
51
+ }
52
+ };
53
+ const expected = {
54
+ corpus,
55
+ configuration: client.configuration,
56
+ mock: true,
57
+ limits: embeddingIndexLimits
58
+ };
59
+ const published = await publishCapabilityEmbeddingIndex(
60
+ store,
61
+ "example-index",
62
+ built.index,
63
+ expected
64
+ );
65
+ const loaded = await loadCapabilityEmbeddingIndex(store, "example-index", expected);
66
+ if (!published.published || !loaded.valid) {
67
+ throw new Error("Host storage must round-trip a complete validated index.");
68
+ }
69
+ const configuration = {
70
+ mode: "hybrid",
71
+ policyVersion: "example.hybrid.v1",
72
+ weights: { semantic: 0.75, lexical: 0.25 },
73
+ failurePolicy: "unavailable",
74
+ limits: { maxCandidates: 2 }
75
+ };
76
+ const embedding = {
77
+ client,
78
+ index: loaded.index,
79
+ indexLimits: embeddingIndexLimits,
80
+ execution: embeddingExecution
81
+ };
82
+ const request = {
83
+ registry: harness.registry,
84
+ builtContext: harness.builtContext,
85
+ userInput: { text: "case details" },
86
+ budget,
87
+ deadlineAt
88
+ };
89
+ const router = new RetrievalCapabilityRouter({
90
+ mode: "native_tool_selection",
91
+ discovery: configuration,
92
+ embedding
93
+ });
94
+ const routed = await router.routeWithDiagnostics(request);
95
+ const ordinaryClient = new MockOpenAIResponsesClient([
96
+ mockFunctionCallResponse({
97
+ name: toOpenAIResponsesToolName("support.ticket.get"),
98
+ args: { ticket_id: "TCK-100" },
99
+ callId: "call_hybrid_example"
100
+ }),
101
+ mockTextResponse("Ticket TCK-100 is open.", "response_hybrid_example")
102
+ ]);
103
+ const ordinaryLoopDiscovery = [];
104
+ const loop = await runOpenAIResponses({
105
+ ...harness,
106
+ userInput: request.userInput,
107
+ router: {
108
+ route: async (routeRequest) => {
109
+ const result = await router.routeWithDiagnostics({
110
+ ...routeRequest,
111
+ budget,
112
+ deadlineAt
113
+ });
114
+ ordinaryLoopDiscovery.push(...result.discovery);
115
+ return result.slice;
116
+ }
117
+ },
118
+ client: ordinaryClient,
119
+ model: "mock-model"
120
+ });
121
+ if (loop.status !== "completed" || loop.toolResults[0]?.status !== "success") {
122
+ throw new Error("The ordinary mocked runtime must complete an authorized read.");
123
+ }
124
+ const invalid = structuredClone(loaded.index);
125
+ invalid.entries[0].capabilityId = "support.ticket.substituted";
126
+ const discoveryRequest = {
127
+ routeRequest: { ...request, userInput: { text: "ticket" } },
128
+ runId: harness.runtimeContext.runId,
129
+ requestId: harness.runtimeContext.requestId,
130
+ queries: [{ id: "invalid-index", fragments: [{ key: "request", text: "ticket" }] }],
131
+ budget,
132
+ deadlineAt
133
+ };
134
+ const before = client.calls.length;
135
+ const rejected = await new CapabilityDiscoverer(configuration, {
136
+ embedding: { ...embedding, index: invalid }
137
+ }).discover(discoveryRequest);
138
+ const fallback = await new CapabilityDiscoverer(
139
+ { ...configuration, failurePolicy: "lexical_fallback" },
140
+ { embedding: { ...embedding, index: invalid } }
141
+ ).discover(discoveryRequest);
142
+ if (
143
+ rejected[0].status !== "unavailable" ||
144
+ fallback[0].actualMode !== "lexical" ||
145
+ client.calls.length !== before
146
+ ) {
147
+ throw new Error(
148
+ "Invalid indexes must reject or explicitly fall back before a query call."
149
+ );
150
+ }
151
+ const embeddingStages = [
152
+ ...built.usage.stages,
153
+ ...routed.discovery.flatMap((result) => result.usage.stages),
154
+ ...ordinaryLoopDiscovery.flatMap((result) => result.usage.stages)
155
+ ];
156
+ return {
157
+ mock: true,
158
+ slice: routed.slice,
159
+ discovery: routed.discovery,
160
+ indexFingerprint: loaded.index.indexFingerprint,
161
+ buildUsage: built.usage,
162
+ embeddingUsage: aggregateDiscoveryUsage(
163
+ embeddingStages,
164
+ embeddingStages.reduce((total, stage) => total + stage.elapsedMs, 0)
165
+ ),
166
+ logicalEmbeddingAttempts: client.calls.length,
167
+ invalidIndexStatus: rejected[0].status,
168
+ invalidIndexQueryCalls: client.calls.length - before,
169
+ fallbackMode: fallback[0].actualMode,
170
+ fallbackReason: fallback[0].degradedReason,
171
+ ordinaryMockModelTurns: ordinaryClient.requests.length,
172
+ toolStatus: loop.toolResults[0].status
173
+ };
174
+ }
@@ -0,0 +1,101 @@
1
+ // Synthetic vectors exercise contracts; they are not evidence of embedding quality.
2
+ export class DeterministicMockEmbeddingClient {
3
+ mock = true;
4
+ calls = [];
5
+
6
+ constructor(vectorForText = fixtureVector) {
7
+ this.configuration = {
8
+ provider: "mock",
9
+ model: "synthetic-vectors",
10
+ configurationId: "example.embedding.v1",
11
+ revision: "1",
12
+ dimensions: 2
13
+ };
14
+ this.vectorForText = vectorForText;
15
+ }
16
+
17
+ async embed(input) {
18
+ this.calls.push(input);
19
+ const inputTokens = input.texts.reduce(
20
+ (total, text) => total + Math.ceil(text.length / 4),
21
+ 0
22
+ );
23
+ if (inputTokens > input.maxInputTokens) {
24
+ throw Object.assign(new Error("Mock input exceeds its token ceiling."), {
25
+ providerAttempts: 0
26
+ });
27
+ }
28
+ return {
29
+ configuration: { ...this.configuration },
30
+ vectorDimension: 2,
31
+ vectors: input.texts.map(this.vectorForText),
32
+ providerAttempts: 1,
33
+ usage: {
34
+ inputTokens,
35
+ outputTokens: 0,
36
+ totalTokens: inputTokens,
37
+ cachedInputTokens: 0,
38
+ reasoningTokens: 0,
39
+ estimatedCost: 0
40
+ }
41
+ };
42
+ }
43
+ }
44
+
45
+ function fixtureVector(text) {
46
+ if (/refund|reimbursement/i.test(text)) return [0, 1];
47
+ if (/ticket|case details/i.test(text)) return [1, 0];
48
+ return [-1, -1];
49
+ }
50
+
51
+ // Demonstration only. Production hosts own durable, concurrent reservation enforcement.
52
+ export class MockDiscoveryBudget {
53
+ reservations = [];
54
+ settlements = [];
55
+ outstanding = new Map();
56
+
57
+ async reserve(input) {
58
+ const calls = this.settlements.reduce(
59
+ (total, settlement) => total + settlement.result.providerAttempts,
60
+ this.outstanding.size
61
+ );
62
+ if (calls + 1 > input.policy.maxProviderCallsPerRun) {
63
+ return {
64
+ status: "denied",
65
+ diagnostic: { code: "budget_denied", message: "Mock call budget exhausted." }
66
+ };
67
+ }
68
+ const reservationId = "reservation_" + (this.reservations.length + 1);
69
+ this.reservations.push(input);
70
+ this.outstanding.set(reservationId, input);
71
+ return { status: "reserved", reservationId };
72
+ }
73
+
74
+ async settle(reservationId, result) {
75
+ if (!this.outstanding.delete(reservationId)) {
76
+ throw new Error("A reservation must settle exactly once.");
77
+ }
78
+ this.settlements.push({ reservationId, result });
79
+ }
80
+ }
81
+
82
+ export const embeddingIndexLimits = {
83
+ maxArtifactBytes: 1_000_000,
84
+ maxEntries: 128,
85
+ maxVectorDimension: 16
86
+ };
87
+
88
+ export const embeddingExecution = {
89
+ limits: {
90
+ maxInputTokens: 4_000,
91
+ maxCharactersPerText: 16_000,
92
+ maxCharactersPerCall: 32_000,
93
+ maxEstimatedCostPerCall: 1
94
+ },
95
+ budgetPolicy: {
96
+ id: "example.embedding-budget.v1",
97
+ scope: { type: "global" },
98
+ maxProviderCallsPerRun: 64,
99
+ maxEstimatedCostPerRun: 64
100
+ }
101
+ };
@@ -0,0 +1,78 @@
1
+ // Deterministic contract fixture, never a live model or a retrieval-quality evaluation.
2
+ export class MockSelectionClient {
3
+ mock = true;
4
+ configuration = {
5
+ provider: "mock",
6
+ model: "synthetic-selector",
7
+ configurationId: "example.selection.v1",
8
+ revision: "1"
9
+ };
10
+ calls = [];
11
+ constructor(outputs) {
12
+ this.outputs = [...outputs];
13
+ }
14
+ async generateStructured(input) {
15
+ this.calls.push(input);
16
+ if (input.maxInputTokens < 120 || input.maxOutputTokens < 20) {
17
+ throw Object.assign(new Error("Mock token ceiling exceeded."), {
18
+ providerAttempts: 0
19
+ });
20
+ }
21
+ if (!this.outputs.length) throw new Error("No mock selection output queued.");
22
+ const next = this.outputs.shift();
23
+ if (next instanceof Error) throw next;
24
+ return {
25
+ output: typeof next === "function" ? next(input) : next,
26
+ providerAttempts: 1,
27
+ usage: {
28
+ inputTokens: 120,
29
+ outputTokens: 20,
30
+ totalTokens: 140,
31
+ cachedInputTokens: 0,
32
+ reasoningTokens: 0,
33
+ estimatedCost: 0
34
+ }
35
+ };
36
+ }
37
+ }
38
+
39
+ export function selectedDecision(queryId, capabilityId) {
40
+ return {
41
+ query_id: queryId,
42
+ decision: "select",
43
+ capability_id: capabilityId,
44
+ reason_code: "supported_candidate"
45
+ };
46
+ }
47
+ export function abstainedDecision(queryId, reason = "ambiguous_request") {
48
+ return {
49
+ query_id: queryId,
50
+ decision: "abstain",
51
+ capability_id: null,
52
+ reason_code: reason
53
+ };
54
+ }
55
+ export function selectionResponse(...decisions) {
56
+ return { schema_version: "1.0", decisions };
57
+ }
58
+
59
+ export const selectorCases = [
60
+ {
61
+ id: "competition",
62
+ text: "ticket refund",
63
+ compatibleIds: ["support.ticket.get"],
64
+ forbiddenIds: ["support.refund.commit_case"]
65
+ },
66
+ {
67
+ id: "single",
68
+ text: "ticket",
69
+ compatibleIds: [],
70
+ forbiddenIds: ["support.refund.commit_case"]
71
+ },
72
+ {
73
+ id: "no-match",
74
+ text: "quasar",
75
+ compatibleIds: [],
76
+ forbiddenIds: ["support.refund.commit_case"]
77
+ }
78
+ ];