nexus-ai-pro 2.13.0 → 2.15.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/API_STABILITY.md +51 -0
- package/CHANGELOG.md +69 -1
- package/README.md +16 -7
- package/dist/adapter-kit/contracts.d.ts +27 -1
- package/dist/adapter-kit/contracts.js +21 -0
- package/dist/adapter-kit/index.d.ts +16 -1
- package/dist/adapter-kit/index.js +13 -3
- package/dist/adapter-kit/record.d.ts +150 -0
- package/dist/adapter-kit/record.js +252 -0
- package/dist/batch/anthropic.js +3 -1
- package/dist/batch/manager.d.ts +5 -0
- package/dist/batch/manager.js +25 -9
- package/dist/batch/openai-client.js +3 -1
- package/dist/cli/adapters.d.ts +10 -0
- package/dist/cli/adapters.js +229 -0
- package/dist/cli/args.js +2 -0
- package/dist/cli/policy.d.ts +10 -0
- package/dist/cli/policy.js +116 -0
- package/dist/cli.js +26 -7
- package/dist/core/lifecycle.d.ts +23 -3
- package/dist/core/lifecycle.js +76 -13
- package/dist/core/nexus.d.ts +14 -14
- package/dist/core/nexus.js +26 -26
- package/dist/embeddings/batch-google.js +7 -1
- package/dist/embeddings/batch.d.ts +7 -0
- package/dist/embeddings/batch.js +32 -9
- package/dist/embeddings/engine.js +1 -1
- package/dist/evaluate/emulate.d.ts +143 -0
- package/dist/evaluate/emulate.js +214 -0
- package/dist/images/operation.js +1 -1
- package/dist/lifecycle/continue.d.ts +12 -0
- package/dist/lifecycle/continue.js +14 -0
- package/dist/media/index.d.ts +14 -1
- package/dist/media/index.js +16 -6
- package/dist/media/mistral.js +3 -1
- package/dist/policy/index.d.ts +184 -0
- package/dist/policy/index.js +490 -0
- package/dist/realtime/gemini-live.transport.js +3 -0
- package/dist/realtime/openai-server.d.ts +21 -4
- package/dist/realtime/openai-server.js +40 -19
- package/dist/realtime/openai-websocket.transport.d.ts +1 -0
- package/dist/realtime/openai-websocket.transport.js +12 -7
- package/dist/realtime/session.js +8 -2
- package/dist/realtime/types.d.ts +8 -1
- package/dist/telephony/manager.js +21 -15
- package/dist/telephony/providers/telnyx.d.ts +14 -13
- package/dist/telephony/providers/telnyx.js +36 -20
- package/dist/telephony/providers/twilio.d.ts +18 -13
- package/dist/telephony/providers/twilio.js +48 -24
- package/dist/types/batch.d.ts +5 -0
- package/dist/types/config.d.ts +3 -1
- package/dist/types/lifecycle.d.ts +40 -0
- package/dist/types/residency.d.ts +19 -7
- package/dist/types/telephony.d.ts +26 -0
- package/dist/types/voice.d.ts +4 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/video/google.js +11 -2
- package/dist/video/index.d.ts +10 -0
- package/dist/video/index.js +39 -14
- package/dist/video/runway.js +4 -1
- package/dist/voice/manager.js +14 -2
- package/dist/voice/providers/openai.d.ts +3 -2
- package/dist/voice/providers/openai.js +9 -10
- package/dist-cjs/adapter-kit/contracts.d.ts +27 -1
- package/dist-cjs/adapter-kit/contracts.js +22 -1
- package/dist-cjs/adapter-kit/index.d.ts +16 -1
- package/dist-cjs/adapter-kit/index.js +21 -2
- package/dist-cjs/adapter-kit/record.d.ts +150 -0
- package/dist-cjs/adapter-kit/record.js +262 -0
- package/dist-cjs/batch/anthropic.js +3 -1
- package/dist-cjs/batch/manager.d.ts +5 -0
- package/dist-cjs/batch/manager.js +25 -9
- package/dist-cjs/batch/openai-client.js +3 -1
- package/dist-cjs/cli/adapters.d.ts +10 -0
- package/dist-cjs/cli/adapters.js +268 -0
- package/dist-cjs/cli/args.js +2 -0
- package/dist-cjs/cli/policy.d.ts +10 -0
- package/dist-cjs/cli/policy.js +122 -0
- package/dist-cjs/core/lifecycle.d.ts +23 -3
- package/dist-cjs/core/lifecycle.js +77 -13
- package/dist-cjs/core/nexus.d.ts +14 -14
- package/dist-cjs/core/nexus.js +34 -34
- package/dist-cjs/embeddings/batch-google.js +7 -1
- package/dist-cjs/embeddings/batch.d.ts +7 -0
- package/dist-cjs/embeddings/batch.js +32 -9
- package/dist-cjs/embeddings/engine.js +1 -1
- package/dist-cjs/evaluate/emulate.d.ts +143 -0
- package/dist-cjs/evaluate/emulate.js +221 -0
- package/dist-cjs/images/operation.js +1 -1
- package/dist-cjs/lifecycle/continue.d.ts +12 -0
- package/dist-cjs/lifecycle/continue.js +17 -0
- package/dist-cjs/media/index.d.ts +14 -1
- package/dist-cjs/media/index.js +16 -6
- package/dist-cjs/media/mistral.js +3 -1
- package/dist-cjs/policy/index.d.ts +184 -0
- package/dist-cjs/policy/index.js +500 -0
- package/dist-cjs/realtime/gemini-live.transport.js +3 -0
- package/dist-cjs/realtime/openai-server.d.ts +21 -4
- package/dist-cjs/realtime/openai-server.js +40 -19
- package/dist-cjs/realtime/openai-websocket.transport.d.ts +1 -0
- package/dist-cjs/realtime/openai-websocket.transport.js +12 -7
- package/dist-cjs/realtime/session.js +8 -2
- package/dist-cjs/realtime/types.d.ts +8 -1
- package/dist-cjs/telephony/manager.js +21 -15
- package/dist-cjs/telephony/providers/telnyx.d.ts +14 -13
- package/dist-cjs/telephony/providers/telnyx.js +36 -20
- package/dist-cjs/telephony/providers/twilio.d.ts +18 -13
- package/dist-cjs/telephony/providers/twilio.js +48 -24
- package/dist-cjs/types/batch.d.ts +5 -0
- package/dist-cjs/types/config.d.ts +3 -1
- package/dist-cjs/types/lifecycle.d.ts +40 -0
- package/dist-cjs/types/residency.d.ts +19 -7
- package/dist-cjs/types/telephony.d.ts +26 -0
- package/dist-cjs/types/voice.d.ts +4 -0
- package/dist-cjs/version.d.ts +1 -1
- package/dist-cjs/version.js +1 -1
- package/dist-cjs/video/google.js +11 -2
- package/dist-cjs/video/index.d.ts +10 -0
- package/dist-cjs/video/index.js +39 -14
- package/dist-cjs/video/runway.js +4 -1
- package/dist-cjs/voice/manager.js +14 -2
- package/dist-cjs/voice/providers/openai.d.ts +3 -2
- package/dist-cjs/voice/providers/openai.js +9 -10
- package/llms.txt +4 -3
- package/package.json +30 -2
package/API_STABILITY.md
CHANGED
|
@@ -41,6 +41,57 @@ Both are covered by this policy:
|
|
|
41
41
|
Deep imports into `dist`, `dist-cjs`, or `src` are not supported. Import only from `nexus-ai-pro` or
|
|
42
42
|
one of its explicit subpaths.
|
|
43
43
|
|
|
44
|
+
## 2.15 stage (2.15.0)
|
|
45
|
+
|
|
46
|
+
Everything 2.15 adds is stable from the start and additive, unless this section says otherwise.
|
|
47
|
+
|
|
48
|
+
New and stable:
|
|
49
|
+
- in `nexus-ai-pro/adapter-kit`: `Adapter.record()`, `compatibilityRecord()`, `readCompatibilityRecord()`,
|
|
50
|
+
`recordDigest()`, `recordStatus()`, `compareRecords()`, `compatibilityPage()`,
|
|
51
|
+
`CompatibilityRecordError`, `COMPATIBILITY_RECORD_FORMAT`, `CompatibilityRecord`,
|
|
52
|
+
`CompatibilityRecordAdapter`, `CompatibilityRecordOptions`, `CompatibilityStatus`,
|
|
53
|
+
`CompatibilityState`, `CompatibilityComparison`, `CheckChange`, `CompatibilityPageOptions`,
|
|
54
|
+
`ADAPTER_CONTRACTS`, `AdapterContract`, and `AdapterContractVersion`; `AdapterReport.contractVersion`,
|
|
55
|
+
`nexusRange`, `capabilities`, and `budgets`;
|
|
56
|
+
- the `nexus-compatibility/1` record format: a reader of one format version reads every record of it;
|
|
57
|
+
a new field may be added, and a record that needs it declares a new format;
|
|
58
|
+
- the `nexus adapters verify`, `page`, and `recheck` commands, their flags, and their exit codes;
|
|
59
|
+
- `OpenAIRealtimeServerOptions.credentials`, `tenantId`, and `provider`, the optional `apiKey`, and the
|
|
60
|
+
tenant the session endpoint takes per call.
|
|
61
|
+
|
|
62
|
+
A contract's version rises when a minor release adds a check, by the rule above; its history keeps
|
|
63
|
+
every version.
|
|
64
|
+
|
|
65
|
+
## 2.14 stage (2.14.0)
|
|
66
|
+
|
|
67
|
+
Everything 2.14 adds is stable from the start and additive, unless this section says otherwise.
|
|
68
|
+
|
|
69
|
+
New and stable:
|
|
70
|
+
- `nexus-ai-pro/policy`: `parsePolicy()`, `applyPolicy()`, `comparePolicies()`, `checkPolicyChange()`,
|
|
71
|
+
`providerGate()`, `policyHash()`, `PolicyError`, `Policy`, `PolicyDocument`, `PolicyAccess`,
|
|
72
|
+
`PolicyRouting`, `PolicyBudgets`, `PolicyResidency`, `PolicyCredentials`, `PolicyIssue`,
|
|
73
|
+
`ApplyPolicyOptions`, `PolicyChange`, `PolicyChangeKind`, and `PolicyCheck`;
|
|
74
|
+
- `LifecycleConfig.providers` and `policy`, `ProviderGate`, `PolicyReference`,
|
|
75
|
+
`OperationDescriptor.policy`, `AuditLogEvent.policy`, and `OperationLifecycle.access()`;
|
|
76
|
+
- the `nexus policy check` command, its flags, its exit codes, and its `--json` output;
|
|
77
|
+
- `nexus-ai-pro/evaluate/emulate`: `emulatedTools()`, `EmulatedToolsOptions`, `EmulatorClient`,
|
|
78
|
+
`EmulatedToolCall`, `EmulatedResult`, `EmulationStore`, `MemoryEmulationStore`, `EmulationError`, and
|
|
79
|
+
`emulationKey()`. What the emulator is told may be reworded in a minor release; a store's keys never
|
|
80
|
+
change within a major;
|
|
81
|
+
- `CallResidency.refusal()`, optional, and the optional `model` its `allows()`, `place()`, and
|
|
82
|
+
`check()` take;
|
|
83
|
+
- `OperationLifecycle.callContext()`, the optional `OperationLifecycleLike.callContext`, and
|
|
84
|
+
`ContinuedCallContext`;
|
|
85
|
+
- `tenantId` on `BatchSubmitRequest`, `EmbeddingBatchSubmitRequest`, `MediaReadRequest`,
|
|
86
|
+
`MediaDescribeRequest`, `MediaAnswerRequest`, `TranscriptionRequest`, `SpeechRequest`, and every
|
|
87
|
+
telephony request that takes a `signal`; `MediaCallContext.tenantId` and `credential`;
|
|
88
|
+
`RealtimeSessionConfig.credential`; the optional context the OpenAI voice adapter and the Twilio and
|
|
89
|
+
Telnyx adapters take on each method that calls their API.
|
|
90
|
+
|
|
91
|
+
The kinds `comparePolicies()` gives a change may be refined in a minor release: a change found to widen
|
|
92
|
+
what a tenant may reach is reported as `widened` from then on, so a check may start to ask for an
|
|
93
|
+
acknowledgment it did not ask for before. A check never stops asking for one it asked for.
|
|
94
|
+
|
|
44
95
|
## 2.13 stage (2.13.0)
|
|
45
96
|
|
|
46
97
|
Everything 2.13 adds is stable from the start and additive, unless this section says otherwise.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,72 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.15.0] - 2026-10-19
|
|
8
|
+
|
|
9
|
+
A compatibility record for community adapters, and realtime sessions minted with the tenant's key.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **A compatibility record for community adapters.** `adapter.record()` and `compatibilityRecord()`
|
|
14
|
+
seal what an adapter kit adapter's `verify()` proved: the contract version it passed, against which
|
|
15
|
+
release, its benchmark, its runtime, and a digest. `nexus adapters verify` makes one from the
|
|
16
|
+
adapter's own repository, `nexus adapters page` lists records on one page, and
|
|
17
|
+
`nexus adapters recheck` verifies each listed adapter again against the installed release and exits
|
|
18
|
+
1 when one that passed no longer does, naming the check. `recordStatus()` tells a passing record
|
|
19
|
+
from a failing, incompatible, or stale one, and `compareRecords()` what broke between two.
|
|
20
|
+
[COMPATIBILITY.md](./COMPATIBILITY.md) lists the adapters this repository ships, verified again by
|
|
21
|
+
every build.
|
|
22
|
+
- **Contracts, versioned.** `ADAPTER_CONTRACTS` gives each kind's contract version and what each
|
|
23
|
+
version added. The vector-store contract is at version 2: “adds a passage again under an id it
|
|
24
|
+
deleted”. An `AdapterReport` carries its `contractVersion`, `nexusRange`, `capabilities`, and
|
|
25
|
+
`budgets`.
|
|
26
|
+
- **Realtime sessions minted with the tenant's key.** The OpenAI realtime server helpers take the
|
|
27
|
+
client's `credentials` resolver and a `tenantId`: the session an SDP exchange makes and the client
|
|
28
|
+
secret a browser connects with use the tenant's key, a tenant without one is refused before anything
|
|
29
|
+
is sent, and the key is cleaned from every error. The session endpoint takes the tenant per call.
|
|
30
|
+
|
|
31
|
+
## [2.14.0] - 2026-10-19
|
|
32
|
+
|
|
33
|
+
Policy you can review, evaluation without side effects, and credentials per tenant in every family.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- **Policy you can review.** `nexus-ai-pro/policy` reads guardrails, routing, budgets, residency, and
|
|
38
|
+
credentials from one versioned file. `parsePolicy()` validates it as the client starts, naming every
|
|
39
|
+
issue; `applyPolicy()` turns it into the client's configuration; and every operation and audit event
|
|
40
|
+
records the policy's name, version, and content hash. `nexus policy check` compares a version with
|
|
41
|
+
the one before it, a file or `git:<ref>`, and fails the build on a change that widens what a tenant
|
|
42
|
+
may reach (a region, a provider, a model, a budget, lowered guardrails, a shared key) until it is
|
|
43
|
+
acknowledged in the file or with `--accept`, and on content changed without a new version.
|
|
44
|
+
- **Per-tenant routing rules.** `LifecycleConfig.providers` takes a `ProviderGate` that admits or
|
|
45
|
+
refuses each provider and model an operation would reach, checked wherever residency is: a refused
|
|
46
|
+
provider is refused with an `OperationDeniedError` naming the rule before anything is sent, a
|
|
47
|
+
completion's refused attempt is dropped from its route, and an embedding never falls back to a
|
|
48
|
+
refused model. `providerGate()` builds one from a policy's routing rules, with `*` wildcards.
|
|
49
|
+
- **Evaluation without side effects.** `emulatedTools()`, on the new `nexus-ai-pro/evaluate/emulate`,
|
|
50
|
+
returns an agent's tools answered by a model playing each one, told the tool, its result schema, a
|
|
51
|
+
scenario, real calls, and the run's earlier calls, and never run, so an evaluation of an agent that
|
|
52
|
+
charges cards or writes to a database sends nothing. Answers are kept by tool, arguments, scenario,
|
|
53
|
+
and call, and replayed, so a suite runs the same answers in CI without a model; tools that change
|
|
54
|
+
nothing can run for real.
|
|
55
|
+
- **Credentials per tenant in every family.** Video, media understanding, completion and embedding
|
|
56
|
+
batches, voice, telephony, and realtime sessions send the tenant's key, resolved by
|
|
57
|
+
`LifecycleConfig.credentials`, in place of the configured one, as completions, embeddings, and images
|
|
58
|
+
have since 2.13. Each takes `tenantId` on its requests. A video job's or a batch's ref records its
|
|
59
|
+
tenant, so `status()`, `resume()`, `cancel()`, and `download()` use the tenant's key and regions from
|
|
60
|
+
any process, through the new `OperationLifecycle.callContext()`. A Twilio tenant's calls go out on its
|
|
61
|
+
subaccount; an OpenAI SIP call keeps its project's key.
|
|
62
|
+
- `ai.lifecycle.access()` returns the `CallResidency` an operation would get, and
|
|
63
|
+
`CallResidency.refusal()` says why a provider would be refused once placed on its twin; `allows()`,
|
|
64
|
+
`place()`, and `check()` take the model as well.
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- `VideoManager.start()` and the calls on a video ref, and `EmbeddingBatchManager.start()` and the
|
|
69
|
+
calls on its refs, ran outside the client's residency policy; they are held to the tenant's regions
|
|
70
|
+
now. A durable video generation ran its operation without its tenant, so a tenant's budget and rate
|
|
71
|
+
limit did not apply to it.
|
|
72
|
+
|
|
7
73
|
## [2.13.0] - 2026-10-19
|
|
8
74
|
|
|
9
75
|
Regions and residency, and credentials per tenant.
|
|
@@ -2946,7 +3012,9 @@ shared policy vocabulary is in place for a future release that revisits this.
|
|
|
2946
3012
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
2947
3013
|
- CLI and audit findings no longer disclose detected secret values.
|
|
2948
3014
|
|
|
2949
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.
|
|
3015
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.15.0...HEAD
|
|
3016
|
+
[2.15.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.14.0...v2.15.0
|
|
3017
|
+
[2.14.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.13.0...v2.14.0
|
|
2950
3018
|
[2.13.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.12.0...v2.13.0
|
|
2951
3019
|
[2.12.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.11.0...v2.12.0
|
|
2952
3020
|
[2.11.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v2.10.0...v2.11.0
|
package/README.md
CHANGED
|
@@ -141,7 +141,7 @@ from the doc comments. The guides live in the repository, so these links go to G
|
|
|
141
141
|
| [MCP](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/mcp.md) | Borrowing tools from MCP servers, a registry of many, and serving your own |
|
|
142
142
|
| [Agent protocols](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/protocols.md) | Serving an agent to user interfaces over AG-UI, to other agents over A2A, and to code editors over ACP, and calling remote agents as tools |
|
|
143
143
|
| [Traces](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/tracing.md) | Run trees, queries, feedback, comparison, and alerts |
|
|
144
|
-
| [Evaluation](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/evaluation.md) | Datasets, evaluators, experiments, comparisons with a verdict, review queues, LLM judges |
|
|
144
|
+
| [Evaluation](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/evaluation.md) | Datasets, evaluators, experiments, comparisons with a verdict, review queues, LLM judges, and tools emulated by a model so an evaluation sends nothing |
|
|
145
145
|
| [Context hub](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/context-hub.md) | Prompts, instructions, tools, and skills versioned together, promoted through gates, and moved between projects |
|
|
146
146
|
| [Insights](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/insights.md) | Failing and slow runs clustered, regressions between time windows, and evaluated fix proposals |
|
|
147
147
|
| [Prompts](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/prompts.md) | Typed templates, content versions, gated promotion, rollback, A/B splits, serving through outages |
|
|
@@ -162,11 +162,12 @@ from the doc comments. The guides live in the repository, so these links go to G
|
|
|
162
162
|
| [Realtime voice](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/realtime.md) | Browser and server realtime sessions with barge-in, tools, and exports |
|
|
163
163
|
| [Telephony](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/telephony.md) | Calls, webhooks, phone numbers, and phone agents on realtime sessions |
|
|
164
164
|
| [Testing](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/testing.md) | Recording and replaying provider traffic, and conformance suites |
|
|
165
|
-
| [Adapter kit](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/adapter-kit.md) | Building a provider, store, or retriever outside this repository,
|
|
165
|
+
| [Adapter kit](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/adapter-kit.md) | Building a provider, store, or retriever outside this repository, verifying it against the same contracts, and its compatibility record on the [compatibility page](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/COMPATIBILITY.md) |
|
|
166
166
|
| [Studio](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/studio.md) | A shared UI for traces, threads, approvals, experiments, prompts, deployments, costs, and health, as a separate package |
|
|
167
167
|
| [Agent server](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/server.md) | Self-hosted HTTP server for assistants: threads, durable runs, resumable streams, cron, a worker queue, and metrics |
|
|
168
168
|
| [Deployments](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/deployments.md) | Revisions and canaries with automatic rollback, autoscaling on Kubernetes and Helm, and per-tenant limits |
|
|
169
169
|
| [Tenancy](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/tenancy.md) | One tenant model: a tenant's view of every store, tenant graph runs, and the isolation suite |
|
|
170
|
+
| [Policy](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/policy.md) | Guardrails, routing, budgets, residency, and credentials as one versioned file, validated as the client starts, checked by `nexus policy check` in CI, and recorded on every operation |
|
|
170
171
|
| [Regions and credentials](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/regions.md) | Agent servers across regions behind a gateway, residency rules that keep each tenant's requests, traces, and assets in its regions, and each tenant's provider keys from a secret manager |
|
|
171
172
|
| [Workflows](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/workflows.md) | Ready-made chains and domain workflows |
|
|
172
173
|
| [Command line](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/cli.md) | The `nexus` command |
|
|
@@ -312,14 +313,22 @@ Shipped so far:
|
|
|
312
313
|
- 2.13 regions and residency, and credentials per tenant: agent servers across regions behind a
|
|
313
314
|
gateway that fails over only within a tenant's regions, residency rules that keep each tenant's
|
|
314
315
|
provider calls, traces, and assets in its regions, and each tenant's provider keys from a secret
|
|
315
|
-
manager, rotated without a restart and kept out of every error
|
|
316
|
+
manager, rotated without a restart and kept out of every error;
|
|
317
|
+
- 2.14 policy you can review, and evaluation without side effects: guardrails, routing, budgets,
|
|
318
|
+
residency, and credentials as one versioned file that `nexus policy check` compares with the version
|
|
319
|
+
before it in CI and every operation records, tools emulated by a model so an evaluation sends
|
|
320
|
+
nothing, and each tenant's key in every family;
|
|
321
|
+
- 2.15 a compatibility record for community adapters: `nexus adapters verify` seals the contract an
|
|
322
|
+
adapter passed, against which release, with its benchmark; `nexus adapters recheck` turns a listed
|
|
323
|
+
adapter red before a release that would break it; and one
|
|
324
|
+
[page](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/COMPATIBILITY.md) lists them.
|
|
316
325
|
|
|
317
326
|
Upgrading from 1.x: `npx nexus migrate src --write` moves your imports, and
|
|
318
327
|
[MIGRATING.md](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/MIGRATING.md) covers the rest.
|
|
319
|
-
Next, 2.
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
328
|
+
Next, 2.16 serves A2A over its HTTP+JSON and gRPC bindings beside JSON-RPC, one task store behind
|
|
329
|
+
all three, and lets a push webhook receive each piece of streamed text. Pinecone, images, the Gemini
|
|
330
|
+
embedding batch tier, media understanding, video, Gemini Live, SIP, and both phone providers
|
|
331
|
+
graduate once the live workflow passes against each. The
|
|
323
332
|
[roadmap](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/ROADMAP.md) lists what comes after, in the order
|
|
324
333
|
applications ask for it.
|
|
325
334
|
|
|
@@ -7,6 +7,7 @@ import type { RagChunk } from '../hallucination/rag.js';
|
|
|
7
7
|
import type { EmbeddingProvider, VectorStore } from '../hallucination/retrieval.js';
|
|
8
8
|
import type { Retriever } from '../rag/retrievers.js';
|
|
9
9
|
import type { Store } from '../types/store.js';
|
|
10
|
+
import type { AdapterKind } from './index.js';
|
|
10
11
|
/** One check of a contract suite. */
|
|
11
12
|
export interface AdapterCheck {
|
|
12
13
|
/** What was checked, as a sentence. */
|
|
@@ -18,6 +19,30 @@ export interface AdapterCheck {
|
|
|
18
19
|
/** True when the adapter does not declare the capability the check needs. */
|
|
19
20
|
skipped?: boolean;
|
|
20
21
|
}
|
|
22
|
+
/** One version of a kind's contract: the release it arrived in, and the checks it added. */
|
|
23
|
+
export interface AdapterContractVersion {
|
|
24
|
+
/** The contract's version, counted from 1. */
|
|
25
|
+
version: number;
|
|
26
|
+
/** The release of `nexus-ai-pro` it arrived in. */
|
|
27
|
+
nexus: string;
|
|
28
|
+
/** The checks it added, by name. */
|
|
29
|
+
added: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
/** A kind's contract: its current version, and what each version added. */
|
|
32
|
+
export interface AdapterContract {
|
|
33
|
+
/** The adapter kind it is for. */
|
|
34
|
+
kind: AdapterKind;
|
|
35
|
+
/** Its current version, which every record names. */
|
|
36
|
+
version: number;
|
|
37
|
+
/** Each version, oldest first, so a record verified against an older one says what it was not checked for. */
|
|
38
|
+
history: readonly AdapterContractVersion[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Every kind's contract, versioned: a version is added when a release adds a check, so a record of
|
|
42
|
+
* an adapter verified against an older version is known to be stale, and the checks it has not run are
|
|
43
|
+
* named.
|
|
44
|
+
*/
|
|
45
|
+
export declare const ADAPTER_CONTRACTS: Readonly<Record<AdapterKind, AdapterContract>>;
|
|
21
46
|
/** The passages every retrieval contract runs on, and that benchmarks reuse. */
|
|
22
47
|
export declare const ADAPTER_FIXTURE_PASSAGES: readonly RagChunk[];
|
|
23
48
|
/** What a vector store declares it supports, for its contract. */
|
|
@@ -40,7 +65,8 @@ export interface VectorStoreContractOptions {
|
|
|
40
65
|
}
|
|
41
66
|
/**
|
|
42
67
|
* The `VectorStore` contract: ranking, `topK`, sources and metadata round-tripped, filters,
|
|
43
|
-
* `minScore`, vector search, replacement by id, deletes,
|
|
68
|
+
* `minScore`, vector search, replacement by id, deletes, an id added again after its delete, and
|
|
69
|
+
* empty writes. The store should be empty
|
|
44
70
|
* when it starts.
|
|
45
71
|
*/
|
|
46
72
|
export declare function runVectorStoreContract(store: VectorStore, options: VectorStoreContractOptions): Promise<AdapterCheck[]>;
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
export const ADAPTER_CONTRACTS = {
|
|
2
|
+
provider: { kind: 'provider', version: 1, history: [{ version: 1, nexus: '2.4.0', added: [] }] },
|
|
3
|
+
embeddings: { kind: 'embeddings', version: 1, history: [{ version: 1, nexus: '2.4.0', added: [] }] },
|
|
4
|
+
'vector-store': {
|
|
5
|
+
kind: 'vector-store',
|
|
6
|
+
version: 2,
|
|
7
|
+
history: [
|
|
8
|
+
{ version: 1, nexus: '2.4.0', added: [] },
|
|
9
|
+
{ version: 2, nexus: '2.15.0', added: ['adds a passage again under an id it deleted'] },
|
|
10
|
+
],
|
|
11
|
+
},
|
|
12
|
+
retriever: { kind: 'retriever', version: 1, history: [{ version: 1, nexus: '2.4.0', added: [] }] },
|
|
13
|
+
store: { kind: 'store', version: 1, history: [{ version: 1, nexus: '2.4.0', added: [] }] },
|
|
14
|
+
};
|
|
1
15
|
export const ADAPTER_FIXTURE_PASSAGES = [
|
|
2
16
|
{
|
|
3
17
|
id: 'refunds#0',
|
|
@@ -112,6 +126,13 @@ export async function runVectorStoreContract(store, options) {
|
|
|
112
126
|
const results = await store.search('how long do refunds take', { topK: 10 });
|
|
113
127
|
return !results.some((result) => result.id === 'refunds#0') || 'the deleted passage is still found';
|
|
114
128
|
});
|
|
129
|
+
await suite.check('adds a passage again under an id it deleted', async () => {
|
|
130
|
+
await store.add([fixturePassages()[0]]);
|
|
131
|
+
await settle();
|
|
132
|
+
const results = await store.search('how long do refunds take', { topK: 10 });
|
|
133
|
+
const copies = results.filter((result) => result.id === 'refunds#0').length;
|
|
134
|
+
return copies === 1 || (copies === 0 ? 'the passage stays deleted' : `found ${copies} copies`);
|
|
135
|
+
});
|
|
115
136
|
await suite.check('accepts empty writes', async () => {
|
|
116
137
|
await store.add([]);
|
|
117
138
|
await store.delete([]);
|
|
@@ -17,8 +17,10 @@ import type { EmbeddingsProvider } from '../types/embeddings.js';
|
|
|
17
17
|
import type { Store } from '../types/store.js';
|
|
18
18
|
import { type AdapterCheck, type RetrieverCapabilities, type RetrieverContractOptions, type StoreCapabilities, type VectorStoreCapabilities } from './contracts.js';
|
|
19
19
|
import { type AdapterErrorClass } from './errors.js';
|
|
20
|
-
|
|
20
|
+
import { type CompatibilityRecord, type CompatibilityRecordOptions } from './record.js';
|
|
21
|
+
export { ADAPTER_CONTRACTS, ADAPTER_FIXTURE_PASSAGES, type AdapterCheck, type AdapterContract, type AdapterContractVersion, type RetrieverCapabilities, type RetrieverContractOptions, runRetrieverContract, runStoreContract, runVectorStoreContract, type StoreCapabilities, type VectorStoreCapabilities, type VectorStoreContractOptions, } from './contracts.js';
|
|
21
22
|
export { AdapterError, type AdapterErrorClass, type AdapterErrorCode, classifyAdapterError } from './errors.js';
|
|
23
|
+
export { type CheckChange, COMPATIBILITY_RECORD_FORMAT, type CompatibilityComparison, type CompatibilityPageOptions, type CompatibilityRecord, type CompatibilityRecordAdapter, CompatibilityRecordError, type CompatibilityRecordOptions, type CompatibilityState, type CompatibilityStatus, compareRecords, compatibilityPage, compatibilityRecord, readCompatibilityRecord, recordDigest, recordStatus, } from './record.js';
|
|
22
24
|
export { parseVersion, satisfiesRange } from './semver.js';
|
|
23
25
|
/** The kinds of adapter the kit builds. */
|
|
24
26
|
export type AdapterKind = 'provider' | 'embeddings' | 'vector-store' | 'retriever' | 'store';
|
|
@@ -89,6 +91,14 @@ export interface AdapterReport {
|
|
|
89
91
|
checks: AdapterCheck[];
|
|
90
92
|
/** Latency per operation over the contract's calls. */
|
|
91
93
|
benchmark: Record<string, AdapterBenchmarkEntry>;
|
|
94
|
+
/** The releases the adapter declares support for. */
|
|
95
|
+
nexusRange: string;
|
|
96
|
+
/** What it declares it can do. */
|
|
97
|
+
capabilities: unknown;
|
|
98
|
+
/** The p95 budgets it declares. */
|
|
99
|
+
budgets?: Readonly<Record<string, number>>;
|
|
100
|
+
/** The version of its kind's contract it was verified against, from `ADAPTER_CONTRACTS`. */
|
|
101
|
+
contractVersion: number;
|
|
92
102
|
}
|
|
93
103
|
/** An adapter built with the kit. */
|
|
94
104
|
export interface Adapter<Config, Instance, Capabilities, VerifyOptions> extends Readonly<Omit<AdapterDefinition<Config, Instance, Capabilities>, 'create'>> {
|
|
@@ -100,6 +110,11 @@ export interface Adapter<Config, Instance, Capabilities, VerifyOptions> extends
|
|
|
100
110
|
compatible(nexusVersion?: string): boolean;
|
|
101
111
|
/** Runs the contract suite for its kind against a fresh instance, with a benchmark. */
|
|
102
112
|
verify(config: Config, options: VerifyOptions): Promise<AdapterReport>;
|
|
113
|
+
/**
|
|
114
|
+
* Verifies it and seals the report as a `CompatibilityRecord`: what a page lists, and what a release
|
|
115
|
+
* is checked against.
|
|
116
|
+
*/
|
|
117
|
+
record(config: Config, options: VerifyOptions, record?: CompatibilityRecordOptions): Promise<CompatibilityRecord>;
|
|
103
118
|
}
|
|
104
119
|
/** What a chat provider supports, which decides the conformance cases it runs. */
|
|
105
120
|
export interface ProviderAdapterCapabilities {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { runEmbeddingProviderConformance, } from '../testing/embedding-provider-conformance.js';
|
|
2
2
|
import { runProviderConformance } from '../testing/provider-conformance.js';
|
|
3
3
|
import { NEXUS_VERSION } from '../version.js';
|
|
4
|
-
import { runRetrieverContract, runStoreContract, runVectorStoreContract, } from './contracts.js';
|
|
4
|
+
import { ADAPTER_CONTRACTS, runRetrieverContract, runStoreContract, runVectorStoreContract, } from './contracts.js';
|
|
5
5
|
import { AdapterError, classifyAdapterError } from './errors.js';
|
|
6
|
+
import { compatibilityRecord } from './record.js';
|
|
6
7
|
import { satisfiesRange } from './semver.js';
|
|
7
|
-
export { ADAPTER_FIXTURE_PASSAGES, runRetrieverContract, runStoreContract, runVectorStoreContract, } from './contracts.js';
|
|
8
|
+
export { ADAPTER_CONTRACTS, ADAPTER_FIXTURE_PASSAGES, runRetrieverContract, runStoreContract, runVectorStoreContract, } from './contracts.js';
|
|
8
9
|
export { AdapterError, classifyAdapterError } from './errors.js';
|
|
10
|
+
export { COMPATIBILITY_RECORD_FORMAT, CompatibilityRecordError, compareRecords, compatibilityPage, compatibilityRecord, readCompatibilityRecord, recordDigest, recordStatus, } from './record.js';
|
|
9
11
|
export { parseVersion, satisfiesRange } from './semver.js';
|
|
10
12
|
const OPERATIONS = {
|
|
11
13
|
provider: ['complete', 'healthCheck'],
|
|
@@ -21,7 +23,7 @@ function build(kind, definition, contract) {
|
|
|
21
23
|
}
|
|
22
24
|
satisfiesRange(NEXUS_VERSION, definition.nexus);
|
|
23
25
|
const create = async (config, options = {}) => instrument(kind, definition, await definition.create(config), options);
|
|
24
|
-
|
|
26
|
+
const adapter = {
|
|
25
27
|
kind,
|
|
26
28
|
name: definition.name,
|
|
27
29
|
version: definition.version,
|
|
@@ -31,6 +33,9 @@ function build(kind, definition, contract) {
|
|
|
31
33
|
...(definition.budgets ? { budgets: definition.budgets } : {}),
|
|
32
34
|
create,
|
|
33
35
|
compatible: (nexusVersion = NEXUS_VERSION) => satisfiesRange(nexusVersion, definition.nexus),
|
|
36
|
+
async record(config, options, record) {
|
|
37
|
+
return compatibilityRecord(await adapter.verify(config, options), record);
|
|
38
|
+
},
|
|
34
39
|
async verify(config, options) {
|
|
35
40
|
const durations = new Map();
|
|
36
41
|
const instance = await create(config, {
|
|
@@ -78,9 +83,14 @@ function build(kind, definition, contract) {
|
|
|
78
83
|
passed: checks.every((check) => check.ok),
|
|
79
84
|
checks,
|
|
80
85
|
benchmark,
|
|
86
|
+
nexusRange: definition.nexus,
|
|
87
|
+
capabilities: definition.capabilities,
|
|
88
|
+
...(definition.budgets ? { budgets: definition.budgets } : {}),
|
|
89
|
+
contractVersion: ADAPTER_CONTRACTS[kind].version,
|
|
81
90
|
};
|
|
82
91
|
},
|
|
83
92
|
};
|
|
93
|
+
return adapter;
|
|
84
94
|
}
|
|
85
95
|
function instrument(kind, definition, instance, options) {
|
|
86
96
|
const operations = new Set(OPERATIONS[kind]);
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { type AdapterCheck } from './contracts.js';
|
|
2
|
+
import type { AdapterBenchmarkEntry, AdapterKind, AdapterReport } from './index.js';
|
|
3
|
+
/** The format every record declares, so a reader knows what it holds. */
|
|
4
|
+
export declare const COMPATIBILITY_RECORD_FORMAT = "nexus-compatibility/1";
|
|
5
|
+
/** The adapter a record is of, as its definition declares it. */
|
|
6
|
+
export interface CompatibilityRecordAdapter {
|
|
7
|
+
/** Its name, usually its package name. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Its version. */
|
|
10
|
+
version: string;
|
|
11
|
+
/** Its kind. */
|
|
12
|
+
kind: AdapterKind;
|
|
13
|
+
/** The releases of `nexus-ai-pro` it declares support for, as a range. */
|
|
14
|
+
nexus: string;
|
|
15
|
+
/** What it declares it can do. */
|
|
16
|
+
capabilities: unknown;
|
|
17
|
+
/** The p95 budgets it declares, in milliseconds. */
|
|
18
|
+
budgets?: Readonly<Record<string, number>>;
|
|
19
|
+
/** Where it is published, such as `@acme/nexus-milvus@0.3.0`. */
|
|
20
|
+
package?: string;
|
|
21
|
+
/** Its source repository. */
|
|
22
|
+
repository?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The module that verifies it, as `nexus adapters verify` loads one, so `nexus adapters recheck` can
|
|
25
|
+
* verify it again: a path, or a package specifier such as `@acme/nexus-milvus/verify`.
|
|
26
|
+
*/
|
|
27
|
+
verify?: string;
|
|
28
|
+
}
|
|
29
|
+
/** What an adapter's `verify()` proved, sealed. */
|
|
30
|
+
export interface CompatibilityRecord {
|
|
31
|
+
/** `nexus-compatibility/1`. */
|
|
32
|
+
format: typeof COMPATIBILITY_RECORD_FORMAT;
|
|
33
|
+
/** The adapter. */
|
|
34
|
+
adapter: CompatibilityRecordAdapter;
|
|
35
|
+
/** The contract it was verified against: its kind and version. */
|
|
36
|
+
contract: {
|
|
37
|
+
kind: AdapterKind;
|
|
38
|
+
version: number;
|
|
39
|
+
};
|
|
40
|
+
/** The release of `nexus-ai-pro` it was verified against. */
|
|
41
|
+
nexusVersion: string;
|
|
42
|
+
/** ISO-8601 time it was verified. */
|
|
43
|
+
verifiedAt: string;
|
|
44
|
+
/** The runtime it was verified on, such as `node 24.21.0 linux x64`. */
|
|
45
|
+
runtime: string;
|
|
46
|
+
/** Whether that release is inside the adapter's declared range. */
|
|
47
|
+
compatible: boolean;
|
|
48
|
+
/** Whether it is compatible and every check that ran held. */
|
|
49
|
+
passed: boolean;
|
|
50
|
+
/** Every check, in order, skipped ones marked. */
|
|
51
|
+
checks: AdapterCheck[];
|
|
52
|
+
/** Latency per operation over the contract's calls. */
|
|
53
|
+
benchmark: Record<string, AdapterBenchmarkEntry>;
|
|
54
|
+
/** The SHA-256 of everything above, so an edited record is known for one. */
|
|
55
|
+
digest: string;
|
|
56
|
+
}
|
|
57
|
+
/** What `compatibilityRecord()` adds to a report. */
|
|
58
|
+
export interface CompatibilityRecordOptions {
|
|
59
|
+
/** Where the adapter is published. */
|
|
60
|
+
package?: string;
|
|
61
|
+
/** Its source repository. */
|
|
62
|
+
repository?: string;
|
|
63
|
+
/** The module that verifies it, for `nexus adapters recheck`. */
|
|
64
|
+
verify?: string;
|
|
65
|
+
/** The runtime, when not the one this runs on. */
|
|
66
|
+
runtime?: string;
|
|
67
|
+
/** Replaces the clock, for tests. */
|
|
68
|
+
now?: () => Date;
|
|
69
|
+
}
|
|
70
|
+
/** Raised when a record cannot be read: not a record, of an unknown format, or edited after it was sealed. */
|
|
71
|
+
export declare class CompatibilityRecordError extends Error {
|
|
72
|
+
/** Every problem found. */
|
|
73
|
+
readonly issues: readonly string[];
|
|
74
|
+
constructor(message: string,
|
|
75
|
+
/** Every problem found. */
|
|
76
|
+
issues?: readonly string[]);
|
|
77
|
+
}
|
|
78
|
+
/** A record of what `verify()` reported, sealed with its digest. */
|
|
79
|
+
export declare function compatibilityRecord(report: AdapterReport, options?: CompatibilityRecordOptions): CompatibilityRecord;
|
|
80
|
+
/** The digest a record is sealed with: the SHA-256 of its content, its keys in order, without the digest. */
|
|
81
|
+
export declare function recordDigest(record: Omit<CompatibilityRecord, 'digest'> | CompatibilityRecord): string;
|
|
82
|
+
/**
|
|
83
|
+
* Reads a record, as JSON text or as an object, and checks it: its format, the fields every record
|
|
84
|
+
* has, and its digest. Throws a `CompatibilityRecordError` listing every problem.
|
|
85
|
+
*/
|
|
86
|
+
export declare function readCompatibilityRecord(input: string | unknown): CompatibilityRecord;
|
|
87
|
+
/** Where a record stands against a release: what a page shows, and what a check gates on. */
|
|
88
|
+
export type CompatibilityState = 'passing' | 'failing' | 'incompatible' | 'stale';
|
|
89
|
+
/** A record's state against a release, and why. */
|
|
90
|
+
export interface CompatibilityStatus {
|
|
91
|
+
/**
|
|
92
|
+
* `failing` when a check did not hold; `incompatible` when the release is outside the adapter's
|
|
93
|
+
* declared range; `stale` when it was verified against an older version of its contract;
|
|
94
|
+
* `passing` otherwise.
|
|
95
|
+
*/
|
|
96
|
+
state: CompatibilityState;
|
|
97
|
+
/** Why, a sentence each. */
|
|
98
|
+
reasons: string[];
|
|
99
|
+
/** The checks its contract added since the version it was verified against. */
|
|
100
|
+
unverified: string[];
|
|
101
|
+
}
|
|
102
|
+
/** Where a record stands against a release, the installed one by default. */
|
|
103
|
+
export declare function recordStatus(record: CompatibilityRecord, options?: {
|
|
104
|
+
nexusVersion?: string;
|
|
105
|
+
}): CompatibilityStatus;
|
|
106
|
+
/** One check whose outcome moved between two records of an adapter. */
|
|
107
|
+
export interface CheckChange {
|
|
108
|
+
/** The check. */
|
|
109
|
+
name: string;
|
|
110
|
+
/** Why it fails now, when it does. */
|
|
111
|
+
detail?: string;
|
|
112
|
+
}
|
|
113
|
+
/** What changed between an adapter's listed record and a record of it verified again. */
|
|
114
|
+
export interface CompatibilityComparison {
|
|
115
|
+
/** The adapter. */
|
|
116
|
+
adapter: string;
|
|
117
|
+
/** Checks that held before and fail now. */
|
|
118
|
+
broken: CheckChange[];
|
|
119
|
+
/** Checks the listed record did not have, with whether each holds. */
|
|
120
|
+
added: AdapterCheck[];
|
|
121
|
+
/** Checks that failed before and hold now. */
|
|
122
|
+
fixed: string[];
|
|
123
|
+
/** Operations whose p95 more than doubled, with both. */
|
|
124
|
+
slower: Array<{
|
|
125
|
+
operation: string;
|
|
126
|
+
beforeMs: number;
|
|
127
|
+
afterMs: number;
|
|
128
|
+
}>;
|
|
129
|
+
/** True when the listed record passed and the new one does not: this release turns it red. */
|
|
130
|
+
regressed: boolean;
|
|
131
|
+
}
|
|
132
|
+
/** Compares an adapter's listed record with one verified again, such as against a release candidate. */
|
|
133
|
+
export declare function compareRecords(listed: CompatibilityRecord, current: CompatibilityRecord): CompatibilityComparison;
|
|
134
|
+
/** Options for `compatibilityPage()`. */
|
|
135
|
+
export interface CompatibilityPageOptions {
|
|
136
|
+
/** The page's title. Defaults to `Adapter compatibility`. */
|
|
137
|
+
title?: string;
|
|
138
|
+
/** A paragraph under the title. */
|
|
139
|
+
intro?: string;
|
|
140
|
+
/** The release each record's state is judged against. Defaults to the installed one. */
|
|
141
|
+
nexusVersion?: string;
|
|
142
|
+
/** `markdown`, the default, or `html`. */
|
|
143
|
+
format?: 'markdown' | 'html';
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* One page listing every record: each adapter, its kind and version, the release and contract it was
|
|
147
|
+
* verified against, its state there, its checks, and its p95 per operation, by kind and name. The
|
|
148
|
+
* same records make the same page, so it can be checked for drift.
|
|
149
|
+
*/
|
|
150
|
+
export declare function compatibilityPage(records: readonly CompatibilityRecord[], options?: CompatibilityPageOptions): string;
|