nexus-ai-pro 1.23.0 → 1.25.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 (158) hide show
  1. package/API_STABILITY.md +32 -2
  2. package/CHANGELOG.md +106 -1
  3. package/MIGRATING.md +169 -0
  4. package/README.md +14 -5
  5. package/dist/capabilities/negotiate.d.ts +1 -0
  6. package/dist/cli/args.js +2 -0
  7. package/dist/cli/deploy.d.ts +15 -0
  8. package/dist/cli/deploy.js +116 -0
  9. package/dist/cli/migrate.d.ts +52 -0
  10. package/dist/cli/migrate.js +224 -0
  11. package/dist/cli/root-moves.d.ts +5 -0
  12. package/dist/cli/root-moves.js +501 -0
  13. package/dist/cli.js +19 -1
  14. package/dist/graph/checkpoint-migration.d.ts +24 -0
  15. package/dist/graph/checkpoint-migration.js +12 -0
  16. package/dist/graph/index.d.ts +1 -0
  17. package/dist/graph/index.js +1 -0
  18. package/dist/hallucination/index.d.ts +10 -0
  19. package/dist/hallucination/index.js +5 -0
  20. package/dist/index.d.ts +1086 -88
  21. package/dist/index.js +31 -31
  22. package/dist/insights/index.d.ts +1 -1
  23. package/dist/insights/index.js +1 -1
  24. package/dist/insights/regressions.d.ts +52 -0
  25. package/dist/insights/regressions.js +80 -71
  26. package/dist/models/registry.d.ts +11 -1
  27. package/dist/models/registry.js +8 -0
  28. package/dist/next/route-handler.d.ts +3 -0
  29. package/dist/operations/adapters.d.ts +5 -1
  30. package/dist/operations/adapters.js +11 -0
  31. package/dist/operations/errors.d.ts +18 -0
  32. package/dist/operations/errors.js +10 -0
  33. package/dist/operations/handle.d.ts +7 -0
  34. package/dist/operations/handle.js +6 -0
  35. package/dist/operations/index.d.ts +3 -3
  36. package/dist/operations/index.js +2 -2
  37. package/dist/operations/runner.d.ts +43 -1
  38. package/dist/operations/runner.js +102 -8
  39. package/dist/operations/stats.d.ts +19 -0
  40. package/dist/operations/stats.js +32 -0
  41. package/dist/operations/store.d.ts +6 -1
  42. package/dist/operations/store.js +17 -0
  43. package/dist/ops/index.d.ts +12 -0
  44. package/dist/ops/index.js +6 -0
  45. package/dist/optimizer/index.d.ts +1 -0
  46. package/dist/optimizer/index.js +1 -0
  47. package/dist/pipeline/index.d.ts +7 -0
  48. package/dist/pipeline/index.js +1 -0
  49. package/dist/postgres/operations.d.ts +5 -1
  50. package/dist/postgres/operations.js +40 -0
  51. package/dist/router/auto-router.js +10 -1
  52. package/dist/security/index.d.ts +2 -0
  53. package/dist/security/index.js +2 -0
  54. package/dist/server/deployments.d.ts +257 -0
  55. package/dist/server/deployments.js +449 -0
  56. package/dist/server/errors.d.ts +20 -0
  57. package/dist/server/errors.js +18 -0
  58. package/dist/server/http.js +2 -1
  59. package/dist/server/index.d.ts +3 -3
  60. package/dist/server/index.js +2 -2
  61. package/dist/server/metrics.d.ts +24 -0
  62. package/dist/server/metrics.js +85 -0
  63. package/dist/server/runs.d.ts +107 -4
  64. package/dist/server/runs.js +410 -63
  65. package/dist/server/server.d.ts +37 -5
  66. package/dist/server/server.js +68 -5
  67. package/dist/server/state.d.ts +2 -0
  68. package/dist/server/state.js +1 -0
  69. package/dist/server/tenancy.d.ts +148 -0
  70. package/dist/server/tenancy.js +195 -0
  71. package/dist/sqlite/operations.d.ts +5 -1
  72. package/dist/sqlite/operations.js +38 -1
  73. package/dist/store/redis.d.ts +8 -4
  74. package/dist/testing/index.d.ts +8 -0
  75. package/dist/testing/index.js +3 -0
  76. package/dist/types/config.d.ts +10 -1
  77. package/dist/types/graph.d.ts +6 -1
  78. package/dist/types/operations.d.ts +30 -0
  79. package/dist/types/providers.d.ts +17 -2
  80. package/dist/types/server.d.ts +215 -0
  81. package/dist/utils/safe-fetch.d.ts +1 -0
  82. package/dist-cjs/capabilities/negotiate.d.ts +1 -0
  83. package/dist-cjs/cli/args.js +2 -0
  84. package/dist-cjs/cli/deploy.d.ts +15 -0
  85. package/dist-cjs/cli/deploy.js +119 -0
  86. package/dist-cjs/cli/migrate.d.ts +52 -0
  87. package/dist-cjs/cli/migrate.js +232 -0
  88. package/dist-cjs/cli/root-moves.d.ts +5 -0
  89. package/dist-cjs/cli/root-moves.js +504 -0
  90. package/dist-cjs/graph/checkpoint-migration.d.ts +24 -0
  91. package/dist-cjs/graph/checkpoint-migration.js +15 -0
  92. package/dist-cjs/graph/index.d.ts +1 -0
  93. package/dist-cjs/graph/index.js +3 -1
  94. package/dist-cjs/hallucination/index.d.ts +10 -0
  95. package/dist-cjs/hallucination/index.js +22 -0
  96. package/dist-cjs/index.d.ts +1086 -88
  97. package/dist-cjs/index.js +5 -4
  98. package/dist-cjs/insights/index.d.ts +1 -1
  99. package/dist-cjs/insights/index.js +2 -1
  100. package/dist-cjs/insights/regressions.d.ts +52 -0
  101. package/dist-cjs/insights/regressions.js +81 -71
  102. package/dist-cjs/models/registry.d.ts +11 -1
  103. package/dist-cjs/models/registry.js +15 -0
  104. package/dist-cjs/next/route-handler.d.ts +3 -0
  105. package/dist-cjs/operations/adapters.d.ts +5 -1
  106. package/dist-cjs/operations/adapters.js +11 -0
  107. package/dist-cjs/operations/errors.d.ts +18 -0
  108. package/dist-cjs/operations/errors.js +12 -1
  109. package/dist-cjs/operations/handle.d.ts +7 -0
  110. package/dist-cjs/operations/handle.js +6 -0
  111. package/dist-cjs/operations/index.d.ts +3 -3
  112. package/dist-cjs/operations/index.js +3 -1
  113. package/dist-cjs/operations/runner.d.ts +43 -1
  114. package/dist-cjs/operations/runner.js +101 -7
  115. package/dist-cjs/operations/stats.d.ts +19 -0
  116. package/dist-cjs/operations/stats.js +38 -0
  117. package/dist-cjs/operations/store.d.ts +6 -1
  118. package/dist-cjs/operations/store.js +19 -1
  119. package/dist-cjs/ops/index.d.ts +12 -0
  120. package/dist-cjs/ops/index.js +18 -0
  121. package/dist-cjs/optimizer/index.d.ts +1 -0
  122. package/dist-cjs/optimizer/index.js +3 -1
  123. package/dist-cjs/pipeline/index.d.ts +7 -0
  124. package/dist-cjs/pipeline/index.js +6 -0
  125. package/dist-cjs/postgres/operations.d.ts +5 -1
  126. package/dist-cjs/postgres/operations.js +40 -0
  127. package/dist-cjs/router/auto-router.js +9 -0
  128. package/dist-cjs/security/index.d.ts +2 -0
  129. package/dist-cjs/security/index.js +6 -1
  130. package/dist-cjs/server/deployments.d.ts +257 -0
  131. package/dist-cjs/server/deployments.js +455 -0
  132. package/dist-cjs/server/errors.d.ts +20 -0
  133. package/dist-cjs/server/errors.js +20 -1
  134. package/dist-cjs/server/http.js +2 -1
  135. package/dist-cjs/server/index.d.ts +3 -3
  136. package/dist-cjs/server/index.js +2 -1
  137. package/dist-cjs/server/metrics.d.ts +24 -0
  138. package/dist-cjs/server/metrics.js +90 -0
  139. package/dist-cjs/server/runs.d.ts +107 -4
  140. package/dist-cjs/server/runs.js +416 -69
  141. package/dist-cjs/server/server.d.ts +37 -5
  142. package/dist-cjs/server/server.js +68 -5
  143. package/dist-cjs/server/state.d.ts +2 -0
  144. package/dist-cjs/server/state.js +2 -1
  145. package/dist-cjs/server/tenancy.d.ts +148 -0
  146. package/dist-cjs/server/tenancy.js +202 -0
  147. package/dist-cjs/sqlite/operations.d.ts +5 -1
  148. package/dist-cjs/sqlite/operations.js +37 -0
  149. package/dist-cjs/store/redis.d.ts +8 -4
  150. package/dist-cjs/testing/index.d.ts +8 -0
  151. package/dist-cjs/testing/index.js +12 -0
  152. package/dist-cjs/types/config.d.ts +10 -1
  153. package/dist-cjs/types/graph.d.ts +6 -1
  154. package/dist-cjs/types/operations.d.ts +30 -0
  155. package/dist-cjs/types/providers.d.ts +17 -2
  156. package/dist-cjs/types/server.d.ts +215 -0
  157. package/dist-cjs/utils/safe-fetch.d.ts +1 -0
  158. package/package.json +149 -4
package/API_STABILITY.md CHANGED
@@ -437,8 +437,9 @@ from the root.
437
437
  `ThreadRecord`, and `RunEvent` follow the 1.x rules. A minor release may add routes and fields.
438
438
  - Event ids are per run and strictly increasing, which is what `Last-Event-ID` depends on. A client
439
439
  that reconnects with an id never receives it again.
440
- - The server is not a security boundary on its own: authentication, authorization beyond tenancy and
441
- scopes, and rate limiting are the application's, through the hooks.
440
+ - The server is not a security boundary on its own: authentication, and authorization beyond tenancy
441
+ and scopes, are the application's, through the hooks. Per-tenant limits are opt-in, through
442
+ `tenants`.
442
443
  - Recovery repeats the step a run died in for graphs and workflows served by `graphAssistant()`, and
443
444
  the whole run for any other assistant, so the repeated part should be idempotent or the run left at a
444
445
  single attempt.
@@ -456,6 +457,35 @@ with nexus-ai-pro and declares the core versions it works with as a peer depende
456
457
  - The access rules are a guarantee: loopback binding by default, a token on every request, the token
457
458
  in a header for every change, and loopback hosts only unless others are allowed.
458
459
 
460
+ ## 2.0 preparation stage (1.25.0)
461
+
462
+ The last 1.x minor deprecates what 2.0 removes. Deprecated APIs keep working, unchanged, for the rest
463
+ of the 1.x line.
464
+
465
+ - The 2.0 root import keeps the core client, its config builders, the types of its configuration,
466
+ requests, and responses, and the errors it throws. Every other root export is deprecated in favour of
467
+ the subpath that already provides it, under the same name or, where noted, another.
468
+ - Every deprecated option warns once per process through Node's `DeprecationWarning` channel, so
469
+ `--throw-deprecation` finds them in a test run. Deprecated exports and fields are marked in the type
470
+ declarations, where editors show them.
471
+ - `nexus migrate` and its map follow the root's deprecations; both are generated from the export map,
472
+ so they cannot disagree.
473
+ - A 1.x checkpoint stays readable throughout 2.x, by both checkpointers and by `migrateCheckpoint()`.
474
+
475
+ ## Deployment stage (1.24.0)
476
+
477
+ Deployments (`nexus-ai-pro/server/deployments`), tenant limits (`nexus-ai-pro/server/tenancy`), and the
478
+ server's worker queue are experimental in production readiness. Their contracts follow the 1.x rules.
479
+
480
+ - `bucket()` is stable across 1.x, so a thread keeps its place in a traffic split through an upgrade.
481
+ - The stored `DeploymentRecord` and `ReplicaReport` shapes may gain fields but not lose them, so
482
+ replicas on different minor releases share one store.
483
+ - The metric names on `/metrics` and the fields of `/scaling` follow the 1.x rules; a minor release may
484
+ add metrics and fields. Autoscaler configurations that read them keep working.
485
+ - `drain()` hands off only runs it could not finish; a hand-off never counts against the retry budget.
486
+ - The files under `deploy/` are templates in the repository, not part of the package, and may change in
487
+ any release.
488
+
459
489
  ## Team platform stage (1.23.0)
460
490
 
461
491
  The context hub (`nexus-ai-pro/context-hub`), insights (`nexus-ai-pro/insights`), and the studio's
package/CHANGELOG.md CHANGED
@@ -4,6 +4,109 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.25.0] - 2026-10-01
8
+
9
+ The bridge to 2.0. Everything 2.0 removes is deprecated now, every capability has a subpath of its
10
+ own, and the tools to migrate ship with it, so a codebase can move while it is still on 1.x.
11
+
12
+ ### Added
13
+
14
+ - **A subpath for every capability.** What could only be imported from the root has an entry point
15
+ of its own, each with no third-party dependency: `nexus-ai-pro/grounding` (grounded prompts,
16
+ verification, self-consistency, knowledge graphs), `/connectors` (web tools), `/ops` (metrics,
17
+ health, audit, OpenTelemetry export, rate limiting), `/pipeline`, `/router`, `/testing`
18
+ (conformance suites), `/next` (the route handler), `/rag/files` (scanned file ingestion), and
19
+ `/optimizer/cost` (cost estimates and budgets). Grounding alone is 15 KB, where it used to mean the
20
+ 584 KB root and its validators. `hardenPrompt()` joins `/security`, `Tokenizer` joins `/optimizer`, the
21
+ registry's data joins `/models`, and the capability types join `/capabilities`.
22
+ - **`nexus migrate`**, a codemod that moves imports to the subpaths the 2.0 root keeps them on. It
23
+ rewrites `import`, `import type`, `export … from`, and destructured `require()` in TypeScript,
24
+ JavaScript, and Markdown code blocks, keeps local names when a name moved under another, and lists
25
+ what it cannot rewrite safely. `--check` fails a CI job while anything is left.
26
+ - **`MIGRATING.md`**, shipped in the package: every change 2.0 makes, with before-and-after code.
27
+ - **Modalities with a direction**: `inputModalities` and `outputModalities` on a model's capabilities,
28
+ `modalitiesOf()` on `nexus-ai-pro/models` to read either shape, and both as routing requirements.
29
+ - **The 2.0 checkpoint schema, readable now**: `migrateCheckpoint()` and `GraphCheckpointV2` on
30
+ `nexus-ai-pro/graph`.
31
+
32
+ ### Deprecated
33
+
34
+ - 499 exports of the root import, each in favour of the subpath that already provides it. 2.0 keeps
35
+ only the core client, its config builders, its types, and the errors it throws on the root. Editors
36
+ strike a deprecated import through and name the subpath; `nexus migrate` moves them.
37
+ - `ModelCapabilities.modalities` and `routing.requiredCapabilities.modalities`, for the directional
38
+ fields. The routing requirement warns once per process.
39
+ - `GraphCheckpoint.interrupt`, for `interrupts`.
40
+
41
+ ### Changed
42
+
43
+ - The guides' examples import from subpaths, as 2.0 requires.
44
+
45
+ ### Fixed
46
+
47
+ - The agents guide pointed at `nexus-ai-pro/connectors`, which did not exist. It does now.
48
+ - `tenantLimits({ now })` drives the default usage and rate stores too. They kept the system clock, so
49
+ a budget judged on a replaced clock reset when the real day ended.
50
+
51
+ ## [1.24.0] - 2026-09-30
52
+
53
+ Deployment at scale, self-managed. Running assistants as a service without a hosted platform:
54
+ revisions and canaries, a worker pool that scales on its queue, and limits per tenant.
55
+
56
+ ### Added
57
+
58
+ - **Revisions and canaries** on `nexus-ai-pro/server/deployments`. `Deployments.assistant()` serves
59
+ several revisions of an assistant from one image; the traffic split is recorded in the server's
60
+ state store and changed with `canary()`, `split()`, `promote()`, and `rollback()`, each kept in a
61
+ history with who and why, and guarded by an expected version. New threads and stateless runs are
62
+ split by a stable hash, a thread keeps its revision while that revision takes traffic, and every
63
+ run records its revision, share, reason, and the deployment version.
64
+ - **A canary guard**: `watchCanaries()` compares each canary with the live revision over the same
65
+ window, rolls it back when its error rate, latency, or cost regressed, and moves one that holds up
66
+ through its `steps` to promotion. A latency rise must be at least `minLatencyChangeMs`, 50 ms by
67
+ default, so noise on fast runs never rolls a canary back. `compareRuns()` on `nexus-ai-pro/insights`
68
+ is the comparison, lifted out of `detectRegressions()`.
69
+ - **A worker queue** in the agent server: with `queue`, a replica runs at most `concurrency` runs and
70
+ leaves the rest queued for the next free worker; `claim: false` makes an API replica. Replicas take
71
+ over lapsed runs every `recoverEveryMs`. `drain()` answers `/health` with `503`, stops claiming, and
72
+ hands runs still going after its timeout to another worker without using a retry.
73
+ - **Scaling signals**: `GET /scaling` as JSON and `GET /metrics` in Prometheus text — queued and running
74
+ runs across the deployment, their load, the oldest wait, lapsed leases, each replica's capacity, and
75
+ run counts and latency per revision. `metrics: { public: true }` serves them to in-cluster scrapers.
76
+ - **Kubernetes and Helm**: `deploy/app` is one image run as an API, a worker, or both, configured from
77
+ the environment; `deploy/kubernetes` has the manifests with a KEDA `ScaledObject` and an HPA
78
+ alternative; `deploy/helm/agent-server` is the chart. The clean-install test runs the template against
79
+ the packed package.
80
+ - **Tenant limits** on `nexus-ai-pro/server/tenancy`: `tenantLimits()` holds each tenant to its active
81
+ runs, its runs per window, and its spending per period, answered with `429` and `Retry-After`.
82
+ `MemoryTenantUsage`, and `RedisTenantUsage` with atomic scripts so replicas share one set of limits.
83
+ Assistants record spending with `context.recordCost()`; `GET /usage` reports it.
84
+ - **Replica health**: with `deployments`, each replica heartbeats its runs, capacity, drain state, and
85
+ revisions, readable from `GET /replicas`.
86
+ - **A deployments view** in the studio: traffic splits and history, each revision's runs, error rate,
87
+ and latency since the last change, replicas, the queue, and tenant usage, with canary, promote, and
88
+ rollback for admins.
89
+ - **`nexus deploy`**: `status`, `canary`, `promote`, and `rollback` against a running server, for the
90
+ pipeline that rolls out an image.
91
+ - Operation queues: `OperationRunner.enqueue()`, `claimQueued()`, and `release()`; `listQueued()` and
92
+ `stats()` on every operation store, and `operationStats()`.
93
+ - Run records gain `revision`, `startedAt`, `finishedAt`, `durationMs`, `cost`, `worker`, and `attempt`.
94
+
95
+ ### Changed
96
+
97
+ - `GET /health` is answered without authentication, so a load balancer's or Kubernetes' probe reaches
98
+ it.
99
+ - A worker never takes over an operation whose lease another worker still holds.
100
+ - `RedisStoreLikeClient` declares `set()` with its expiry and `del()` with one key, the shapes an
101
+ `ioredis` client satisfies as it is.
102
+ - The last nine guides are rewritten for readability.
103
+ - `nexus-ai-pro-studio` requires nexus-ai-pro 1.24 or newer.
104
+
105
+ ### Fixed
106
+
107
+ - The deployment templates run. The Dockerfile started a file the build never produced, and the
108
+ example server ignored `REDIS_URL`, so its replicas shared nothing.
109
+
7
110
  ## [1.23.0] - 2026-09-30
8
111
 
9
112
  The team engineering platform. The studio becomes something a team shares, and it starts finding
@@ -1152,7 +1255,9 @@ shared policy vocabulary is in place for a future release that revisits this.
1152
1255
  - URL fetching rejects unsafe private-network targets and limits response reads.
1153
1256
  - CLI and audit findings no longer disclose detected secret values.
1154
1257
 
1155
- [Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.23.0...HEAD
1258
+ [Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.25.0...HEAD
1259
+ [1.25.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.24.0...v1.25.0
1260
+ [1.24.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.23.0...v1.24.0
1156
1261
  [1.23.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.22.0...v1.23.0
1157
1262
  [1.22.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.21.0...v1.22.0
1158
1263
  [1.21.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.20.0...v1.21.0
package/MIGRATING.md ADDED
@@ -0,0 +1,169 @@
1
+ # Migrating to 2.0
2
+
3
+ 2.0.0 removes what the 1.x line deprecated. Everything you need to get ready ships in 1.25, so you can
4
+ migrate while you are still on 1.x. Nothing below breaks before 2.0.
5
+
6
+ Start with the codemod. It rewrites what it can safely, and lists the rest:
7
+
8
+ ```bash
9
+ npx nexus migrate src # reports what would change
10
+ npx nexus migrate src --write # rewrites the files
11
+ npx nexus migrate src --check # exits 1 while anything is left, for CI
12
+ ```
13
+
14
+ Then run your tests with `node --throw-deprecation`. Every deprecated option warns once per process,
15
+ so a clean run means nothing you call is going away.
16
+
17
+ | Change | The codemod | By hand |
18
+ | --- | --- | --- |
19
+ | [The root import keeps only the core](#the-root-import-keeps-only-the-core) | Rewrites the imports | Namespace and dynamic imports of the root |
20
+ | [`estimatedCost` is removed](#a-responses-estimatedcost-is-removed) | Lists each read | Read `cost.amount` |
21
+ | [`ImageManagerConfig` is removed](#imagemanagerconfig-is-removed) | Renames it | — |
22
+ | [Options that were never read are removed](#options-that-were-never-read-are-removed) | — | Delete them; each warns today |
23
+ | [Modalities say which way they flow](#modalities-say-which-way-they-flow) | — | Set the two new fields |
24
+ | [Checkpoints gain ids and lose `interrupt`](#checkpoints-gain-ids-and-lose-interrupt) | — | Read `interrupts` |
25
+ | [Validators and Node types become optional](#validators-and-node-types-become-optional) | — | Install what you use |
26
+ | [Planned, not yet final](#planned-not-yet-final) | — | Nothing yet |
27
+
28
+ ## The root import keeps only the core
29
+
30
+ In 2.0, `nexus-ai-pro` exports the core client and nothing else. That is:
31
+
32
+ - `NexusAI`, `createNexus`, and the config builders;
33
+ - `tool()`, the streaming helpers, and the usage and pricing helpers for custom providers;
34
+ - the types of the client's configuration, requests, and responses;
35
+ - the errors the client throws: `NexusProviderError`, `NexusSecurityError`, `NexusRateLimitError`,
36
+ `NexusCapabilityError`, `TokenBudgetError`, `CostBudgetError`, and `ResponseFormatError`.
37
+
38
+ Every other export is on its own subpath already. In 1.25 each one is deprecated on the root, and your
39
+ editor strikes it through with the subpath to use.
40
+
41
+ ```ts
42
+ // Before
43
+ import { NexusAI, MemoryVectorStore, withRagContext, OperationRunner } from 'nexus-ai-pro';
44
+
45
+ // After
46
+ import { NexusAI } from 'nexus-ai-pro';
47
+ import { OperationRunner } from 'nexus-ai-pro/operations';
48
+ import { withRagContext } from 'nexus-ai-pro/grounding';
49
+ import { MemoryVectorStore } from 'nexus-ai-pro/rag';
50
+ ```
51
+
52
+ The codemod does this for `import`, `import type`, `export … from`, and destructured `require()`. A
53
+ name that moved under another name keeps its local name through an alias:
54
+
55
+ ```ts
56
+ // Before
57
+ import type { AgentModelClient } from 'nexus-ai-pro';
58
+ // After
59
+ import type { AgentLoopModelClient as AgentModelClient } from 'nexus-ai-pro/agent';
60
+ ```
61
+
62
+ It cannot split a namespace import (`import * as nexus from 'nexus-ai-pro'`) or a dynamic `import()`,
63
+ so it lists them. Import each name you use from its subpath instead. Every subpath and what it costs to
64
+ install is in the [packaging guide](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/packaging.md).
65
+
66
+ The smaller root is the point: an application that uses one family no longer loads the client, its
67
+ validators, or the model registry.
68
+
69
+ ## A response's `estimatedCost` is removed
70
+
71
+ The formatted string on a response's metadata goes. Read the numeric cost and format it yourself:
72
+
73
+ ```ts
74
+ // Before
75
+ console.log(response.meta.estimatedCost); // '$0.0012'
76
+
77
+ // After
78
+ const cost = response.meta.cost;
79
+ if (cost) console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: cost.currency }).format(cost.amount));
80
+ ```
81
+
82
+ A plan's `estimatedCost`, from `ai.plan()`, is an object and stays.
83
+
84
+ ## `ImageManagerConfig` is removed
85
+
86
+ It was an alias of `ImageConfig`. The codemod renames the import and keeps your local name.
87
+
88
+ ## Options that were never read are removed
89
+
90
+ These were accepted and ignored. Each one already warns once per process when it is set.
91
+
92
+ | Option | Deprecated in |
93
+ | --- | --- |
94
+ | `GoogleProviderConfig.projectId` | 1.16.0 |
95
+ | `OllamaProviderConfig.timeout` | 1.16.0 |
96
+ | `MetricsConfig.prometheus` | 1.16.0 |
97
+ | `DensificationConfig.preserveMarkdown` | 1.16.0 |
98
+ | `HealthConfig.latencyHalfLife` | 1.16.0 |
99
+ | `InjectionDetectionConfig.sensitivity` | 1.19.0 |
100
+ | `ToolPolicyConfig.requiresApproval` | 1.19.0 |
101
+
102
+ Delete them. Nothing changes, because nothing read them.
103
+
104
+ ## Modalities say which way they flow
105
+
106
+ A model's `modalities` list mixed inputs and outputs: `vision` meant an image in, and `image` meant an
107
+ image out. 2.0 replaces it with `inputModalities` and `outputModalities`, which 1.25 already reads.
108
+
109
+ ```ts
110
+ // A model you define, before
111
+ models: { registry: { 'my-model': { modalities: ['text', 'vision'], /* … */ } } }
112
+
113
+ // After: keep modalities until 2.0, and add the two new fields
114
+ models: {
115
+ registry: {
116
+ 'my-model': { modalities: ['text', 'vision'], inputModalities: ['text', 'image'], outputModalities: ['text'], /* … */ },
117
+ },
118
+ }
119
+ ```
120
+
121
+ Read either shape through `modalitiesOf()` from `nexus-ai-pro/models`. In routing requirements, replace
122
+ `modalities` with `inputModalities` or `outputModalities`; the old field warns once.
123
+
124
+ ## Checkpoints gain ids and lose `interrupt`
125
+
126
+ The 2.0 checkpoint schema gives every checkpoint an id and its pending tasks, and keeps questions only
127
+ in `interrupts`. Both checkpointers keep reading 1.x checkpoints throughout 2.x, so stored threads
128
+ resume.
129
+
130
+ ```ts
131
+ // Before
132
+ const question = checkpoint.interrupt;
133
+
134
+ // After
135
+ const [question] = checkpoint.interrupts ?? [];
136
+ ```
137
+
138
+ To write code against the 2.0 shape today, read checkpoints through `migrateCheckpoint()` from
139
+ `nexus-ai-pro/graph`, which returns it from either schema.
140
+
141
+ ## Validators and Node types become optional
142
+
143
+ `zod`, `ajv`, and `ajv-formats` become optional peer dependencies, and so does `@types/node`. The target is
144
+ that a graph-only application installs at most 3.5 MB, instead of about 10 MB today.
145
+
146
+ If you validate with schemas, or compile TypeScript against Node's types, add what you use:
147
+
148
+ ```bash
149
+ npm install zod ajv ajv-formats
150
+ npm install --save-dev @types/node
151
+ ```
152
+
153
+ The 2.0 release notes list exactly which calls need each one.
154
+
155
+ ## Planned, not yet final
156
+
157
+ These are designed during the 2.0 cycle. This guide gains their before-and-after code when they land.
158
+
159
+ - **One lifecycle for every operation.** Completions, streams, embeddings, voice, images, jobs, graphs,
160
+ and agents share authorization, budgets, hooks, audit, metrics, and tracing. Custom providers receive
161
+ a `ProviderCallContext` with the abort signal, deadline, request id, trace context, and idempotency key.
162
+ - **Typed pipeline contexts.** `PipelineContext` becomes generic over its request and response, and
163
+ `PipelineStepName` lists only the built-in steps.
164
+ - **Mixed outputs.** A tool result can carry asset references instead of base64 JSON.
165
+
166
+ ## Runtime
167
+
168
+ 2.0 runs on Node 22 and newer. If it ships after Node 22's end of life in April 2027, the floor moves to
169
+ Node 24.
package/README.md CHANGED
@@ -99,6 +99,8 @@ You can still pass a plain `NexusAIConfig` to `new NexusAI(...)` when you want f
99
99
  environment
100
100
  - version prompts, instructions, tools, and skills together, and promote them through evaluation gates
101
101
  - find failing and slow runs, detect regressions, and review evaluated fix proposals in a shared studio
102
+ - serve assistants as revisions, with canaries that roll back on a regression, workers that scale on
103
+ the queue under Kubernetes, and per-tenant quotas, rate limits, and budgets
102
104
  - trip routing away from a failing provider, and share one rate-limit budget across workers
103
105
  - reach the providers' half-price asynchronous batch tier behind one operation handle
104
106
  - persist generated media to disk or S3 with tenant isolation, retention, and checksums
@@ -139,8 +141,9 @@ from the doc comments. The guides live in the repository, so these links go to G
139
141
  | [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 |
140
142
  | [Telephony](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/telephony.md) | Calls, webhooks, phone numbers, and phone agents on realtime sessions |
141
143
  | [Testing](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/testing.md) | Recording and replaying provider traffic, and conformance suites |
142
- | [Studio](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/studio.md) | A local UI for traces, threads, approvals, experiments, prompts, costs, and health, as a separate package |
143
- | [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 |
144
+ | [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 |
145
+ | [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 |
146
+ | [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 |
144
147
  | [Workflows](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/workflows.md) | Ready-made chains and domain workflows |
145
148
  | [Command line](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/cli.md) | The `nexus` command |
146
149
  | [Packaging and install weight](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/docs/packaging.md) | Every entry point and what it costs |
@@ -219,9 +222,15 @@ Shipped so far:
219
222
  as images;
220
223
  - document loaders, five more vector stores, hybrid retrieval with reranking, and an MCP registry;
221
224
  - a shared studio with accounts, roles, an audit log, and comments; a context hub; insights with
222
- evaluated fix proposals; and evaluation caching.
223
-
224
- Next: self-managed deployment at scale, before 2.0.0 consolidates. The image family leaves experimental once recorded live
225
+ evaluated fix proposals; and evaluation caching;
226
+ - self-managed deployment at scale: revisions and canaries with automatic rollback, a worker queue
227
+ that autoscales on Kubernetes, and per-tenant limits;
228
+ - the bridge to 2.0: every capability on a subpath of its own, everything 2.0 removes deprecated, and
229
+ a codemod that moves your imports.
230
+
231
+ Next: 2.0.0 consolidates. It slims the root import to the core client; `npx nexus migrate src --write`
232
+ moves your imports today, and [MIGRATING.md](https://github.com/mkhitar-abrahamyan/nexus-ai/blob/main/MIGRATING.md)
233
+ covers the rest. The image family leaves experimental once recorded live
225
234
  conformance passes on all three backends.
226
235
 
227
236
  ## Before Production
@@ -45,3 +45,4 @@ export interface NegotiateOptions {
45
45
  * declaration means the registry does not know, not that the provider refuses.
46
46
  */
47
47
  export declare function negotiateCompletionRequest(request: CompletionRequest, capabilities: ModelCapabilities | undefined, options?: NegotiateOptions): NegotiationResult<CompletionRequest>;
48
+ export type { CapabilityConfig, CapabilityPolicy, CapabilityWarning, CapabilityWarningAction, } from '../types/capabilities.js';
package/dist/cli/args.js CHANGED
@@ -3,6 +3,7 @@ import { pathToFileURL } from 'node:url';
3
3
  export const BOOLEAN_FLAGS = new Set([
4
4
  'all',
5
5
  'allow-dataset-mismatch',
6
+ 'check',
6
7
  'densify',
7
8
  'fail',
8
9
  'fail-on-regression',
@@ -10,6 +11,7 @@ export const BOOLEAN_FLAGS = new Set([
10
11
  'json',
11
12
  'print',
12
13
  'reveal-values',
14
+ 'write',
13
15
  ]);
14
16
  export function parseArgs(args) {
15
17
  const positionals = [];
@@ -0,0 +1,15 @@
1
+ import { type ParsedArgs } from './args.js';
2
+ /**
3
+ * `nexus deploy` reads and changes an agent server's deployments over HTTP, for a pipeline that rolls
4
+ * out a new image and then moves traffic onto it:
5
+ *
6
+ * nexus deploy status [assistant]
7
+ * nexus deploy canary <assistant> <revision> <percent>
8
+ * nexus deploy promote <assistant> <revision>
9
+ * nexus deploy rollback <assistant> [--to <revision>]
10
+ *
11
+ * `--url` (or `NEXUS_SERVER_URL`) names the server, and `--token` (or `NEXUS_SERVER_TOKEN`) is sent
12
+ * as a bearer token. Changes take `--reason`, recorded in the deployment's history, and `--version`,
13
+ * which refuses the change if someone else moved the deployment first.
14
+ */
15
+ export declare function runDeployCommand(subcommand: string | undefined, { positionals, flags }: ParsedArgs): Promise<void>;
@@ -0,0 +1,116 @@
1
+ import { CliUsageError, numberFlag, printTable, stringFlag, writeJson } from './args.js';
2
+ export async function runDeployCommand(subcommand, { positionals, flags }) {
3
+ const server = serverOf(flags);
4
+ const reason = stringFlag(flags, 'reason');
5
+ const expectedVersion = numberFlag(flags, 'version');
6
+ const change = async (assistant, body) => {
7
+ if (!assistant)
8
+ throw new CliUsageError(`nexus deploy ${subcommand} needs an assistant.`);
9
+ const deployment = await server.request('POST', `/deployments/${encodeURIComponent(assistant)}`, {
10
+ ...body,
11
+ ...(reason ? { reason } : {}),
12
+ ...(expectedVersion === undefined ? {} : { expectedVersion }),
13
+ });
14
+ if (flags.json === true)
15
+ writeJson(deployment);
16
+ else
17
+ console.log(`${assistant}: version ${deployment.version}, live ${deployment.live}, ${splitText(deployment.traffic)}`);
18
+ };
19
+ switch (subcommand) {
20
+ case 'status': {
21
+ const [assistant] = positionals;
22
+ if (assistant) {
23
+ const deployment = await server.request('GET', `/deployments/${encodeURIComponent(assistant)}`);
24
+ if (flags.json === true)
25
+ return writeJson(deployment);
26
+ console.log(`${deployment.assistant}: version ${deployment.version}, live ${deployment.live}`);
27
+ console.log(`split: ${splitText(deployment.traffic)}`);
28
+ if (deployment.stats?.length) {
29
+ console.log('');
30
+ printTable(deployment.stats.map((item) => ({
31
+ revision: item.revision || '(none)',
32
+ runs: String(item.runs),
33
+ failed: String(item.failed),
34
+ 'error rate': `${(item.errorRate * 100).toFixed(1)}%`,
35
+ p95: item.p95Ms === undefined ? '' : `${Math.round(item.p95Ms)}ms`,
36
+ })), ['revision', 'runs', 'failed', 'error rate', 'p95']);
37
+ }
38
+ if (deployment.history.length) {
39
+ console.log('');
40
+ printTable(deployment.history.slice(0, 10).map((entry) => ({
41
+ version: String(entry.version),
42
+ at: entry.at,
43
+ action: entry.action,
44
+ split: splitText(entry.traffic),
45
+ by: entry.by ?? '',
46
+ reason: entry.reason ?? '',
47
+ })), ['version', 'at', 'action', 'split', 'by', 'reason']);
48
+ }
49
+ return;
50
+ }
51
+ const { deployments } = await server.request('GET', '/deployments');
52
+ if (flags.json === true)
53
+ return writeJson(deployments);
54
+ printTable(deployments.map((deployment) => ({
55
+ assistant: deployment.assistant,
56
+ live: deployment.live,
57
+ split: splitText(deployment.traffic),
58
+ version: String(deployment.version),
59
+ updated: deployment.version ? deployment.updatedAt : 'never',
60
+ })), ['assistant', 'live', 'split', 'version', 'updated']);
61
+ return;
62
+ }
63
+ case 'canary': {
64
+ const [assistant, revision, percent] = positionals;
65
+ const share = Number(percent);
66
+ if (!revision || !Number.isFinite(share) || share < 0 || share > 100) {
67
+ throw new CliUsageError('Usage: nexus deploy canary <assistant> <revision> <percent from 0 to 100>');
68
+ }
69
+ return change(assistant, { action: 'canary', revision, weight: share / 100 });
70
+ }
71
+ case 'promote': {
72
+ const [assistant, revision] = positionals;
73
+ if (!revision)
74
+ throw new CliUsageError('Usage: nexus deploy promote <assistant> <revision>');
75
+ return change(assistant, { action: 'promote', revision });
76
+ }
77
+ case 'rollback': {
78
+ const [assistant] = positionals;
79
+ const to = stringFlag(flags, 'to');
80
+ return change(assistant, { action: 'rollback', ...(to ? { to } : {}) });
81
+ }
82
+ default:
83
+ throw new CliUsageError(`Unknown deploy command "${subcommand ?? ''}". Use status, canary, promote, or rollback.`);
84
+ }
85
+ }
86
+ function serverOf(flags) {
87
+ const url = stringFlag(flags, 'url') ?? process.env.NEXUS_SERVER_URL;
88
+ if (!url)
89
+ throw new CliUsageError('nexus deploy needs the server: pass --url or set NEXUS_SERVER_URL.');
90
+ const token = stringFlag(flags, 'token') ?? process.env.NEXUS_SERVER_TOKEN;
91
+ const base = url.replace(/\/+$/, '');
92
+ return {
93
+ async request(method, route, body) {
94
+ const response = await fetch(`${base}${route}`, {
95
+ method,
96
+ headers: {
97
+ ...(token ? { authorization: `Bearer ${token}` } : {}),
98
+ ...(body === undefined ? {} : { 'content-type': 'application/json' }),
99
+ },
100
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
101
+ });
102
+ const text = await response.text();
103
+ const parsed = text ? JSON.parse(text) : {};
104
+ if (!response.ok) {
105
+ const error = parsed.error;
106
+ throw new Error(`${response.status} ${error?.code ?? response.statusText}: ${error?.message ?? text}`);
107
+ }
108
+ return parsed;
109
+ },
110
+ };
111
+ }
112
+ function splitText(traffic) {
113
+ return Object.entries(traffic)
114
+ .map(([revision, weight]) => `${revision} ${Math.round(weight * 1000) / 10}%`)
115
+ .join(', ');
116
+ }
@@ -0,0 +1,52 @@
1
+ import { type ParsedArgs } from './args.js';
2
+ /** One thing `migrateSource()` changed, or found and left for a person. */
3
+ export interface MigrationNote {
4
+ /** The line, starting at 1. */
5
+ line: number;
6
+ /** What was done, or what to do. */
7
+ message: string;
8
+ }
9
+ /** What `migrateSource()` produced for one file's text. */
10
+ export interface MigrationOutcome {
11
+ /** The text after migration; the input itself when nothing changed. */
12
+ text: string;
13
+ /** Imports rewritten and names renamed. */
14
+ changes: MigrationNote[];
15
+ /** What it found and could not rewrite safely, for a person to finish. */
16
+ notes: MigrationNote[];
17
+ }
18
+ /**
19
+ * Migrates one file's text to the 2.0 imports: names the root import drops are imported from their
20
+ * subpaths, names that moved under another name keep their local name through an alias, and deprecated
21
+ * aliases are replaced. What cannot be rewritten safely — a namespace import of the root, a dynamic
22
+ * import, a read of `estimatedCost` — is reported instead of guessed at.
23
+ *
24
+ * Markdown is migrated inside its TypeScript and JavaScript code blocks only. Running it twice changes
25
+ * nothing the second time.
26
+ */
27
+ export declare function migrateSource(text: string, options?: {
28
+ file?: string;
29
+ }): MigrationOutcome;
30
+ /** Options for `migrateFiles()`. */
31
+ export interface MigrateFilesOptions {
32
+ /** Writes the migrated files. Without it, nothing is written and the result says what would change. */
33
+ write?: boolean;
34
+ }
35
+ /** What `migrateFiles()` did with one file. */
36
+ export interface FileMigration extends Omit<MigrationOutcome, 'text'> {
37
+ /** The file, as given or found. */
38
+ file: string;
39
+ /** Whether its text changed. */
40
+ changed: boolean;
41
+ }
42
+ /**
43
+ * Migrates every source and Markdown file under the given paths, skipping `node_modules`, build
44
+ * output, and version control. Files are written only with `write`.
45
+ */
46
+ export declare function migrateFiles(paths: readonly string[], options?: MigrateFilesOptions): Promise<FileMigration[]>;
47
+ /**
48
+ * `nexus migrate [paths…] [--write] [--check] [--json]` moves imports of the root to the subpaths the
49
+ * 2.0 root import keeps them on. Without `--write` it only reports; `--check` exits 1 when a file still
50
+ * needs migrating, for a CI job that keeps a codebase ready.
51
+ */
52
+ export declare function runMigrateCommand({ positionals, flags }: ParsedArgs): Promise<void>;