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.
- package/CHANGELOG.md +42 -0
- package/README.md +38 -30
- package/ROADMAP.md +14 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +32 -1
- package/dist/discovery/bindings.d.ts +7 -0
- package/dist/discovery/bindings.d.ts.map +1 -0
- package/dist/discovery/bindings.js +24 -0
- package/dist/discovery/budget.d.ts +17 -0
- package/dist/discovery/budget.d.ts.map +1 -0
- package/dist/discovery/budget.js +77 -0
- package/dist/discovery/configuration.d.ts +10 -0
- package/dist/discovery/configuration.d.ts.map +1 -0
- package/dist/discovery/configuration.js +63 -0
- package/dist/discovery/corpus.d.ts +8 -0
- package/dist/discovery/corpus.d.ts.map +1 -0
- package/dist/discovery/corpus.js +64 -0
- package/dist/discovery/diagnostics.d.ts +15 -0
- package/dist/discovery/diagnostics.d.ts.map +1 -0
- package/dist/discovery/diagnostics.js +11 -0
- package/dist/discovery/discoverer.d.ts +23 -0
- package/dist/discovery/discoverer.d.ts.map +1 -0
- package/dist/discovery/discoverer.js +261 -0
- package/dist/discovery/embedding-configuration.d.ts +12 -0
- package/dist/discovery/embedding-configuration.d.ts.map +1 -0
- package/dist/discovery/embedding-configuration.js +81 -0
- package/dist/discovery/embedding-types.d.ts +75 -0
- package/dist/discovery/embedding-types.d.ts.map +1 -0
- package/dist/discovery/embedding-types.js +1 -0
- package/dist/discovery/embeddings.d.ts +38 -0
- package/dist/discovery/embeddings.d.ts.map +1 -0
- package/dist/discovery/embeddings.js +71 -0
- package/dist/discovery/evaluation-validation.d.ts +8 -0
- package/dist/discovery/evaluation-validation.d.ts.map +1 -0
- package/dist/discovery/evaluation-validation.js +19 -0
- package/dist/discovery/evaluation.d.ts +84 -0
- package/dist/discovery/evaluation.d.ts.map +1 -0
- package/dist/discovery/evaluation.js +310 -0
- package/dist/discovery/export.d.ts +14 -0
- package/dist/discovery/export.d.ts.map +1 -0
- package/dist/discovery/export.js +81 -0
- package/dist/discovery/facade.d.ts +82 -0
- package/dist/discovery/facade.d.ts.map +1 -0
- package/dist/discovery/facade.js +266 -0
- package/dist/discovery/fingerprint.d.ts +71 -0
- package/dist/discovery/fingerprint.d.ts.map +1 -0
- package/dist/discovery/fingerprint.js +67 -0
- package/dist/discovery/index-builder.d.ts +3 -0
- package/dist/discovery/index-builder.d.ts.map +1 -0
- package/dist/discovery/index-builder.js +129 -0
- package/dist/discovery/index-validation.d.ts +12 -0
- package/dist/discovery/index-validation.d.ts.map +1 -0
- package/dist/discovery/index-validation.js +117 -0
- package/dist/discovery/index.d.ts +32 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +18 -0
- package/dist/discovery/json-snapshot.d.ts +3 -0
- package/dist/discovery/json-snapshot.d.ts.map +1 -0
- package/dist/discovery/json-snapshot.js +11 -0
- package/dist/discovery/lexical.d.ts +12 -0
- package/dist/discovery/lexical.d.ts.map +1 -0
- package/dist/discovery/lexical.js +26 -0
- package/dist/discovery/metadata.d.ts +4 -0
- package/dist/discovery/metadata.d.ts.map +1 -0
- package/dist/discovery/metadata.js +33 -0
- package/dist/discovery/ranking.d.ts +7 -0
- package/dist/discovery/ranking.d.ts.map +1 -0
- package/dist/discovery/ranking.js +68 -0
- package/dist/discovery/replay.d.ts +50 -0
- package/dist/discovery/replay.d.ts.map +1 -0
- package/dist/discovery/replay.js +175 -0
- package/dist/discovery/retrieval-policy.d.ts +5 -0
- package/dist/discovery/retrieval-policy.d.ts.map +1 -0
- package/dist/discovery/retrieval-policy.js +10 -0
- package/dist/discovery/router.d.ts +39 -0
- package/dist/discovery/router.d.ts.map +1 -0
- package/dist/discovery/router.js +98 -0
- package/dist/discovery/selection-attempt.d.ts +20 -0
- package/dist/discovery/selection-attempt.d.ts.map +1 -0
- package/dist/discovery/selection-attempt.js +39 -0
- package/dist/discovery/selection-cards.d.ts +12 -0
- package/dist/discovery/selection-cards.d.ts.map +1 -0
- package/dist/discovery/selection-cards.js +79 -0
- package/dist/discovery/selection-configuration.d.ts +18 -0
- package/dist/discovery/selection-configuration.d.ts.map +1 -0
- package/dist/discovery/selection-configuration.js +71 -0
- package/dist/discovery/selection-response.d.ts +13 -0
- package/dist/discovery/selection-response.d.ts.map +1 -0
- package/dist/discovery/selection-response.js +47 -0
- package/dist/discovery/selection-types.d.ts +18 -0
- package/dist/discovery/selection-types.d.ts.map +1 -0
- package/dist/discovery/selection-types.js +1 -0
- package/dist/discovery/selection.d.ts +6 -0
- package/dist/discovery/selection.d.ts.map +1 -0
- package/dist/discovery/selection.js +145 -0
- package/dist/discovery/types.d.ts +291 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +1 -0
- package/dist/discovery/usage.d.ts +2 -0
- package/dist/discovery/usage.d.ts.map +1 -0
- package/dist/discovery/usage.js +1 -0
- package/dist/discovery/vectors.d.ts +5 -0
- package/dist/discovery/vectors.d.ts.map +1 -0
- package/dist/discovery/vectors.js +43 -0
- package/dist/discovery/versions.d.ts +37 -0
- package/dist/discovery/versions.d.ts.map +1 -0
- package/dist/discovery/versions.js +36 -0
- package/dist/evals-live/live-eval-runner.d.ts +1 -0
- package/dist/evals-live/live-eval-runner.d.ts.map +1 -1
- package/dist/evals-live/live-eval-runner.js +12 -1
- package/dist/evals-live/types.d.ts +3 -0
- package/dist/evals-live/types.d.ts.map +1 -1
- package/dist/generated/manifest-types.d.ts +3655 -0
- package/dist/generated/manifest-types.d.ts.map +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +8 -0
- package/dist/mcp-server/server.d.ts.map +1 -1
- package/dist/mcp-server/server.js +11 -2
- package/dist/mcp-server/types.d.ts +4 -0
- package/dist/mcp-server/types.d.ts.map +1 -1
- package/dist/observability/redaction.d.ts.map +1 -1
- package/dist/observability/redaction.js +6 -2
- package/dist/observability/types.d.ts +1 -1
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/openai/index.d.ts +2 -0
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +1 -0
- package/dist/openai/responses-runner.d.ts +1 -1
- package/dist/openai/responses-runner.d.ts.map +1 -1
- package/dist/openai/responses-runner.js +134 -7
- package/dist/openai/selection-client.d.ts +28 -0
- package/dist/openai/selection-client.d.ts.map +1 -0
- package/dist/openai/selection-client.js +95 -0
- package/dist/openai/tool-loop.js +1 -1
- package/dist/openai/types.d.ts +19 -2
- package/dist/openai/types.d.ts.map +1 -1
- package/dist/replay/discovery-snapshot.d.ts +10 -0
- package/dist/replay/discovery-snapshot.d.ts.map +1 -0
- package/dist/replay/discovery-snapshot.js +17 -0
- package/dist/replay/recorder.d.ts.map +1 -1
- package/dist/replay/recorder.js +4 -0
- package/dist/replay/redaction.js +5 -1
- package/dist/replay/replayer.d.ts.map +1 -1
- package/dist/replay/replayer.js +14 -1
- package/dist/replay/types.d.ts +3 -0
- package/dist/replay/types.d.ts.map +1 -1
- package/dist/replay/validation.d.ts.map +1 -1
- package/dist/replay/validation.js +6 -0
- package/dist/runtime/bounded-json.d.ts +4 -0
- package/dist/runtime/bounded-json.d.ts.map +1 -0
- package/dist/runtime/bounded-json.js +74 -0
- package/dist/runtime/eligibility.d.ts +4 -0
- package/dist/runtime/eligibility.d.ts.map +1 -0
- package/dist/runtime/eligibility.js +128 -0
- package/dist/runtime/index.d.ts +5 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/provider-attempt.d.ts +11 -0
- package/dist/runtime/provider-attempt.d.ts.map +1 -0
- package/dist/runtime/provider-attempt.js +221 -0
- package/dist/runtime/provider-run.d.ts +10 -0
- package/dist/runtime/provider-run.d.ts.map +1 -0
- package/dist/runtime/provider-run.js +123 -0
- package/dist/runtime/provider-stop.d.ts +9 -0
- package/dist/runtime/provider-stop.d.ts.map +1 -0
- package/dist/runtime/provider-stop.js +28 -0
- package/dist/runtime/provider-types.d.ts +189 -0
- package/dist/runtime/provider-types.d.ts.map +1 -0
- package/dist/runtime/provider-types.js +1 -0
- package/dist/runtime/provider-usage.d.ts +9 -0
- package/dist/runtime/provider-usage.d.ts.map +1 -0
- package/dist/runtime/provider-usage.js +69 -0
- package/dist/runtime/router.d.ts.map +1 -1
- package/dist/runtime/router.js +3 -118
- package/dist/runtime/types.d.ts +9 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/validator.d.ts +3 -0
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +32 -0
- package/docs/api/public-api-policy.md +10 -0
- package/docs/api/stable-workflow.md +58 -0
- package/docs/api.md +7 -0
- package/docs/capability-manifests.md +24 -0
- package/docs/development.md +22 -0
- package/docs/discovery.md +186 -0
- package/docs/evals/discovery-live.md +199 -0
- package/docs/evals/discovery-qualification.md +158 -0
- package/docs/evals/overview.md +9 -0
- package/docs/getting-started/installation.md +11 -12
- package/docs/getting-started/openai-quickstart.md +16 -5
- package/docs/getting-started/provider-neutral-quickstart.md +247 -88
- package/docs/getting-started/quickstart.md +8 -30
- package/docs/index.md +10 -0
- package/docs/release.md +29 -5
- package/docs/runtime.md +27 -0
- package/docs/start-here.md +23 -134
- package/examples/12-capability-discovery-selection/README.md +346 -0
- package/examples/12-capability-discovery-selection/customer-cases.mjs +52 -0
- package/examples/12-capability-discovery-selection/customer-harness.mjs +91 -0
- package/examples/12-capability-discovery-selection/customer-request-example.mjs +320 -0
- package/examples/12-capability-discovery-selection/discovery-example.mjs +175 -0
- package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.suite.json +7887 -0
- package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.v2.suite.json +8167 -0
- package/examples/12-capability-discovery-selection/discovery-fixtures/three-domains.v3.suite.json +8342 -0
- package/examples/12-capability-discovery-selection/evaluation/application.mjs +305 -0
- package/examples/12-capability-discovery-selection/evaluation/campaign.mjs +248 -0
- package/examples/12-capability-discovery-selection/evaluation/clients.mjs +433 -0
- package/examples/12-capability-discovery-selection/evaluation/continuation.mjs +208 -0
- package/examples/12-capability-discovery-selection/evaluation/durable-budget.mjs +420 -0
- package/examples/12-capability-discovery-selection/evaluation/freeze.mjs +9 -0
- package/examples/12-capability-discovery-selection/evaluation/harness.mjs +618 -0
- package/examples/12-capability-discovery-selection/evaluation/mock-host.mjs +260 -0
- package/examples/12-capability-discovery-selection/evaluation/preflight.mjs +115 -0
- package/examples/12-capability-discovery-selection/evaluation/qualification-workflows.mjs +87 -0
- package/examples/12-capability-discovery-selection/evaluation/regrade.mjs +281 -0
- package/examples/12-capability-discovery-selection/evaluation/report.mjs +517 -0
- package/examples/12-capability-discovery-selection/evaluation/runner.mjs +613 -0
- package/examples/12-capability-discovery-selection/evaluation/saved-campaign.mjs +385 -0
- package/examples/12-capability-discovery-selection/evaluation/wording.mjs +115 -0
- package/examples/12-capability-discovery-selection/evaluation/workflow-application.mjs +378 -0
- package/examples/12-capability-discovery-selection/evaluation/workflow-cases.mjs +90 -0
- package/examples/12-capability-discovery-selection/evaluation-example.mjs +154 -0
- package/examples/12-capability-discovery-selection/hybrid-example.mjs +174 -0
- package/examples/12-capability-discovery-selection/mock-embeddings.mjs +101 -0
- package/examples/12-capability-discovery-selection/mock-selection.mjs +78 -0
- package/examples/12-capability-discovery-selection/pipeline-example.mjs +496 -0
- package/examples/12-capability-discovery-selection/retrieval-cases.mjs +31 -0
- package/examples/12-capability-discovery-selection/run-campaign-mock.mjs +40 -0
- package/examples/12-capability-discovery-selection/run-customer-mock.mjs +15 -0
- package/examples/12-capability-discovery-selection/run-evaluation-live.mjs +10 -0
- package/examples/12-capability-discovery-selection/run-evaluation-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/run-evaluation-regrade.mjs +71 -0
- package/examples/12-capability-discovery-selection/run-hybrid-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/run-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/run-pipeline-mock.mjs +2 -0
- package/examples/12-capability-discovery-selection/run-selector-mock.mjs +3 -0
- package/examples/12-capability-discovery-selection/selection-example.mjs +88 -0
- package/package.json +17 -4
- package/schemas/discovery/embedding-index.schema.json +71 -0
- package/schemas/discovery/eval-observations.schema.json +409 -0
- package/schemas/discovery/eval-suite.schema.json +375 -0
- package/schemas/discovery/metadata.schema.json +30 -0
- package/schemas/discovery/selection-response.schema.json +47 -0
- package/schemas/replay/discovery-snapshot.schema.json +335 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# From a customer request to a tool
|
|
2
|
+
|
|
3
|
+
Install `ai-capability-framework` (stable 1.1.0 or later). Lexical/native is the
|
|
4
|
+
recommended default. Hybrid is experimental and opt-in; the
|
|
5
|
+
[qualification report](../../docs/evals/discovery-qualification.md) explains its limits.
|
|
6
|
+
|
|
7
|
+
The application AI produces tasks. Application code searches for relevant capabilities,
|
|
8
|
+
then its existing model chooses a tool from the shortlist. The runtime validates the
|
|
9
|
+
call and enforces execution and approval policy.
|
|
10
|
+
|
|
11
|
+
Run the complete no-key example from the repository root:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm run build
|
|
15
|
+
node examples/12-capability-discovery-selection/run-customer-mock.mjs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The customer asks to read a ticket and prepare a refund for its order. A mocked planning
|
|
19
|
+
call returns two dependent tasks. Application code searches each task when ready, passes
|
|
20
|
+
the authorized read result into the next task's context, and uses ordinary model tool
|
|
21
|
+
calls to read the ticket and prepare a refund preview. The example's host policy
|
|
22
|
+
requires operator review. It stops with approval pending and never exposes or executes
|
|
23
|
+
refund commit.
|
|
24
|
+
|
|
25
|
+
The discovery integration needs only the registry, tasks, and existing runtime context:
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
import { createCapabilityDiscovery } from "ai-capability-framework/discovery";
|
|
29
|
+
|
|
30
|
+
const discovery = createCapabilityDiscovery({ registry });
|
|
31
|
+
const [result] = await discovery.search({
|
|
32
|
+
tasks: [{ id: "read-ticket", text: "Read ticket TCK-100." }],
|
|
33
|
+
runtimeContext
|
|
34
|
+
});
|
|
35
|
+
const router = discovery.routerFor(result);
|
|
36
|
+
// Pass router, the same runtimeContext, and the exact task text to your ordinary runner.
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The default profile uses lexical retrieval, up to eight candidates, no alias bonus or
|
|
40
|
+
diversity, and a 30-second discovery deadline. An earlier caller deadline wins. Search
|
|
41
|
+
accepts controls, existing eligibility filters and permission overrides, cancellation,
|
|
42
|
+
and a custom context builder. Batch results retain task IDs and input order. Use the
|
|
43
|
+
low-level discoverer for multiple fragments or advanced ranking.
|
|
44
|
+
|
|
45
|
+
`routerFor` reuses the issued shortlist without ranking or embedding again. Results are
|
|
46
|
+
immutable and bound to their issuing instance, original task text, runtime context, and
|
|
47
|
+
source. Keep the result in the same request; reconstructed or foreign results are
|
|
48
|
+
rejected. Changed source, identity, permissions, controls, cancellation, or expiry
|
|
49
|
+
cannot export a stale shortlist. Prepare dependent context before searching. Provider
|
|
50
|
+
export and execution retain their ordinary checks.
|
|
51
|
+
|
|
52
|
+
The example also runs no-match clarification, permission denial, and an explicitly
|
|
53
|
+
invoked mock hybrid companion. Planning and ordinary model usage are reported
|
|
54
|
+
separately: one planning turn and four ordinary turns, all synthetic. Lexical discovery
|
|
55
|
+
uses no provider calls. The hybrid companion uses one explicit index-build batch and one
|
|
56
|
+
query attempt; invalid-index rejection purchases no query embedding. No dedicated
|
|
57
|
+
selector runs.
|
|
58
|
+
|
|
59
|
+
## Optional semantic search
|
|
60
|
+
|
|
61
|
+
Enable hybrid mode explicitly, using your configured embedding client and an index built
|
|
62
|
+
in a separate administrative operation:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
import { createInMemoryDiscoveryBudget } from "ai-capability-framework/discovery";
|
|
66
|
+
|
|
67
|
+
const budget = createInMemoryDiscoveryBudget({
|
|
68
|
+
runId: runtimeContext.runId,
|
|
69
|
+
maxProviderCalls: 8,
|
|
70
|
+
maxInputTokens: 32000
|
|
71
|
+
});
|
|
72
|
+
const discovery = createCapabilityDiscovery({
|
|
73
|
+
registry,
|
|
74
|
+
mode: "hybrid",
|
|
75
|
+
embedding: { client: embeddingClient, index, maxInputTokens: 4000 }
|
|
76
|
+
});
|
|
77
|
+
const results = await discovery.search({ tasks, runtimeContext, budget });
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The standard hybrid starting weights are 0.75 semantic and 0.25 lexical. Failures return
|
|
81
|
+
unavailable unless lexical fallback is explicitly configured. Override `weights`,
|
|
82
|
+
`failurePolicy`, and `limits` on the facade as needed. Embedding options allow
|
|
83
|
+
overriding artifact bounds (16 MiB, 10,000 entries, 4,096 dimensions) and provider
|
|
84
|
+
character bounds (16,384 per text, 65,536 per call). The caller supplies the token
|
|
85
|
+
ceiling. Token enforcement and retry disabling remain embedding-client responsibilities.
|
|
86
|
+
Indexes must still match the exact source and embedding configuration; serving never
|
|
87
|
+
builds or repairs them.
|
|
88
|
+
|
|
89
|
+
The in-memory helper enforces a finite single-run budget in one process. A supplied
|
|
90
|
+
`maxEstimatedCost` also requires `embedding.maxEstimatedCostPerCall`; the framework
|
|
91
|
+
assumes no prices. Unknown consumption retains reserved allowance. Late completion
|
|
92
|
+
settles its reservation without restoring a cancelled result. An unresolved attempt
|
|
93
|
+
retains its reservation for the lifetime of the helper.
|
|
94
|
+
|
|
95
|
+
For distributed or durable enforcement, pass `budget: { ledger, policy }` with your own
|
|
96
|
+
ledger and existing budget policy. Reuse the scope across discovery calls in a run. Use
|
|
97
|
+
the shared-run companion below to account for managed planning and downstream model
|
|
98
|
+
calls; this example reports those stages separately. No default credentials, model
|
|
99
|
+
service, or live transport is supplied.
|
|
100
|
+
|
|
101
|
+
These mocks demonstrate contracts and integration. They do not establish real semantic
|
|
102
|
+
quality or guarantee that the first candidate is the correct tool. Applications own
|
|
103
|
+
decomposition, task dependencies, argument completion, and customer responses. A model
|
|
104
|
+
may choose a candidate or request clarification; scores never authorize execution.
|
|
105
|
+
|
|
106
|
+
## Optional dedicated selection
|
|
107
|
+
|
|
108
|
+
Use the ordinary model/tool loop for the standard flow above. If your application needs
|
|
109
|
+
a separate model decision, explicitly call the same discovery instance's `select`
|
|
110
|
+
method:
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
const batch = await discovery.select({
|
|
114
|
+
results,
|
|
115
|
+
client: selectionClient,
|
|
116
|
+
budget,
|
|
117
|
+
maxInputTokens: 4000,
|
|
118
|
+
maxOutputTokens: 1000
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The framework recovers task text and context bindings from its own search results and
|
|
123
|
+
constructs candidate cards. Supply a configured `SelectionModelClient` with an explicit
|
|
124
|
+
`mock` marker and `generateStructured` method; input/output token ceilings are passed to
|
|
125
|
+
that client. Use the existing budget helper or your own `{ ledger, policy }` scope. Cost
|
|
126
|
+
caps require `maxEstimatedCostPerCall`, with optional host cost estimation. There is no
|
|
127
|
+
default model, account, price, or credential lookup.
|
|
128
|
+
|
|
129
|
+
`batch.outcomes` contains ordered selected/abstained decisions or safe failure outcomes
|
|
130
|
+
for matched tasks. Non-matched tasks stay in `batch.discovery` and are never represented
|
|
131
|
+
as model abstentions. `batch.usage` owns selection and repair usage once for the whole
|
|
132
|
+
batch; discovery usage remains in the original discovery results. Individual outcomes
|
|
133
|
+
carry no duplicate provider-usage receipt.
|
|
134
|
+
|
|
135
|
+
Cards preserve complete model descriptions, usage/exclusion guidance, input-field names,
|
|
136
|
+
and read/prepare distinctions. Scores, full schemas, runtime identities, hidden policy,
|
|
137
|
+
and paths are omitted. Optional `contextByQueryId` explicitly projects application data
|
|
138
|
+
for the model. Foreign/reconstructed results and incompatible invocation scopes are
|
|
139
|
+
rejected. Current source, eligibility, identity, controls, cancellation, and original
|
|
140
|
+
deadlines are rechecked; a new deadline can shorten the original bound.
|
|
141
|
+
|
|
142
|
+
Defaults are eight tasks, 32,000 serialized input characters, and one attempt. Override
|
|
143
|
+
`limits: { maxTasks, maxInputCharacters, maxAttempts }` up to 32 tasks, 128,000
|
|
144
|
+
characters, and two attempts. The same character ceiling bounds response parsing. With
|
|
145
|
+
two attempts, one repair may use safe issue codes and the original cards. Oversized
|
|
146
|
+
batches/cards are rejected without clipping or paid splitting. Provider, accounting,
|
|
147
|
+
stale-binding, budget, control, cancellation, and deadline failures cause no repair or
|
|
148
|
+
automatic candidate choice.
|
|
149
|
+
|
|
150
|
+
Advanced callers can pass the same low-level request to `buildCapabilitySelectionTasks`
|
|
151
|
+
and `ModelCapabilitySelector.select`; the helper derives its hashes from that request's
|
|
152
|
+
configured client and limits, without a provider call or manual fingerprint
|
|
153
|
+
construction.
|
|
154
|
+
|
|
155
|
+
The selector returns decisions; application argument completion and runtime execution
|
|
156
|
+
remain separate. Native search and `routerFor` never call the dedicated selector.
|
|
157
|
+
Selected-result routers, the optional Responses adapter, and managed full-run accounting
|
|
158
|
+
are available; see the shared-run integration below. Imports use the public discovery
|
|
159
|
+
subpath; the [named lexical/native workflow](../../docs/api/stable-workflow.md) is
|
|
160
|
+
stable.
|
|
161
|
+
|
|
162
|
+
Run the explicit selector companion:
|
|
163
|
+
|
|
164
|
+
```sh
|
|
165
|
+
npm run build
|
|
166
|
+
node examples/12-capability-discovery-selection/run-selector-mock.mjs
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
It demonstrates competition, single-candidate abstention, a skipped no-match task, and
|
|
170
|
+
one enabled repair. Across two explicit invocations it reports three mock provider
|
|
171
|
+
attempts and 420 synthetic total tokens, with complete reported usage. It executes no
|
|
172
|
+
tools and makes no embedding or live model calls. The fixture establishes contracts, not
|
|
173
|
+
model quality.
|
|
174
|
+
|
|
175
|
+
## Advanced lexical example
|
|
176
|
+
|
|
177
|
+
Run from the repository root:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
npm run build
|
|
181
|
+
node examples/12-capability-discovery-selection/run-mock.mjs
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
This example reuses the synthetic support manifests. Discovery returns independent
|
|
185
|
+
shortlists for four tasks, then the router turns one request into a bounded runtime
|
|
186
|
+
slice. Existing provider export checks produce the tool descriptors. A mocked ordinary
|
|
187
|
+
model/tool loop chooses the ticket lookup, executes the existing authorized runtime
|
|
188
|
+
handler, and returns an answer.
|
|
189
|
+
|
|
190
|
+
Discovery makes zero provider calls and reports complete zero token and cost totals. The
|
|
191
|
+
two ordinary mock model turns run locally. No key, network connection, embedding client,
|
|
192
|
+
or dedicated selector is used.
|
|
193
|
+
|
|
194
|
+
Imports use supported package subpaths. The executable retrieval fixtures include
|
|
195
|
+
compatible and forbidden capabilities without adding manifests to the normal inventory.
|
|
196
|
+
|
|
197
|
+
## Hybrid mock
|
|
198
|
+
|
|
199
|
+
Run the explicit index build and hybrid example:
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
npm run build
|
|
203
|
+
node examples/12-capability-discovery-selection/run-hybrid-mock.mjs
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
This flow builds deterministic synthetic vectors, validates the complete index, and
|
|
207
|
+
round-trips it through host-owned memory storage. It demonstrates a semantic match with
|
|
208
|
+
zero lexical evidence, an invalid-index rejection before any query embedding, and
|
|
209
|
+
explicit lexical fallback. The ordinary mocked model/tool loop still performs tool
|
|
210
|
+
selection and an authorized read.
|
|
211
|
+
|
|
212
|
+
The flow records three logical mock embedding attempts: one document batch and two
|
|
213
|
+
independent query calls, including the query made by the ordinary runtime loop. All
|
|
214
|
+
embedding usage is labeled mock. These vectors provide contract evidence only. No live
|
|
215
|
+
embedding service or dedicated selector is used.
|
|
216
|
+
|
|
217
|
+
Hybrid callers supply an embedding client, complete model configuration, an index,
|
|
218
|
+
artifact and input limits, an absolute deadline, and a shared reservation ledger. Each
|
|
219
|
+
task joins its original fragment texts with newlines and makes at most one embedding
|
|
220
|
+
attempt, sequentially. The native-router wrapper forwards the caller's ledger and
|
|
221
|
+
deadline without changing ordinary runtime runners.
|
|
222
|
+
|
|
223
|
+
Storage implementations must atomically replace complete validated artifacts. Serving
|
|
224
|
+
does not load or rebuild an index implicitly. Stale source, model, revision, dimension,
|
|
225
|
+
or provenance bindings require explicit rebuilding or a configured whole-query lexical
|
|
226
|
+
fallback. An absent model revision does not establish an immutable embedding space.
|
|
227
|
+
|
|
228
|
+
Cancellation returns a fixed usage snapshot. If a provider attempt remains pending, its
|
|
229
|
+
reservation stays held until its observed completion settles it; host recovery handles
|
|
230
|
+
attempts that never finish. Clients enforce token ceilings and disable hidden retries.
|
|
231
|
+
Unreported usage and cost remain unknown.
|
|
232
|
+
|
|
233
|
+
## Shared-run integration
|
|
234
|
+
|
|
235
|
+
Run `node examples/12-capability-discovery-selection/run-pipeline-mock.mjs` after
|
|
236
|
+
`npm run build`. The companion runs lexical/native, lexical/dedicated, hybrid/native,
|
|
237
|
+
and hybrid/dedicated paths through the existing tool loop. Each reads a ticket, carries
|
|
238
|
+
its order ID into refund preparation, and produces a preview requiring approval. It
|
|
239
|
+
makes no real provider calls.
|
|
240
|
+
|
|
241
|
+
Create one optional `createAicfProviderRun` with the existing runtime run ID, a
|
|
242
|
+
reservation budget, and an absolute deadline. Pass it to `search`; facade selection and
|
|
243
|
+
result-bound routers recover that scope. The ordinary Responses runner accepts
|
|
244
|
+
`providerExecution` with explicit model identity, provenance, input/output token
|
|
245
|
+
ceilings, and an application-supplied complete-input token preflight. Continuation
|
|
246
|
+
history is supplied to that preflight. No tokenizer, pricing, credentials, or model
|
|
247
|
+
defaults are discovered.
|
|
248
|
+
|
|
249
|
+
Dedicated selection remains optional:
|
|
250
|
+
|
|
251
|
+
```js
|
|
252
|
+
const batch = await discovery.select({
|
|
253
|
+
results,
|
|
254
|
+
client: selectionClient,
|
|
255
|
+
maxInputTokens: 4000,
|
|
256
|
+
maxOutputTokens: 1000
|
|
257
|
+
});
|
|
258
|
+
const router = discovery.routerFor(batch, task.id);
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Here `results` came from a search using `providerRun`. Without a run, continue supplying
|
|
262
|
+
the existing explicit `budget`. A batch can select several independent tasks, but each
|
|
263
|
+
router exports only its own task's decision. Revalidation repeats neither ranking nor
|
|
264
|
+
provider work. The ordinary model still supplies arguments; normal policy, validation,
|
|
265
|
+
approval, and execution remain in force.
|
|
266
|
+
|
|
267
|
+
`createOpenAISelectionClient` wraps an existing Responses-compatible client and requires
|
|
268
|
+
a complete-input token preflight. It forwards cancellation and timeout, disables
|
|
269
|
+
transport retries, and uses a versioned strict structured-output projection. Embeddings
|
|
270
|
+
continue to use the caller's supplied client and separately built compatible index.
|
|
271
|
+
|
|
272
|
+
`providerRun.attempt` lets application planning or response calls share the same ledger.
|
|
273
|
+
Only calls made through the managed boundary are counted. The in-memory budget
|
|
274
|
+
optionally limits output tokens and retains allowance for unknown usage; use a host
|
|
275
|
+
ledger for distributed or durable enforcement. The runner preserves its legacy `usage`
|
|
276
|
+
field and adds an all-turn `providerUsage` receipt for managed turns. The run snapshot
|
|
277
|
+
combines unique attempts once across stages. Missing usage/cost remains unknown; mock
|
|
278
|
+
zero cost in this example is explicitly supplied.
|
|
279
|
+
|
|
280
|
+
New trace events contain bounded metadata and numeric receipts, including under
|
|
281
|
+
content-capture settings. Run-local retention stops at 256 events and reports overflow.
|
|
282
|
+
Hosts own trace retention and access. Hashes are not anonymization.
|
|
283
|
+
|
|
284
|
+
`createDiscoverySnapshot` creates a bounded metadata snapshot for the existing replay
|
|
285
|
+
extension. Snapshot validation checks bindings and membership; ranking replay
|
|
286
|
+
additionally requires original query fixtures and, for hybrid retrieval, compatible host
|
|
287
|
+
vector fixtures. It never calls a provider. Neither operation establishes model semantic
|
|
288
|
+
correctness. Existing `router_only` replay requires an explicit discovery handler for
|
|
289
|
+
these snapshots. Live replay remains separately enabled and budgeted.
|
|
290
|
+
|
|
291
|
+
The companion reports five, seven, seven, and nine customer-run mock attempts
|
|
292
|
+
respectively. Administrative index-build usage is reported separately. Failure cases
|
|
293
|
+
cover clarification, abstention, permission/source revocation, budget exhaustion, and
|
|
294
|
+
invalid-index rejection without query embedding. Synthetic responses and vectors
|
|
295
|
+
establish integration behavior; they do not qualify retrieval or selection quality.
|
|
296
|
+
|
|
297
|
+
## Installed package and evaluation
|
|
298
|
+
|
|
299
|
+
Fake data: all requests, capabilities, identities, and outputs are synthetic. No secrets
|
|
300
|
+
are needed. No live provider calls occur.
|
|
301
|
+
|
|
302
|
+
Command from an installed consumer directory:
|
|
303
|
+
|
|
304
|
+
```sh
|
|
305
|
+
node node_modules/ai-capability-framework/examples/12-capability-discovery-selection/run-customer-mock.mjs
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Expected output: one planning turn, four ordinary turns, one authorized read, one
|
|
309
|
+
approval-required preparation, and zero commits. The separately invoked hybrid companion
|
|
310
|
+
uses two mock embedding attempts. All five commands use supported public imports and
|
|
311
|
+
resolve manifests relative to their own modules, independent of the working directory.
|
|
312
|
+
|
|
313
|
+
Run `npm run eval:discovery:mock` from the repository, or run the packaged
|
|
314
|
+
`run-evaluation-mock.mjs` in the same way, for the frozen 240-case lexical baseline. The
|
|
315
|
+
suite has three domains, 120 train cases, 60 calibration cases, and 60 held-out cases,
|
|
316
|
+
with scenario families confined to one partition. Independently scripted selection
|
|
317
|
+
observations demonstrate selected, abstained, unavailable, and invalid-output outcomes.
|
|
318
|
+
Their accounting is explicitly incomplete because no provider attempts were observed. No
|
|
319
|
+
selector is invoked by the evaluator.
|
|
320
|
+
|
|
321
|
+
The baseline retains retrieval misses and false positives; its rates are informational.
|
|
322
|
+
Do not tune against the frozen held-out set. These fixtures do not qualify live models.
|
|
323
|
+
See the [discovery guide](../../docs/discovery.md) for defaults, ownership, limits,
|
|
324
|
+
budgets, replay boundaries, and evaluation metrics.
|
|
325
|
+
|
|
326
|
+
## Optional live evaluation campaign
|
|
327
|
+
|
|
328
|
+
The
|
|
329
|
+
[offline regrading guide](../../docs/evals/discovery-live.md#regrade-saved-wording-offline)
|
|
330
|
+
shows how to reassess saved wording without model access. It preserves frozen results,
|
|
331
|
+
observed delivery and historical accounting, and writes a separate versioned report.
|
|
332
|
+
|
|
333
|
+
`npm run eval:discovery:live` validates the corrected v3 suite and fixed-eight-candidate
|
|
334
|
+
schedule with zero provider calls. `npm run eval:discovery:campaign:mock` exercises the
|
|
335
|
+
complete campaign, durable accounting, three held-out repetitions, and 48 workflow runs
|
|
336
|
+
with deterministic clients. It writes evidence under ignored `.aicf/` and makes no
|
|
337
|
+
quality claim about real models.
|
|
338
|
+
|
|
339
|
+
Paid execution requires `--live`, an explicit host configuration, compatible model
|
|
340
|
+
clients, token preflights, matching offline acceptance evidence, and a pinned
|
|
341
|
+
continuation of the original campaign budget. This command performs no paid work by
|
|
342
|
+
default. The application owns response facts and validates model wording with a recorded
|
|
343
|
+
deterministic fallback. Plans, terminal task outcomes and component grades are retained
|
|
344
|
+
in ignored evidence. The original suite and all existing companions are preserved. See
|
|
345
|
+
the [evaluation guide](../../docs/evals/discovery-live.md) for stages, resume behavior,
|
|
346
|
+
limits, and interpretation.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Application-owned planning fixtures; these are not additional manifests.
|
|
2
|
+
export const customerRequest =
|
|
3
|
+
"Read ticket TCK-100 and prepare a refund for its order.";
|
|
4
|
+
export const plannedTasks = [
|
|
5
|
+
{
|
|
6
|
+
id: "read-ticket",
|
|
7
|
+
text: "Read ticket TCK-100 for the refund review.",
|
|
8
|
+
dependsOn: []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "prepare-refund",
|
|
12
|
+
text: "Prepare a refund case for the order from support ticket TCK-100.",
|
|
13
|
+
dependsOn: ["read-ticket"]
|
|
14
|
+
}
|
|
15
|
+
];
|
|
16
|
+
export const taskExpectations = {
|
|
17
|
+
"read-ticket": {
|
|
18
|
+
compatibleIds: ["support.ticket.get"],
|
|
19
|
+
forbiddenIds: ["support.refund.commit_case"]
|
|
20
|
+
},
|
|
21
|
+
"prepare-refund": {
|
|
22
|
+
compatibleIds: ["support.refund.prepare_case"],
|
|
23
|
+
forbiddenIds: ["support.refund.commit_case"]
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/** Example application validation, deliberately separate from framework discovery. */
|
|
28
|
+
export function validatePlannedTasks(value) {
|
|
29
|
+
if (!Array.isArray(value) || !value.length || value.length > 8)
|
|
30
|
+
throw new Error("Invalid application task plan.");
|
|
31
|
+
const known = new Set();
|
|
32
|
+
return value.map((task) => {
|
|
33
|
+
if (
|
|
34
|
+
!task ||
|
|
35
|
+
typeof task !== "object" ||
|
|
36
|
+
Object.keys(task).some((key) => !["id", "text", "dependsOn"].includes(key)) ||
|
|
37
|
+
typeof task.id !== "string" ||
|
|
38
|
+
!task.id.trim() ||
|
|
39
|
+
known.has(task.id) ||
|
|
40
|
+
typeof task.text !== "string" ||
|
|
41
|
+
!task.text.trim() ||
|
|
42
|
+
task.text.length > 4000 ||
|
|
43
|
+
!Array.isArray(task.dependsOn) ||
|
|
44
|
+
task.dependsOn.some((id) => !known.has(id)) ||
|
|
45
|
+
new Set(task.dependsOn).size !== task.dependsOn.length
|
|
46
|
+
) {
|
|
47
|
+
throw new Error("Invalid application task plan.");
|
|
48
|
+
}
|
|
49
|
+
known.add(task.id);
|
|
50
|
+
return { id: task.id, text: task.text, dependsOn: [...task.dependsOn] };
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AicfActionLifecycleManager,
|
|
3
|
+
AicfHandlerRegistry,
|
|
4
|
+
AicfToolExecutor,
|
|
5
|
+
DefaultPolicyBroker,
|
|
6
|
+
InMemoryApprovalStore,
|
|
7
|
+
InMemoryAuditSink,
|
|
8
|
+
InMemoryIdempotencyStore,
|
|
9
|
+
InMemoryPreparedActionStore
|
|
10
|
+
} from "ai-capability-framework/runtime";
|
|
11
|
+
import { createDiscoveryExample } from "./discovery-example.mjs";
|
|
12
|
+
|
|
13
|
+
// Existing application runtime setup is separate from the discovery integration.
|
|
14
|
+
export async function createCustomerHarness() {
|
|
15
|
+
const { registry, runtimeContext } = await createDiscoveryExample();
|
|
16
|
+
runtimeContext.facts = { "refund.order_not_refundable": false };
|
|
17
|
+
const handlers = new AicfHandlerRegistry({ registry });
|
|
18
|
+
const readCalls = [],
|
|
19
|
+
prepareCalls = [];
|
|
20
|
+
handlers.register({
|
|
21
|
+
capabilityId: "support.ticket.get",
|
|
22
|
+
read: ({ args }) => {
|
|
23
|
+
readCalls.push(args);
|
|
24
|
+
return {
|
|
25
|
+
ticket: { ticket_id: args.ticket_id, order_id: "ORD-100", status: "open" }
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
handlers.register({
|
|
30
|
+
capabilityId: "support.refund.prepare_case",
|
|
31
|
+
prepare: ({ args }) => {
|
|
32
|
+
prepareCalls.push(args);
|
|
33
|
+
return {
|
|
34
|
+
data: {
|
|
35
|
+
ticket_id: args.ticket_id,
|
|
36
|
+
order_id: args.order_id,
|
|
37
|
+
reason_code: args.reason_code
|
|
38
|
+
},
|
|
39
|
+
riskTier: "medium",
|
|
40
|
+
summary: "Refund case prepared for review.",
|
|
41
|
+
userMessage: "The refund case is ready for approval."
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const auditSink = new InMemoryAuditSink();
|
|
46
|
+
const policyBroker = new DefaultPolicyBroker({
|
|
47
|
+
hostPolicyHook: (input) =>
|
|
48
|
+
input.operation === "prepare"
|
|
49
|
+
? {
|
|
50
|
+
status: "approval_required",
|
|
51
|
+
reasons: [],
|
|
52
|
+
requiredApprovals: [
|
|
53
|
+
{
|
|
54
|
+
approvalType: "operator_review",
|
|
55
|
+
reason: "Application policy requires refund review."
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
: null
|
|
60
|
+
});
|
|
61
|
+
const actionLifecycle = new AicfActionLifecycleManager({
|
|
62
|
+
registry,
|
|
63
|
+
handlers,
|
|
64
|
+
auditSink,
|
|
65
|
+
policyBroker,
|
|
66
|
+
approvalStore: new InMemoryApprovalStore(),
|
|
67
|
+
idempotencyStore: new InMemoryIdempotencyStore(),
|
|
68
|
+
preparedActionStore: new InMemoryPreparedActionStore()
|
|
69
|
+
});
|
|
70
|
+
const executor = new AicfToolExecutor({
|
|
71
|
+
registry,
|
|
72
|
+
handlers,
|
|
73
|
+
auditSink,
|
|
74
|
+
policyBroker,
|
|
75
|
+
actionLifecycle
|
|
76
|
+
});
|
|
77
|
+
const executedOperations = [];
|
|
78
|
+
const execute = executor.execute.bind(executor);
|
|
79
|
+
executor.execute = async (input) => {
|
|
80
|
+
executedOperations.push(input.operation);
|
|
81
|
+
return execute(input);
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
registry,
|
|
85
|
+
runtimeContext,
|
|
86
|
+
executor,
|
|
87
|
+
readCalls,
|
|
88
|
+
prepareCalls,
|
|
89
|
+
executedOperations
|
|
90
|
+
};
|
|
91
|
+
}
|