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.
Files changed (126) hide show
  1. package/API_STABILITY.md +51 -0
  2. package/CHANGELOG.md +69 -1
  3. package/README.md +16 -7
  4. package/dist/adapter-kit/contracts.d.ts +27 -1
  5. package/dist/adapter-kit/contracts.js +21 -0
  6. package/dist/adapter-kit/index.d.ts +16 -1
  7. package/dist/adapter-kit/index.js +13 -3
  8. package/dist/adapter-kit/record.d.ts +150 -0
  9. package/dist/adapter-kit/record.js +252 -0
  10. package/dist/batch/anthropic.js +3 -1
  11. package/dist/batch/manager.d.ts +5 -0
  12. package/dist/batch/manager.js +25 -9
  13. package/dist/batch/openai-client.js +3 -1
  14. package/dist/cli/adapters.d.ts +10 -0
  15. package/dist/cli/adapters.js +229 -0
  16. package/dist/cli/args.js +2 -0
  17. package/dist/cli/policy.d.ts +10 -0
  18. package/dist/cli/policy.js +116 -0
  19. package/dist/cli.js +26 -7
  20. package/dist/core/lifecycle.d.ts +23 -3
  21. package/dist/core/lifecycle.js +76 -13
  22. package/dist/core/nexus.d.ts +14 -14
  23. package/dist/core/nexus.js +26 -26
  24. package/dist/embeddings/batch-google.js +7 -1
  25. package/dist/embeddings/batch.d.ts +7 -0
  26. package/dist/embeddings/batch.js +32 -9
  27. package/dist/embeddings/engine.js +1 -1
  28. package/dist/evaluate/emulate.d.ts +143 -0
  29. package/dist/evaluate/emulate.js +214 -0
  30. package/dist/images/operation.js +1 -1
  31. package/dist/lifecycle/continue.d.ts +12 -0
  32. package/dist/lifecycle/continue.js +14 -0
  33. package/dist/media/index.d.ts +14 -1
  34. package/dist/media/index.js +16 -6
  35. package/dist/media/mistral.js +3 -1
  36. package/dist/policy/index.d.ts +184 -0
  37. package/dist/policy/index.js +490 -0
  38. package/dist/realtime/gemini-live.transport.js +3 -0
  39. package/dist/realtime/openai-server.d.ts +21 -4
  40. package/dist/realtime/openai-server.js +40 -19
  41. package/dist/realtime/openai-websocket.transport.d.ts +1 -0
  42. package/dist/realtime/openai-websocket.transport.js +12 -7
  43. package/dist/realtime/session.js +8 -2
  44. package/dist/realtime/types.d.ts +8 -1
  45. package/dist/telephony/manager.js +21 -15
  46. package/dist/telephony/providers/telnyx.d.ts +14 -13
  47. package/dist/telephony/providers/telnyx.js +36 -20
  48. package/dist/telephony/providers/twilio.d.ts +18 -13
  49. package/dist/telephony/providers/twilio.js +48 -24
  50. package/dist/types/batch.d.ts +5 -0
  51. package/dist/types/config.d.ts +3 -1
  52. package/dist/types/lifecycle.d.ts +40 -0
  53. package/dist/types/residency.d.ts +19 -7
  54. package/dist/types/telephony.d.ts +26 -0
  55. package/dist/types/voice.d.ts +4 -0
  56. package/dist/version.d.ts +1 -1
  57. package/dist/version.js +1 -1
  58. package/dist/video/google.js +11 -2
  59. package/dist/video/index.d.ts +10 -0
  60. package/dist/video/index.js +39 -14
  61. package/dist/video/runway.js +4 -1
  62. package/dist/voice/manager.js +14 -2
  63. package/dist/voice/providers/openai.d.ts +3 -2
  64. package/dist/voice/providers/openai.js +9 -10
  65. package/dist-cjs/adapter-kit/contracts.d.ts +27 -1
  66. package/dist-cjs/adapter-kit/contracts.js +22 -1
  67. package/dist-cjs/adapter-kit/index.d.ts +16 -1
  68. package/dist-cjs/adapter-kit/index.js +21 -2
  69. package/dist-cjs/adapter-kit/record.d.ts +150 -0
  70. package/dist-cjs/adapter-kit/record.js +262 -0
  71. package/dist-cjs/batch/anthropic.js +3 -1
  72. package/dist-cjs/batch/manager.d.ts +5 -0
  73. package/dist-cjs/batch/manager.js +25 -9
  74. package/dist-cjs/batch/openai-client.js +3 -1
  75. package/dist-cjs/cli/adapters.d.ts +10 -0
  76. package/dist-cjs/cli/adapters.js +268 -0
  77. package/dist-cjs/cli/args.js +2 -0
  78. package/dist-cjs/cli/policy.d.ts +10 -0
  79. package/dist-cjs/cli/policy.js +122 -0
  80. package/dist-cjs/core/lifecycle.d.ts +23 -3
  81. package/dist-cjs/core/lifecycle.js +77 -13
  82. package/dist-cjs/core/nexus.d.ts +14 -14
  83. package/dist-cjs/core/nexus.js +34 -34
  84. package/dist-cjs/embeddings/batch-google.js +7 -1
  85. package/dist-cjs/embeddings/batch.d.ts +7 -0
  86. package/dist-cjs/embeddings/batch.js +32 -9
  87. package/dist-cjs/embeddings/engine.js +1 -1
  88. package/dist-cjs/evaluate/emulate.d.ts +143 -0
  89. package/dist-cjs/evaluate/emulate.js +221 -0
  90. package/dist-cjs/images/operation.js +1 -1
  91. package/dist-cjs/lifecycle/continue.d.ts +12 -0
  92. package/dist-cjs/lifecycle/continue.js +17 -0
  93. package/dist-cjs/media/index.d.ts +14 -1
  94. package/dist-cjs/media/index.js +16 -6
  95. package/dist-cjs/media/mistral.js +3 -1
  96. package/dist-cjs/policy/index.d.ts +184 -0
  97. package/dist-cjs/policy/index.js +500 -0
  98. package/dist-cjs/realtime/gemini-live.transport.js +3 -0
  99. package/dist-cjs/realtime/openai-server.d.ts +21 -4
  100. package/dist-cjs/realtime/openai-server.js +40 -19
  101. package/dist-cjs/realtime/openai-websocket.transport.d.ts +1 -0
  102. package/dist-cjs/realtime/openai-websocket.transport.js +12 -7
  103. package/dist-cjs/realtime/session.js +8 -2
  104. package/dist-cjs/realtime/types.d.ts +8 -1
  105. package/dist-cjs/telephony/manager.js +21 -15
  106. package/dist-cjs/telephony/providers/telnyx.d.ts +14 -13
  107. package/dist-cjs/telephony/providers/telnyx.js +36 -20
  108. package/dist-cjs/telephony/providers/twilio.d.ts +18 -13
  109. package/dist-cjs/telephony/providers/twilio.js +48 -24
  110. package/dist-cjs/types/batch.d.ts +5 -0
  111. package/dist-cjs/types/config.d.ts +3 -1
  112. package/dist-cjs/types/lifecycle.d.ts +40 -0
  113. package/dist-cjs/types/residency.d.ts +19 -7
  114. package/dist-cjs/types/telephony.d.ts +26 -0
  115. package/dist-cjs/types/voice.d.ts +4 -0
  116. package/dist-cjs/version.d.ts +1 -1
  117. package/dist-cjs/version.js +1 -1
  118. package/dist-cjs/video/google.js +11 -2
  119. package/dist-cjs/video/index.d.ts +10 -0
  120. package/dist-cjs/video/index.js +39 -14
  121. package/dist-cjs/video/runway.js +4 -1
  122. package/dist-cjs/voice/manager.js +14 -2
  123. package/dist-cjs/voice/providers/openai.d.ts +3 -2
  124. package/dist-cjs/voice/providers/openai.js +9 -10
  125. package/llms.txt +4 -3
  126. 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.13.0...HEAD
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, and verifying it against the same contracts |
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.14 makes policy a reviewed file, checked by the command line before it ships, brings
320
- per-tenant keys to every family, and lets an evaluation run an agent over emulated tools with nothing
321
- sent. Pinecone, images, the Gemini embedding batch tier, media understanding, video, Gemini Live, SIP,
322
- and both phone providers graduate once the live workflow passes against each. The
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, and empty writes. The store should be empty
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
- export { ADAPTER_FIXTURE_PASSAGES, type AdapterCheck, type RetrieverCapabilities, type RetrieverContractOptions, runRetrieverContract, runStoreContract, runVectorStoreContract, type StoreCapabilities, type VectorStoreCapabilities, type VectorStoreContractOptions, } from './contracts.js';
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
- return {
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;