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,84 @@
|
|
|
1
|
+
import type { DiscoveryEvaluationSuite } from "../generated/manifest-types.js";
|
|
2
|
+
import type { ProviderUsage } from "../runtime/provider-types.js";
|
|
3
|
+
import type { ManifestRegistry } from "../types.js";
|
|
4
|
+
import type { DiscoveryEvaluationDiagnostic } from "./evaluation-validation.js";
|
|
5
|
+
export type { DiscoveryEvaluationSuite, DiscoveryEvaluationObservations } from "../generated/manifest-types.js";
|
|
6
|
+
export type { DiscoveryEvaluationDiagnostic } from "./evaluation-validation.js";
|
|
7
|
+
export interface DiscoveryEvaluationRate {
|
|
8
|
+
numerator: number;
|
|
9
|
+
denominator: number;
|
|
10
|
+
value: number | null;
|
|
11
|
+
}
|
|
12
|
+
export interface DiscoveryEvaluationDistribution {
|
|
13
|
+
count: number;
|
|
14
|
+
minimum: number | null;
|
|
15
|
+
mean: number | null;
|
|
16
|
+
p95: number | null;
|
|
17
|
+
maximum: number | null;
|
|
18
|
+
}
|
|
19
|
+
export interface DiscoveryEvaluationReport {
|
|
20
|
+
suiteFingerprint: string;
|
|
21
|
+
scopeFingerprint: string;
|
|
22
|
+
complete: boolean;
|
|
23
|
+
semanticQualityQualified: false;
|
|
24
|
+
counts: {
|
|
25
|
+
expected: number;
|
|
26
|
+
observed: number;
|
|
27
|
+
missing: number;
|
|
28
|
+
byPartition: Record<string, number>;
|
|
29
|
+
byDomain: Record<string, number>;
|
|
30
|
+
byCohort: Record<string, number>;
|
|
31
|
+
};
|
|
32
|
+
retrieval: {
|
|
33
|
+
k: number;
|
|
34
|
+
compatibleRecallAtK: DiscoveryEvaluationRate;
|
|
35
|
+
topOnePrecision: DiscoveryEvaluationRate;
|
|
36
|
+
noMatchFalsePositiveRate: DiscoveryEvaluationRate;
|
|
37
|
+
shortlistSize: DiscoveryEvaluationDistribution;
|
|
38
|
+
outcomes: Record<string, number>;
|
|
39
|
+
forbiddenCandidateCases: number;
|
|
40
|
+
policyViolationCases: number;
|
|
41
|
+
readToMutationCases: number;
|
|
42
|
+
};
|
|
43
|
+
selection: {
|
|
44
|
+
outcomes: Record<string, number>;
|
|
45
|
+
compatibleAccuracy: DiscoveryEvaluationRate;
|
|
46
|
+
abstentionRate: DiscoveryEvaluationRate;
|
|
47
|
+
coverage: DiscoveryEvaluationRate;
|
|
48
|
+
noMatchFalseSelectionRate: DiscoveryEvaluationRate;
|
|
49
|
+
forbiddenChoices: number;
|
|
50
|
+
policyViolations: number;
|
|
51
|
+
readToMutationChoices: number;
|
|
52
|
+
};
|
|
53
|
+
latencyMs: DiscoveryEvaluationDistribution;
|
|
54
|
+
accountingComplete: boolean;
|
|
55
|
+
usageComplete: boolean;
|
|
56
|
+
usage: ProviderUsage;
|
|
57
|
+
provenance: {
|
|
58
|
+
mockAttempts: number;
|
|
59
|
+
liveAttempts: number;
|
|
60
|
+
pendingAttempts: number;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export type DiscoveryEvaluationResult = {
|
|
64
|
+
valid: true;
|
|
65
|
+
report: Readonly<DiscoveryEvaluationReport>;
|
|
66
|
+
diagnostics: readonly [];
|
|
67
|
+
} | {
|
|
68
|
+
valid: false;
|
|
69
|
+
diagnostics: readonly DiscoveryEvaluationDiagnostic[];
|
|
70
|
+
};
|
|
71
|
+
export interface EvaluateCapabilityDiscoveryRequest {
|
|
72
|
+
suite: unknown;
|
|
73
|
+
registry: ManifestRegistry;
|
|
74
|
+
observations: unknown;
|
|
75
|
+
/** Explicit expected cases; omitted means the entire frozen suite. Missing observations remain missing. */
|
|
76
|
+
caseIds?: readonly string[];
|
|
77
|
+
}
|
|
78
|
+
/** Includes authored cases, labels, partitions and capability content; excludes no suite fields. */
|
|
79
|
+
export declare function fingerprintDiscoveryEvaluationSuite(value: DiscoveryEvaluationSuite): string;
|
|
80
|
+
/** Semantic fixture checks used by the CLI without executing retrieval or providers. */
|
|
81
|
+
export declare function validateDiscoveryEvaluationSuite(value: unknown, registry?: ManifestRegistry): readonly DiscoveryEvaluationDiagnostic[];
|
|
82
|
+
/** Scores observations only. It never calls a ranker, model, embedding client, or executor. */
|
|
83
|
+
export declare function evaluateCapabilityDiscovery(request: EvaluateCapabilityDiscoveryRequest): DiscoveryEvaluationResult;
|
|
84
|
+
//# sourceMappingURL=evaluation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluation.d.ts","sourceRoot":"","sources":["../../src/discovery/evaluation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { buildRegistry } from "../registry.js";
|
|
2
|
+
import { validateRuntimeContext } from "../runtime/context.js";
|
|
3
|
+
import { deepFreeze } from "../runtime/bounded-json.js";
|
|
4
|
+
import { aggregateProviderUsage, usageQuantities, USAGE_QUANTITIES } from "../runtime/provider-usage.js";
|
|
5
|
+
import { validateManifests } from "../validator.js";
|
|
6
|
+
import { captureEligibility } from "./bindings.js";
|
|
7
|
+
import { buildCapabilitySearchCorpus, registrySourceFingerprint } from "./corpus.js";
|
|
8
|
+
import { resolveDiscoveryConfiguration } from "./configuration.js";
|
|
9
|
+
import { DiscoveryError } from "./diagnostics.js";
|
|
10
|
+
import { hashDiscoveryContent } from "./fingerprint.js";
|
|
11
|
+
import { evaluationObservationsSnapshot, evaluationSuiteSnapshot } from "./evaluation-validation.js";
|
|
12
|
+
import { retrievalPolicyFingerprint } from "./retrieval-policy.js";
|
|
13
|
+
/** Includes authored cases, labels, partitions and capability content; excludes no suite fields. */
|
|
14
|
+
export function fingerprintDiscoveryEvaluationSuite(value) {
|
|
15
|
+
const suite = evaluationSuiteSnapshot(value);
|
|
16
|
+
if (!suite)
|
|
17
|
+
throw new DiscoveryError({ code: "invalid_input", message: "A valid discovery evaluation suite is required." });
|
|
18
|
+
return hashDiscoveryContent({ kind: "discovery_evaluation_suite", version: "1.0", suite });
|
|
19
|
+
}
|
|
20
|
+
function loadedSuite(suite) {
|
|
21
|
+
return suite.capabilities.map(manifest => ({ kind: "capability", path: `synthetic/${manifest.id}.yaml`,
|
|
22
|
+
absolutePath: `/synthetic/${manifest.id}.yaml`, manifest: manifest }));
|
|
23
|
+
}
|
|
24
|
+
function routeFor(suite, entry, registry) {
|
|
25
|
+
const context = suite.contexts[entry.context_id];
|
|
26
|
+
const runtimeContext = context.runtime_context;
|
|
27
|
+
validateRuntimeContext(runtimeContext);
|
|
28
|
+
if (!Array.isArray(runtimeContext.subject.permissions) || !runtimeContext.subject.permissions.every(x => typeof x === "string")
|
|
29
|
+
|| !runtimeContext.autonomy || !["low", "medium", "high", "critical"].includes(runtimeContext.autonomy.maxRiskTier))
|
|
30
|
+
throw new Error("context");
|
|
31
|
+
return { ...context.eligibility, registry, userInput: { text: entry.fragments.map(fragment => fragment.text).join("\n") },
|
|
32
|
+
builtContext: { runtimeContext, items: [], modelContextText: "", redactions: [], warnings: [] } };
|
|
33
|
+
}
|
|
34
|
+
/** Semantic fixture checks used by the CLI without executing retrieval or providers. */
|
|
35
|
+
export function validateDiscoveryEvaluationSuite(value, registry) {
|
|
36
|
+
const suite = evaluationSuiteSnapshot(value);
|
|
37
|
+
if (!suite)
|
|
38
|
+
return [{ code: "invalid_suite_schema" }];
|
|
39
|
+
const errors = [];
|
|
40
|
+
const add = (code, caseId) => { if (errors.length < 64)
|
|
41
|
+
errors.push({ code, ...(caseId ? { caseId } : {}) }); };
|
|
42
|
+
try {
|
|
43
|
+
const definitions = loadedSuite(suite);
|
|
44
|
+
if (!validateManifests(definitions).valid)
|
|
45
|
+
return [{ code: "invalid_suite_capabilities" }];
|
|
46
|
+
const authoredRegistry = buildRegistry(definitions);
|
|
47
|
+
if (registry && registrySourceFingerprint(registry) !== registrySourceFingerprint(authoredRegistry))
|
|
48
|
+
return [{ code: "suite_registry_mismatch" }];
|
|
49
|
+
registry ??= authoredRegistry;
|
|
50
|
+
for (const context of Object.values(suite.contexts)) {
|
|
51
|
+
try {
|
|
52
|
+
validateRuntimeContext(context.runtime_context);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
add("invalid_context");
|
|
56
|
+
}
|
|
57
|
+
for (const id of [...context.eligibility?.includeCapabilityIds ?? [], ...context.eligibility?.excludeCapabilityIds ?? []]) {
|
|
58
|
+
if (!registry.capabilityById.has(id))
|
|
59
|
+
add("unknown_eligibility_capability");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const ids = new Set(), families = new Map();
|
|
63
|
+
for (const entry of suite.cases) {
|
|
64
|
+
if (ids.has(entry.id))
|
|
65
|
+
add("duplicate_case", entry.id);
|
|
66
|
+
ids.add(entry.id);
|
|
67
|
+
if (families.has(entry.family_id) && families.get(entry.family_id) !== entry.partition)
|
|
68
|
+
add("family_partition_leak", entry.id);
|
|
69
|
+
families.set(entry.family_id, entry.partition);
|
|
70
|
+
if (!Object.hasOwn(suite.contexts, entry.context_id)) {
|
|
71
|
+
add("unknown_context", entry.id);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (entry.compatible_ids.some(id => entry.forbidden_ids.includes(id))
|
|
75
|
+
|| entry.compatible_ids.length && entry.forbidden_operations.includes(entry.expected_operation)
|
|
76
|
+
|| entry.cohorts.includes("true_no_match") && entry.compatible_ids.length)
|
|
77
|
+
add("contradictory_labels", entry.id);
|
|
78
|
+
let eligible;
|
|
79
|
+
try {
|
|
80
|
+
eligible = new Set(captureEligibility(routeFor(suite, entry, registry)).eligible.map(x => x.manifest.id));
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
add("invalid_context", entry.id);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
for (const id of [...entry.compatible_ids, ...entry.forbidden_ids]) {
|
|
87
|
+
const capability = registry.capabilityById.get(id)?.manifest;
|
|
88
|
+
if (!capability) {
|
|
89
|
+
add("unknown_capability", entry.id);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (entry.compatible_ids.includes(id) && (!eligible.has(id) || operationFor(capability) !== entry.expected_operation
|
|
93
|
+
|| capability.lifecycle.commit || capability.capability_type === "write_commit"))
|
|
94
|
+
add("invalid_compatible_capability", entry.id);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
add("invalid_suite_bindings");
|
|
100
|
+
}
|
|
101
|
+
return errors;
|
|
102
|
+
}
|
|
103
|
+
const operationFor = (capability) => capability.lifecycle.commit
|
|
104
|
+
|| capability.capability_type === "write_commit" ? "commit" : capability.lifecycle.prepare ? "prepare" : "read";
|
|
105
|
+
const rate = (numerator, denominator) => ({ numerator, denominator, value: denominator ? numerator / denominator : null });
|
|
106
|
+
function distribution(values) {
|
|
107
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
108
|
+
let mean = 0;
|
|
109
|
+
values.forEach((value, index) => { mean += (value - mean) / (index + 1); });
|
|
110
|
+
return { count: values.length, minimum: sorted[0] ?? null, maximum: sorted.at(-1) ?? null,
|
|
111
|
+
mean: values.length ? mean : null,
|
|
112
|
+
p95: sorted[Math.ceil(sorted.length * 0.95) - 1] ?? null };
|
|
113
|
+
}
|
|
114
|
+
/** Scores observations only. It never calls a ranker, model, embedding client, or executor. */
|
|
115
|
+
export function evaluateCapabilityDiscovery(request) {
|
|
116
|
+
const errors = [...validateDiscoveryEvaluationSuite(request.suite, request.registry)];
|
|
117
|
+
const suite = evaluationSuiteSnapshot(request.suite);
|
|
118
|
+
const observations = evaluationObservationsSnapshot(request.observations);
|
|
119
|
+
if (!observations)
|
|
120
|
+
errors.push({ code: "invalid_observations_schema" });
|
|
121
|
+
const caseIds = request.caseIds;
|
|
122
|
+
if (caseIds !== undefined && (!Array.isArray(caseIds) || caseIds.length > (suite?.cases.length ?? 0) || !Array.from(caseIds).every(id => typeof id === "string")
|
|
123
|
+
|| new Set(caseIds).size !== caseIds.length || caseIds.some(id => !suite?.cases.some(entry => entry.id === id)))) {
|
|
124
|
+
errors.push({ code: "invalid_evaluation_scope" });
|
|
125
|
+
}
|
|
126
|
+
if (errors.length || !suite || !observations)
|
|
127
|
+
return { valid: false, diagnostics: deepFreeze(errors) };
|
|
128
|
+
try {
|
|
129
|
+
return evaluate(suite, observations, request.registry, caseIds);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return { valid: false, diagnostics: [{ code: "invalid_evaluation_bindings" }] };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function evaluate(suite, observations, registry, caseIds) {
|
|
136
|
+
const errors = [];
|
|
137
|
+
const add = (code, caseId) => { if (errors.length < 64)
|
|
138
|
+
errors.push({ code, ...(caseId ? { caseId } : {}) }); };
|
|
139
|
+
const configuration = resolveDiscoveryConfiguration(observations.configuration);
|
|
140
|
+
if (hashDiscoveryContent(configuration) !== hashDiscoveryContent(observations.configuration))
|
|
141
|
+
add("unresolved_configuration");
|
|
142
|
+
const corpus = buildCapabilitySearchCorpus(registry);
|
|
143
|
+
const suiteFingerprint = fingerprintDiscoveryEvaluationSuite(suite);
|
|
144
|
+
if (observations.suite_id !== suite.id || observations.suite_fingerprint !== suiteFingerprint
|
|
145
|
+
|| observations.registry_source_fingerprint !== corpus.registrySourceFingerprint || observations.corpus_fingerprint !== corpus.corpusFingerprint
|
|
146
|
+
|| observations.retrieval_policy_fingerprint !== retrievalPolicyFingerprint(configuration, observations.custom_ranker_version))
|
|
147
|
+
add("observation_binding_mismatch");
|
|
148
|
+
const definitions = new Map(suite.cases.map(entry => [entry.id, entry]));
|
|
149
|
+
const scope = new Set(caseIds ?? suite.cases.map(entry => entry.id));
|
|
150
|
+
const expectedCases = suite.cases.filter(entry => scope.has(entry.id));
|
|
151
|
+
const scopeFingerprint = hashDiscoveryContent({ kind: "discovery_evaluation_scope", version: "1.0", suiteFingerprint,
|
|
152
|
+
caseIds: [...scope].sort() });
|
|
153
|
+
const seen = new Set();
|
|
154
|
+
const retrievalOutcomes = { matched: 0, no_match: 0, unavailable: 0, cancelled: 0 };
|
|
155
|
+
const selectionOutcomes = { selected: 0, abstained: 0, unavailable: 0, invalid_output: 0, cancelled: 0, not_performed: 0 };
|
|
156
|
+
const byPartition = Object.create(null), byDomain = Object.create(null), byCohort = Object.create(null);
|
|
157
|
+
let hits = 0, topHits = 0, nonempty = 0, noMatchFalsePositives = 0;
|
|
158
|
+
let forbiddenCandidates = 0, policyCandidateCases = 0, readMutationCases = 0;
|
|
159
|
+
let selectedMatched = 0, correctSelected = 0, covered = 0, answerableMatched = 0, submitted = 0;
|
|
160
|
+
let forbiddenChoices = 0, policyChoices = 0, readMutationChoices = 0;
|
|
161
|
+
let noMatchSelections = 0;
|
|
162
|
+
const sizes = [], latencies = [];
|
|
163
|
+
for (const observed of observations.cases) {
|
|
164
|
+
const entry = definitions.get(observed.case_id);
|
|
165
|
+
if (!entry) {
|
|
166
|
+
add("foreign_observation", observed.case_id);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (!scope.has(entry.id)) {
|
|
170
|
+
add("observation_outside_scope", entry.id);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (seen.has(entry.id)) {
|
|
174
|
+
add("duplicate_observation", entry.id);
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
seen.add(entry.id);
|
|
178
|
+
const eligibility = captureEligibility(routeFor(suite, entry, registry));
|
|
179
|
+
const eligible = new Set(eligibility.eligible.map(x => x.manifest.id));
|
|
180
|
+
if (observed.eligibility_fingerprint !== eligibility.fingerprint)
|
|
181
|
+
add("eligibility_binding_mismatch", entry.id);
|
|
182
|
+
if ((observed.status === "matched") !== !!observed.candidates.length || observed.candidates.length > configuration.limits.maxCandidates
|
|
183
|
+
|| (observed.status === "unavailable" || observed.status === "cancelled") !== (observed.actual_mode === null)
|
|
184
|
+
|| configuration.mode === "lexical" && observed.actual_mode === "hybrid"
|
|
185
|
+
|| configuration.mode === "hybrid" && observed.actual_mode === "lexical" && configuration.failurePolicy !== "lexical_fallback"
|
|
186
|
+
|| observed.actual_mode === "hybrid" && observed.status === "matched" && !observed.index_fingerprint)
|
|
187
|
+
add("invalid_retrieval_observation", entry.id);
|
|
188
|
+
const candidateIds = new Set();
|
|
189
|
+
let forbidden = false, policy = false, readMutation = false;
|
|
190
|
+
for (const candidate of observed.candidates) {
|
|
191
|
+
const manifest = registry.capabilityById.get(candidate.capability_id)?.manifest;
|
|
192
|
+
if (!manifest || manifest.version !== candidate.capability_version || candidateIds.has(candidate.capability_id)) {
|
|
193
|
+
add("invalid_candidate_binding", entry.id);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
candidateIds.add(candidate.capability_id);
|
|
197
|
+
const operation = operationFor(manifest);
|
|
198
|
+
forbidden ||= entry.forbidden_ids.includes(manifest.id) || entry.forbidden_operations.includes(operation);
|
|
199
|
+
policy ||= !eligible.has(manifest.id) || operation === "commit";
|
|
200
|
+
readMutation ||= entry.expected_operation === "read" && operation !== "read";
|
|
201
|
+
}
|
|
202
|
+
if (forbidden)
|
|
203
|
+
forbiddenCandidates++;
|
|
204
|
+
if (policy)
|
|
205
|
+
policyCandidateCases++;
|
|
206
|
+
if (readMutation)
|
|
207
|
+
readMutationCases++;
|
|
208
|
+
retrievalOutcomes[observed.status]++;
|
|
209
|
+
if (observed.candidates.length)
|
|
210
|
+
nonempty++;
|
|
211
|
+
if (entry.compatible_ids.some(id => candidateIds.has(id)))
|
|
212
|
+
hits++;
|
|
213
|
+
if (observed.candidates[0] && entry.compatible_ids.includes(observed.candidates[0].capability_id))
|
|
214
|
+
topHits++;
|
|
215
|
+
if (entry.cohorts.includes("true_no_match") && candidateIds.size)
|
|
216
|
+
noMatchFalsePositives++;
|
|
217
|
+
sizes.push(observed.candidates.length);
|
|
218
|
+
latencies.push(observed.latency_ms);
|
|
219
|
+
byPartition[entry.partition] = (byPartition[entry.partition] ?? 0) + 1;
|
|
220
|
+
byDomain[entry.domain] = (byDomain[entry.domain] ?? 0) + 1;
|
|
221
|
+
for (const cohort of entry.cohorts)
|
|
222
|
+
byCohort[cohort] = (byCohort[cohort] ?? 0) + 1;
|
|
223
|
+
const selection = observed.selection;
|
|
224
|
+
const answerable = entry.compatible_ids.length > 0;
|
|
225
|
+
if (answerable && observed.status === "matched")
|
|
226
|
+
answerableMatched++;
|
|
227
|
+
const status = selection?.status ?? "not_performed";
|
|
228
|
+
selectionOutcomes[status]++;
|
|
229
|
+
if (status !== "not_performed") {
|
|
230
|
+
submitted++;
|
|
231
|
+
if (observed.status !== "matched")
|
|
232
|
+
add("selection_without_shortlist", entry.id);
|
|
233
|
+
}
|
|
234
|
+
if (selection?.status === "selected") {
|
|
235
|
+
const manifest = registry.capabilityById.get(selection.capability_id)?.manifest;
|
|
236
|
+
if (!manifest || !candidateIds.has(manifest.id) || manifest.version !== selection.capability_version
|
|
237
|
+
|| operationFor(manifest) !== selection.operation) {
|
|
238
|
+
add("invalid_selection_binding", entry.id);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (answerable) {
|
|
242
|
+
selectedMatched++;
|
|
243
|
+
covered++;
|
|
244
|
+
if (entry.compatible_ids.includes(manifest.id))
|
|
245
|
+
correctSelected++;
|
|
246
|
+
}
|
|
247
|
+
if (entry.cohorts.includes("true_no_match"))
|
|
248
|
+
noMatchSelections++;
|
|
249
|
+
if (entry.forbidden_ids.includes(manifest.id) || entry.forbidden_operations.includes(selection.operation))
|
|
250
|
+
forbiddenChoices++;
|
|
251
|
+
if (!eligible.has(manifest.id) || selection.operation === "commit")
|
|
252
|
+
policyChoices++;
|
|
253
|
+
if (entry.expected_operation === "read" && selection.operation !== "read")
|
|
254
|
+
readMutationChoices++;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const attempts = new Map();
|
|
258
|
+
for (const attempt of observations.attempts) {
|
|
259
|
+
const key = JSON.stringify([attempt.run_id, attempt.attempt_id]);
|
|
260
|
+
const previous = attempts.get(key);
|
|
261
|
+
if (previous && hashDiscoveryContent(previous) !== hashDiscoveryContent(attempt))
|
|
262
|
+
add("conflicting_attempt_receipt");
|
|
263
|
+
attempts.set(key, attempt);
|
|
264
|
+
if (attempt.completed_responses > attempt.provider_attempts || attempt.retry_attempts > attempt.provider_attempts
|
|
265
|
+
|| attempt.repair_attempts > attempt.provider_attempts)
|
|
266
|
+
add("invalid_attempt_counts");
|
|
267
|
+
}
|
|
268
|
+
if (errors.length)
|
|
269
|
+
return { valid: false, diagnostics: deepFreeze(errors) };
|
|
270
|
+
const stages = [...attempts.values()].map(attempt => ({
|
|
271
|
+
attemptId: JSON.stringify([attempt.run_id, attempt.attempt_id]), stage: attempt.stage, configuration: attempt.configuration,
|
|
272
|
+
mock: attempt.mock, pending: attempt.pending, outcome: attempt.outcome, cacheHits: 0,
|
|
273
|
+
providerAttempts: attempt.provider_attempts, completedResponses: attempt.completed_responses,
|
|
274
|
+
retryAttempts: attempt.retry_attempts, repairAttempts: attempt.repair_attempts, elapsedMs: attempt.elapsed_ms,
|
|
275
|
+
...usageQuantities(attempt.usage, attempt.provider_attempts === 0)
|
|
276
|
+
}));
|
|
277
|
+
const elapsed = stages.reduce((sum, stage) => sum + stage.elapsedMs, 0);
|
|
278
|
+
if (!Number.isFinite(elapsed)
|
|
279
|
+
|| ["providerAttempts", "completedResponses", "retryAttempts", "repairAttempts"].some(key => !Number.isSafeInteger(stages.reduce((sum, stage) => sum + stage[key], 0)))
|
|
280
|
+
|| USAGE_QUANTITIES.some(key => {
|
|
281
|
+
const total = stages.reduce((sum, stage) => sum + stage[key].knownSubtotal, 0);
|
|
282
|
+
return !Number.isFinite(total) || key !== "estimatedCost" && !Number.isSafeInteger(total);
|
|
283
|
+
}))
|
|
284
|
+
return { valid: false, diagnostics: [{ code: "invalid_accounting_totals" }] };
|
|
285
|
+
let usage = aggregateProviderUsage(stages, elapsed);
|
|
286
|
+
if (!observations.usage_complete) {
|
|
287
|
+
const totals = { ...usage.totals };
|
|
288
|
+
for (const key of USAGE_QUANTITIES)
|
|
289
|
+
totals[key] = { total: null, complete: false, knownSubtotal: totals[key].knownSubtotal };
|
|
290
|
+
usage = deepFreeze({ stages: usage.stages, totals });
|
|
291
|
+
}
|
|
292
|
+
// Missing cases stay in recall/no-match denominators; partial runs cannot inflate them.
|
|
293
|
+
const answerable = expectedCases.filter(entry => entry.compatible_ids.length).length;
|
|
294
|
+
const trueNoMatch = expectedCases.filter(entry => entry.cohorts.includes("true_no_match")).length;
|
|
295
|
+
return { valid: true, diagnostics: [], report: deepFreeze({
|
|
296
|
+
suiteFingerprint, scopeFingerprint, complete: seen.size === expectedCases.length, semanticQualityQualified: false,
|
|
297
|
+
counts: { expected: expectedCases.length, observed: seen.size, missing: expectedCases.length - seen.size, byPartition, byDomain, byCohort },
|
|
298
|
+
retrieval: { k: configuration.limits.maxCandidates, compatibleRecallAtK: rate(hits, answerable), topOnePrecision: rate(topHits, nonempty),
|
|
299
|
+
noMatchFalsePositiveRate: rate(noMatchFalsePositives, trueNoMatch), shortlistSize: distribution(sizes), outcomes: retrievalOutcomes,
|
|
300
|
+
forbiddenCandidateCases: forbiddenCandidates, policyViolationCases: policyCandidateCases, readToMutationCases: readMutationCases },
|
|
301
|
+
selection: { outcomes: selectionOutcomes, compatibleAccuracy: rate(correctSelected, selectedMatched),
|
|
302
|
+
abstentionRate: rate(selectionOutcomes.abstained, submitted), coverage: rate(covered, answerableMatched),
|
|
303
|
+
noMatchFalseSelectionRate: rate(noMatchSelections, trueNoMatch),
|
|
304
|
+
forbiddenChoices, policyViolations: policyChoices, readToMutationChoices: readMutationChoices },
|
|
305
|
+
latencyMs: distribution(latencies), accountingComplete: observations.usage_complete,
|
|
306
|
+
usageComplete: observations.usage_complete && stages.every(stage => !stage.pending) && USAGE_QUANTITIES.every(key => usage.totals[key].complete), usage,
|
|
307
|
+
provenance: { mockAttempts: stages.filter(stage => stage.mock).reduce((sum, x) => sum + x.providerAttempts, 0),
|
|
308
|
+
liveAttempts: stages.filter(stage => !stage.mock).reduce((sum, x) => sum + x.providerAttempts, 0), pendingAttempts: stages.filter(stage => stage.pending).length }
|
|
309
|
+
}) };
|
|
310
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CapabilityRouteRequest } from "../runtime/types.js";
|
|
2
|
+
import type { CapabilityDiscoveryResult, CapabilitySelectionBatchResult, DiscoveryRouteResult } from "./types.js";
|
|
3
|
+
export declare function validateRouterLimit(limit: number | undefined): void;
|
|
4
|
+
/** A task-local selector decision narrows an already validated shortlist. */
|
|
5
|
+
export declare function exportSelectedResult(request: CapabilityRouteRequest & {
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
deadlineAt?: number;
|
|
8
|
+
}, original: CapabilityDiscoveryResult, batch: CapabilitySelectionBatchResult, source: string, current?: boolean): DiscoveryRouteResult;
|
|
9
|
+
/** Shared final gate for fresh retrieval and request-bound shortlist reuse. */
|
|
10
|
+
export declare function exportDiscoveryResult(request: CapabilityRouteRequest & {
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
deadlineAt?: number;
|
|
13
|
+
}, original: CapabilityDiscoveryResult, sourceFingerprint: string, bindingCurrent?: boolean): DiscoveryRouteResult;
|
|
14
|
+
//# sourceMappingURL=export.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/discovery/export.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAKlE,OAAO,KAAK,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAInE;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,sBAAsB,GAAG;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/E,QAAQ,EAAE,yBAAyB,EAAE,KAAK,EAAE,8BAA8B,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,UAAO,GACzG,oBAAoB,CAetB;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,sBAAsB,GAAG;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAC/E,QAAQ,EAAE,yBAAyB,EACnC,iBAAiB,EAAE,MAAM,EACzB,cAAc,UAAO,GACpB,oBAAoB,CAkDtB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { captureEligibility } from "./bindings.js";
|
|
2
|
+
import { registrySourceFingerprint } from "./corpus.js";
|
|
3
|
+
import { discoveryStopReason } from "./discoverer.js";
|
|
4
|
+
import { DiscoveryError } from "./diagnostics.js";
|
|
5
|
+
export function validateRouterLimit(limit) {
|
|
6
|
+
if (limit !== undefined && (!Number.isInteger(limit) || limit < 1 || limit > 20)) {
|
|
7
|
+
throw new DiscoveryError({ code: "invalid_input", message: "maxCapabilities must be an integer from 1 through 20." });
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
/** A task-local selector decision narrows an already validated shortlist. */
|
|
11
|
+
export function exportSelectedResult(request, original, batch, source, current = true) {
|
|
12
|
+
const exported = exportDiscoveryResult(request, original, source, current);
|
|
13
|
+
const outcome = batch.outcomes.find(item => item.queryId === original.queryId);
|
|
14
|
+
const selected = outcome?.status === "selected" && exported.discovery[0]?.status === "matched"
|
|
15
|
+
&& request.registry.capabilityById.get(outcome.capabilityId)?.manifest.version === outcome.capabilityVersion
|
|
16
|
+
? outcome.capabilityId : undefined;
|
|
17
|
+
const items = exported.slice.items.filter(item => item.capabilityId === selected).map(item => ({ ...item,
|
|
18
|
+
reasons: ["Selected for this task by the explicitly configured selector; execution authorization remains required."] }));
|
|
19
|
+
return { ...exported, selection: batch.outcomes, selectionBatch: batch, slice: {
|
|
20
|
+
items, excluded: [...exported.slice.excluded, ...exported.slice.items.filter(item => item.capabilityId !== selected)
|
|
21
|
+
.map(item => ({ capabilityId: item.capabilityId, reason: "Capability was not selected for this task." }))],
|
|
22
|
+
warnings: items.length ? exported.slice.warnings : [...exported.slice.warnings, {
|
|
23
|
+
code: "selection_" + (outcome?.status ?? "not_submitted"), message: "Selection did not provide a current actionable capability for this task."
|
|
24
|
+
}]
|
|
25
|
+
} };
|
|
26
|
+
}
|
|
27
|
+
/** Shared final gate for fresh retrieval and request-bound shortlist reuse. */
|
|
28
|
+
export function exportDiscoveryResult(request, original, sourceFingerprint, bindingCurrent = true) {
|
|
29
|
+
let result = original;
|
|
30
|
+
let eligibility;
|
|
31
|
+
let current = false;
|
|
32
|
+
try {
|
|
33
|
+
eligibility = captureEligibility(request);
|
|
34
|
+
current = bindingCurrent && eligibility.fingerprint === result.eligibilityFingerprint
|
|
35
|
+
&& registrySourceFingerprint(request.registry) === sourceFingerprint;
|
|
36
|
+
}
|
|
37
|
+
catch { /* Invalidated live registries cannot yield a tool slice. */ }
|
|
38
|
+
const stop = discoveryStopReason(request);
|
|
39
|
+
if (stop || (!current && result.status === "matched")) {
|
|
40
|
+
const code = stop ?? "stale_binding";
|
|
41
|
+
result = {
|
|
42
|
+
...result, status: stop ? "cancelled" : "unavailable", actualMode: null, candidates: [],
|
|
43
|
+
diagnostics: [{ code, queryId: result.queryId, message: stop
|
|
44
|
+
? "Discovery was cancelled or its deadline elapsed." : "Discovery bindings changed before tool export." }]
|
|
45
|
+
};
|
|
46
|
+
delete result.indexFingerprint;
|
|
47
|
+
}
|
|
48
|
+
const candidates = result.status === "matched" ? result.candidates.slice(0, request.maxCapabilities ?? result.candidates.length) : [];
|
|
49
|
+
const selected = new Set(candidates.map(candidate => candidate.capabilityId));
|
|
50
|
+
const excluded = [...(eligibility?.excluded ?? [])];
|
|
51
|
+
for (const entry of eligibility?.eligible ?? []) {
|
|
52
|
+
if (!selected.has(entry.manifest.id))
|
|
53
|
+
excluded.push({
|
|
54
|
+
capabilityId: entry.manifest.id, reason: "Capability was not included in the retrieval shortlist."
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const warnings = result.status === "matched" ? [] : [{
|
|
58
|
+
code: "discovery_" + result.status,
|
|
59
|
+
message: result.status === "no_match" ? "Discovery found no eligible candidates meeting the retrieval policy."
|
|
60
|
+
: result.status === "cancelled" ? "Discovery was cancelled or its deadline elapsed."
|
|
61
|
+
: "Discovery is unavailable; no tools were shortlisted."
|
|
62
|
+
}];
|
|
63
|
+
if (result.actualMode === "lexical" && result.degradedReason)
|
|
64
|
+
warnings.push({
|
|
65
|
+
code: "discovery_lexical_fallback", message: "Discovery used the configured whole-query lexical fallback policy."
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
discovery: [result],
|
|
69
|
+
slice: {
|
|
70
|
+
items: candidates.map(candidate => {
|
|
71
|
+
const manifest = request.registry.capabilityById.get(candidate.capabilityId).manifest;
|
|
72
|
+
return {
|
|
73
|
+
capabilityId: candidate.capabilityId, score: candidate.scores.final,
|
|
74
|
+
exposedOperations: manifest.lifecycle.prepare ? ["select", "prepare"] : ["select"],
|
|
75
|
+
reasons: ["Included by the retrieval policy; ordinary tool selection is required."]
|
|
76
|
+
};
|
|
77
|
+
}),
|
|
78
|
+
excluded, warnings
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { AicfProviderRun } from "../runtime/provider-types.js";
|
|
2
|
+
import type { AicfCapabilityRouter, AicfContextBuilder, AicfRuntimeContext, CapabilityRouteRequest } from "../runtime/types.js";
|
|
3
|
+
import type { ManifestRegistry } from "../types.js";
|
|
4
|
+
import type { DiscoveryBudgetScope } from "./budget.js";
|
|
5
|
+
import type { EmbeddingExecutionOptions, EmbeddingIndexLimits } from "./embedding-types.js";
|
|
6
|
+
import type { CapabilitySelectRequest } from "./selection-types.js";
|
|
7
|
+
import type { CapabilityDiscoveryResult, CapabilityLexicalRanker, CapabilitySelectionBatchResult, DiscoveryLimits, DiscoveryRouteResult, EmbeddingClient, HybridDiscoveryConfiguration } from "./types.js";
|
|
8
|
+
export declare const DISCOVERY_STANDARD_PROFILE: {
|
|
9
|
+
policyVersion: string;
|
|
10
|
+
timeoutMs: number;
|
|
11
|
+
weights: {
|
|
12
|
+
semantic: number;
|
|
13
|
+
lexical: number;
|
|
14
|
+
};
|
|
15
|
+
failurePolicy: "unavailable";
|
|
16
|
+
indexLimits: {
|
|
17
|
+
maxArtifactBytes: number;
|
|
18
|
+
maxEntries: number;
|
|
19
|
+
maxVectorDimension: number;
|
|
20
|
+
};
|
|
21
|
+
maxCharactersPerText: number;
|
|
22
|
+
maxCharactersPerCall: number;
|
|
23
|
+
};
|
|
24
|
+
/** @inline */
|
|
25
|
+
interface CapabilityDiscoveryOptionsBase {
|
|
26
|
+
registry: ManifestRegistry;
|
|
27
|
+
contextBuilder?: AicfContextBuilder;
|
|
28
|
+
ranker?: CapabilityLexicalRanker;
|
|
29
|
+
policyVersion?: string;
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
limits?: Partial<DiscoveryLimits>;
|
|
32
|
+
aliasWeight?: number;
|
|
33
|
+
minRetrievalScore?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface CapabilityDiscoveryEmbeddingOptions {
|
|
36
|
+
client: EmbeddingClient;
|
|
37
|
+
index: unknown;
|
|
38
|
+
maxInputTokens: number;
|
|
39
|
+
indexLimits?: Partial<EmbeddingIndexLimits>;
|
|
40
|
+
maxCharactersPerText?: number;
|
|
41
|
+
maxCharactersPerCall?: number;
|
|
42
|
+
maxEstimatedCostPerCall?: number;
|
|
43
|
+
estimateCost?: EmbeddingExecutionOptions["estimateCost"];
|
|
44
|
+
}
|
|
45
|
+
export type CapabilityDiscoveryOptions = CapabilityDiscoveryOptionsBase & ({
|
|
46
|
+
mode?: "lexical";
|
|
47
|
+
embedding?: never;
|
|
48
|
+
weights?: never;
|
|
49
|
+
failurePolicy?: never;
|
|
50
|
+
} | {
|
|
51
|
+
mode: "hybrid";
|
|
52
|
+
embedding: CapabilityDiscoveryEmbeddingOptions;
|
|
53
|
+
weights?: HybridDiscoveryConfiguration["weights"];
|
|
54
|
+
failurePolicy?: HybridDiscoveryConfiguration["failurePolicy"];
|
|
55
|
+
});
|
|
56
|
+
export type CapabilityDiscoveryEligibility = Omit<CapabilityRouteRequest, "registry" | "builtContext" | "userInput" | "controls">;
|
|
57
|
+
export interface CapabilitySearchRequest {
|
|
58
|
+
providerRun?: AicfProviderRun;
|
|
59
|
+
tasks: readonly {
|
|
60
|
+
id: string;
|
|
61
|
+
text: string;
|
|
62
|
+
}[];
|
|
63
|
+
runtimeContext: AicfRuntimeContext;
|
|
64
|
+
controls?: CapabilityRouteRequest["controls"];
|
|
65
|
+
eligibility?: CapabilityDiscoveryEligibility;
|
|
66
|
+
signal?: AbortSignal;
|
|
67
|
+
deadlineAt?: number;
|
|
68
|
+
budget?: DiscoveryBudgetScope;
|
|
69
|
+
}
|
|
70
|
+
export interface CapabilityResultRouter extends AicfCapabilityRouter {
|
|
71
|
+
routeWithDiagnostics(request: CapabilityRouteRequest): DiscoveryRouteResult;
|
|
72
|
+
}
|
|
73
|
+
export interface CapabilityDiscovery {
|
|
74
|
+
search(request: CapabilitySearchRequest): Promise<readonly CapabilityDiscoveryResult[]>;
|
|
75
|
+
select(request: CapabilitySelectRequest): Promise<CapabilitySelectionBatchResult>;
|
|
76
|
+
routerFor(result: CapabilityDiscoveryResult): CapabilityResultRouter;
|
|
77
|
+
routerFor(batch: CapabilitySelectionBatchResult, queryId: string): CapabilityResultRouter;
|
|
78
|
+
}
|
|
79
|
+
/** Simple application-driven search. Model choice and execution stay in the ordinary runtime. */
|
|
80
|
+
export declare function createCapabilityDiscovery(options: CapabilityDiscoveryOptions): CapabilityDiscovery;
|
|
81
|
+
export {};
|
|
82
|
+
//# sourceMappingURL=facade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"facade.d.ts","sourceRoot":"","sources":["../../src/discovery/facade.ts"],"names":[],"mappings":"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"}
|