nexus-ai-pro 1.3.0 → 1.5.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 +67 -1
- package/CHANGELOG.md +153 -1
- package/README.md +213 -6
- package/ROADMAP.md +385 -209
- package/dist/capabilities/negotiate.d.ts +38 -0
- package/dist/capabilities/negotiate.js +190 -0
- package/dist/core/nexus.d.ts +26 -0
- package/dist/core/nexus.js +81 -3
- package/dist/core/usage.d.ts +58 -0
- package/dist/core/usage.js +97 -0
- package/dist/embeddings/adapters.d.ts +66 -0
- package/dist/embeddings/adapters.js +246 -0
- package/dist/embeddings/errors.d.ts +36 -0
- package/dist/embeddings/errors.js +76 -0
- package/dist/embeddings/index.d.ts +8 -0
- package/dist/embeddings/index.js +7 -0
- package/dist/embeddings/manager.d.ts +62 -0
- package/dist/embeddings/manager.js +618 -0
- package/dist/embeddings/mock.d.ts +36 -0
- package/dist/embeddings/mock.js +64 -0
- package/dist/embeddings/models.d.ts +74 -0
- package/dist/embeddings/models.js +252 -0
- package/dist/embeddings/providers.d.ts +15 -0
- package/dist/embeddings/providers.js +10 -0
- package/dist/embeddings/register.d.ts +10 -0
- package/dist/embeddings/register.js +39 -0
- package/dist/index.d.ts +16 -8
- package/dist/index.js +10 -4
- package/dist/models/registry.d.ts +60 -1
- package/dist/models/registry.js +82 -5
- package/dist/ops/rate-limiter.d.ts +11 -2
- package/dist/optimizer/cost.d.ts +10 -0
- package/dist/optimizer/cost.js +54 -2
- package/dist/providers/anthropic.js +169 -32
- package/dist/providers/cohere.js +4 -0
- package/dist/providers/google.d.ts +9 -0
- package/dist/providers/google.js +81 -37
- package/dist/providers/ollama.d.ts +2 -0
- package/dist/providers/ollama.js +27 -29
- package/dist/providers/openai.d.ts +8 -1
- package/dist/providers/openai.js +121 -32
- package/dist/security/schema-validator.d.ts +4 -4
- package/dist/testing/embedding-provider-conformance.d.ts +33 -0
- package/dist/testing/embedding-provider-conformance.js +117 -0
- package/dist/types/capabilities.d.ts +34 -0
- package/dist/types/capabilities.js +1 -0
- package/dist/types/config.d.ts +29 -1
- package/dist/types/embeddings.d.ts +230 -0
- package/dist/types/embeddings.js +1 -0
- package/dist/types/messages.d.ts +75 -0
- package/dist/types/planning.d.ts +7 -0
- package/dist/types/providers.d.ts +75 -0
- package/dist/types/providers.js +90 -1
- package/dist/types/response.d.ts +48 -1
- package/dist-cjs/capabilities/negotiate.d.ts +38 -0
- package/dist-cjs/capabilities/negotiate.js +195 -0
- package/dist-cjs/core/nexus.d.ts +26 -0
- package/dist-cjs/core/nexus.js +81 -3
- package/dist-cjs/core/usage.d.ts +58 -0
- package/dist-cjs/core/usage.js +104 -0
- package/dist-cjs/embeddings/adapters.d.ts +66 -0
- package/dist-cjs/embeddings/adapters.js +254 -0
- package/dist-cjs/embeddings/errors.d.ts +36 -0
- package/dist-cjs/embeddings/errors.js +86 -0
- package/dist-cjs/embeddings/index.d.ts +8 -0
- package/dist-cjs/embeddings/index.js +42 -0
- package/dist-cjs/embeddings/manager.d.ts +62 -0
- package/dist-cjs/embeddings/manager.js +622 -0
- package/dist-cjs/embeddings/mock.d.ts +36 -0
- package/dist-cjs/embeddings/mock.js +68 -0
- package/dist-cjs/embeddings/models.d.ts +74 -0
- package/dist-cjs/embeddings/models.js +265 -0
- package/dist-cjs/embeddings/providers.d.ts +15 -0
- package/dist-cjs/embeddings/providers.js +11 -0
- package/dist-cjs/embeddings/register.d.ts +10 -0
- package/dist-cjs/embeddings/register.js +42 -0
- package/dist-cjs/index.d.ts +16 -8
- package/dist-cjs/index.js +48 -4
- package/dist-cjs/models/registry.d.ts +60 -1
- package/dist-cjs/models/registry.js +85 -4
- package/dist-cjs/ops/rate-limiter.d.ts +11 -2
- package/dist-cjs/optimizer/cost.d.ts +10 -0
- package/dist-cjs/optimizer/cost.js +56 -3
- package/dist-cjs/providers/anthropic.js +168 -31
- package/dist-cjs/providers/cohere.js +4 -0
- package/dist-cjs/providers/google.d.ts +9 -0
- package/dist-cjs/providers/google.js +81 -37
- package/dist-cjs/providers/ollama.d.ts +2 -0
- package/dist-cjs/providers/ollama.js +27 -29
- package/dist-cjs/providers/openai.d.ts +8 -1
- package/dist-cjs/providers/openai.js +121 -32
- package/dist-cjs/security/schema-validator.d.ts +4 -4
- package/dist-cjs/testing/embedding-provider-conformance.d.ts +33 -0
- package/dist-cjs/testing/embedding-provider-conformance.js +121 -0
- package/dist-cjs/types/capabilities.d.ts +34 -0
- package/dist-cjs/types/capabilities.js +2 -0
- package/dist-cjs/types/config.d.ts +29 -1
- package/dist-cjs/types/embeddings.d.ts +230 -0
- package/dist-cjs/types/embeddings.js +2 -0
- package/dist-cjs/types/messages.d.ts +75 -0
- package/dist-cjs/types/planning.d.ts +7 -0
- package/dist-cjs/types/providers.d.ts +75 -0
- package/dist-cjs/types/providers.js +91 -2
- package/dist-cjs/types/response.d.ts +48 -1
- package/package.json +67 -2
package/API_STABILITY.md
CHANGED
|
@@ -26,7 +26,48 @@ Source files, `dist` file paths, examples, test helpers that are not exported, a
|
|
|
26
26
|
- Security fixes may tighten validation or blocking behavior in a patch release when preserving the old behavior would leave users exposed.
|
|
27
27
|
- Provider behavior can change when an upstream API changes; Nexus will preserve its normalized request and response contracts where possible.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
## Module formats
|
|
30
|
+
|
|
31
|
+
Since 1.2.0 the package ships parallel ESM and CommonJS builds and supports Node.js 22 or newer.
|
|
32
|
+
Both are covered by this policy:
|
|
33
|
+
|
|
34
|
+
- every export subpath carries `import` and `require` conditions, each resolving to its own build and
|
|
35
|
+
its own declarations, so a CommonJS consumer never lands on ESM declarations;
|
|
36
|
+
- `typesVersions` maps each subpath to its CommonJS declarations, so subpath types resolve under
|
|
37
|
+
`moduleResolution: "node10"` without a consumer migrating its `tsconfig.json`;
|
|
38
|
+
- dropping either build, or removing a subpath from either condition, requires a major release.
|
|
39
|
+
|
|
40
|
+
Deep imports into `dist`, `dist-cjs`, or `src` are not supported. Import only from `nexus-ai-pro` or
|
|
41
|
+
one of its explicit subpaths.
|
|
42
|
+
|
|
43
|
+
## Capability negotiation stage
|
|
44
|
+
|
|
45
|
+
`negotiateCompletionRequest()`, `NexusCapabilityError`, `CapabilityPolicy`, `CapabilityWarning`, and
|
|
46
|
+
the `nexus-ai-pro/capabilities` subpath are public and follow the 1.x rules.
|
|
47
|
+
|
|
48
|
+
Which options a given model accepts is registry data, not a compatibility guarantee. A model's
|
|
49
|
+
declared capabilities, cache lifetimes, reasoning effort levels, and prices can change in a minor
|
|
50
|
+
release when a provider changes its lineup, and new normalized warning entries may be added. What is
|
|
51
|
+
guaranteed is the behavior of each policy: `strict` throws before the provider call, `warn` records a
|
|
52
|
+
warning and continues, `off` sends the request unchanged, and an option a model does not mention is
|
|
53
|
+
always passed through rather than refused.
|
|
54
|
+
|
|
55
|
+
`ResponseMeta.usage` and `ResponseMeta.cost` are public normalized shapes. Reported token counts and
|
|
56
|
+
prices originate with the provider or with bundled defaults and are not compatibility guarantees;
|
|
57
|
+
`cost.basis` distinguishes the two. `ResponseMeta.estimatedCost` is deprecated in favor of
|
|
58
|
+
`cost.amount` and will be removed in the next major release.
|
|
59
|
+
|
|
60
|
+
## Telephony API stage
|
|
61
|
+
|
|
62
|
+
The `nexus-ai-pro/telephony`, `telephony/twilio`, and `telephony/realtime-bridge` subpaths are public
|
|
63
|
+
and follow the 1.x rules. This covers `TelephonyManager`, the `TelephonyProvider` contract, the
|
|
64
|
+
normalized call, media-stream, status-callback, and phone-number types, the TwiML helpers, and the
|
|
65
|
+
realtime bridge.
|
|
66
|
+
|
|
67
|
+
Provider payloads under `raw`, TwiML markup details beyond the documented helper options, webhook
|
|
68
|
+
signature formats, upstream call-status vocabularies, and carrier behavior are controlled by the
|
|
69
|
+
provider and are not normalized guarantees. `TelephonyProvider` methods are optional by design, so a
|
|
70
|
+
provider adapter may implement any subset; adding a new optional method is a minor change.
|
|
30
71
|
|
|
31
72
|
## Realtime API stage
|
|
32
73
|
|
|
@@ -65,6 +106,31 @@ exactly-once provider execution. Those capabilities will use additive adapters a
|
|
|
65
106
|
`MemoryAssetStore` is likewise process-local and does not promise cross-process durability or shared
|
|
66
107
|
tenant state.
|
|
67
108
|
|
|
109
|
+
## Embeddings API stage
|
|
110
|
+
|
|
111
|
+
The `nexus-ai-pro/embeddings` family is public and follows the 1.x rules, including the explicit
|
|
112
|
+
`embeddings/adapters`, `embeddings/mock`, and `embeddings/models` subpaths. This covers
|
|
113
|
+
`EmbeddingManager`, `ai.embed()` and `ai.embedOne()`, the `EmbeddingsProvider` contract, the
|
|
114
|
+
normalized request, embedding, and meta shapes, the error subclasses, and `toEmbeddingFunction()`.
|
|
115
|
+
|
|
116
|
+
`EmbeddingsProvider` is a distinct contract from the pre-existing `EmbeddingProvider` function type
|
|
117
|
+
used by `MemoryVectorStore`, the semantic cache, and RAG ingestion. That function type is unchanged
|
|
118
|
+
and remains supported; `toEmbeddingFunction()` converts one into the other.
|
|
119
|
+
|
|
120
|
+
Two behaviors are guaranteed and differ deliberately from completions. Vectors are returned in input
|
|
121
|
+
order regardless of how the request was split, deduplicated, or served from cache. And an option the
|
|
122
|
+
target model or adapter declares it cannot honor is **refused**, not dropped, because a vector built
|
|
123
|
+
with different dimensions or a different input type is silently incompatible with vectors already in
|
|
124
|
+
a store. An option nothing in the registry describes is still passed through, on the same
|
|
125
|
+
absence-means-unknown rule the completion path uses.
|
|
126
|
+
|
|
127
|
+
Embedding model entries are registry data, not compatibility guarantees. Bundled dimensions, input
|
|
128
|
+
limits, batch limits, and prices can change in a minor release when a provider changes its lineup,
|
|
129
|
+
and are overridable through `embeddings.models.registry`. Which concrete model an alias such as
|
|
130
|
+
`embed-quality` resolves to can also change in a minor release: the vectors two targets produce are
|
|
131
|
+
not interchangeable, so pin a concrete model whenever a stored index must stay valid across
|
|
132
|
+
upgrades. Provider payloads under `raw` and reported token counts are controlled by the provider.
|
|
133
|
+
|
|
68
134
|
## Deprecation process
|
|
69
135
|
|
|
70
136
|
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. Removals
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,152 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.5.0] - 2026-08-31
|
|
8
|
+
|
|
9
|
+
Embeddings become a first-class operation. `ai.embed()` gets the routing, caching, batching, budget,
|
|
10
|
+
retry, audit, and metrics that until now only completions had, so embedding spend is visible next to
|
|
11
|
+
completion spend instead of leaving the platform entirely. Everything here is additive.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`ai.embed()` and `ai.embedOne()`.** A provider-neutral embeddings operation family behind
|
|
16
|
+
`EmbeddingManager`, reached through `ai.embeddings` or the new `nexus-ai-pro/embeddings` subpath.
|
|
17
|
+
The manager is built on first access, so a runtime that never embeds pays nothing for it.
|
|
18
|
+
- **Adapters for OpenAI, Google, Cohere, Mistral, and Ollama**, plus any OpenAI-compatible
|
|
19
|
+
`/embeddings` server through `OpenAIEmbeddingProvider`'s `baseUrl` and `providerName`. They are
|
|
20
|
+
registered automatically from the provider credentials already in `providers`, so a configured
|
|
21
|
+
chat provider makes `ai.embedOne('text')` work with no embedding-specific configuration. Explicit
|
|
22
|
+
registration through `registerEmbeddingProvider()` always wins, and auto-registration can be
|
|
23
|
+
turned off with `embeddings.autoRegisterProviders: false`.
|
|
24
|
+
- **Batching, deduplication, and per-input caching.** A batch larger than the model's limit is split
|
|
25
|
+
and run with bounded concurrency, and the vectors still come back in input order. Repeated texts
|
|
26
|
+
within one request are answered by a single provider call, and caching is keyed per input, so a
|
|
27
|
+
partially repeated batch only sends the texts it has not seen. `meta.batches`, `meta.cachedInputs`,
|
|
28
|
+
and `meta.deduplicatedInputs` report what actually happened.
|
|
29
|
+
- **Structured usage and numeric cost for embeddings.** `meta.usage` and `meta.cost` reuse the same
|
|
30
|
+
`TokenUsage` and `ResponseCost` shapes as completions, priced from a new embedding model registry.
|
|
31
|
+
When a provider reports no token counts — Google's `batchEmbedContents` does not — tokens are
|
|
32
|
+
estimated locally rather than reported as zero, so a call is never priced at nothing.
|
|
33
|
+
- **An embedding model registry** with dimensions, supported truncation sizes, input limits, batch
|
|
34
|
+
limits, and prices for eleven models across five providers, with aliases (`auto`, `embed-fast`,
|
|
35
|
+
`embed-quality`, `embed-multilingual`, `embed-local`) and full override through
|
|
36
|
+
`embeddings.models.registry`. It is deliberately separate from `KNOWN_MODELS`, because completion
|
|
37
|
+
routing scores models on context window, output price, and tool support, none of which an
|
|
38
|
+
embedding model has.
|
|
39
|
+
- **Capability refusal.** An unsupported `dimensions`, `inputType`, `encodingFormat`, or `truncate`
|
|
40
|
+
value throws `EmbeddingCapabilityError` before the provider call. Embeddings refuse rather than
|
|
41
|
+
drop: a vector built with different dimensions is silently incompatible with the vectors already
|
|
42
|
+
in a store, and the mismatch only surfaces later as unexplained retrieval quality loss. An option
|
|
43
|
+
the registry says nothing about is still passed through, and `providerOptions` reaches the
|
|
44
|
+
provider body untouched.
|
|
45
|
+
- **`toEmbeddingFunction()`**, which adapts the family to the plain `EmbeddingProvider` function that
|
|
46
|
+
`MemoryVectorStore`, the semantic cache, and RAG ingestion already accept. An existing vector store
|
|
47
|
+
gains routing, caching, retry, and metrics without changing its own contract.
|
|
48
|
+
- **`normalize`** for unit-length vectors, applied locally when the provider does not already return
|
|
49
|
+
them, and reapplied after a locally truncated vector loses its length.
|
|
50
|
+
- **A deterministic `MockEmbeddingProvider`** and `runEmbeddingProviderConformance()`, which checks
|
|
51
|
+
one vector per input, input order, consistent width, optional determinism, and an honored abort.
|
|
52
|
+
- New subpaths `nexus-ai-pro/embeddings`, `embeddings/adapters`, `embeddings/mock`, and
|
|
53
|
+
`embeddings/models`.
|
|
54
|
+
|
|
55
|
+
### Changed
|
|
56
|
+
|
|
57
|
+
- `RateLimiter.check()` accepts the new structural `RateLimitedRequest` instead of a
|
|
58
|
+
`CompletionRequest`, so one limiter instance and one budget cover every operation family.
|
|
59
|
+
`CompletionRequest` still satisfies it, so no call site changes.
|
|
60
|
+
- Coverage rose from 82.6% lines / 68.9% branches / 78.2% functions to 85.7% / 70.9% / 80.8%, with
|
|
61
|
+
65 new tests. `embeddings/providers.ts`, previously the weakest file in the package at 37% lines,
|
|
62
|
+
is now at 99%.
|
|
63
|
+
|
|
64
|
+
### Notes
|
|
65
|
+
|
|
66
|
+
- Bundled embedding dimensions and prices are defaults, not financial truth; override them through
|
|
67
|
+
`embeddings.models.registry` when exact numbers matter.
|
|
68
|
+
- Which concrete model an embedding alias resolves to can change in a minor release. Two targets do
|
|
69
|
+
not produce interchangeable vectors, so pin a concrete model when a stored index must stay valid
|
|
70
|
+
across upgrades.
|
|
71
|
+
|
|
72
|
+
## [1.4.0] - 2026-08-25
|
|
73
|
+
|
|
74
|
+
Request parity and cost truth: the completion request can now express what current models actually
|
|
75
|
+
do, and the response reports what the call really cost. Every addition is an optional field or a new
|
|
76
|
+
union member, so existing code is unaffected.
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
|
|
80
|
+
- **Provider prompt caching.** `CompletionRequest.cache` selects `off`, `auto`, or `explicit` mode
|
|
81
|
+
with a `5m` or `1h` lifetime, and `Message.cache` / `ToolDefinition.cache` mark the end of a
|
|
82
|
+
cacheable prefix. The Anthropic adapter translates marks into `cache_control` breakpoints,
|
|
83
|
+
respecting the four-breakpoint limit by keeping the deepest marks, and every adapter reports what
|
|
84
|
+
the provider actually reused.
|
|
85
|
+
- **Reasoning controls.** `CompletionRequest.reasoning` carries `effort`, `maxTokens`, and `summary`.
|
|
86
|
+
These map to OpenAI `reasoning_effort` and the Responses `reasoning` field, Anthropic extended
|
|
87
|
+
thinking with a token budget, and Gemini `thinkingConfig`. A new `'reasoning'` `StreamChunk`
|
|
88
|
+
variant carries reasoning summaries, kept separate from `'text'` so existing consumers that switch
|
|
89
|
+
on chunk type see no change.
|
|
90
|
+
- **Tool and sampling controls.** `toolChoice`, `parallelToolCalls`, `seed`, `topK`,
|
|
91
|
+
`frequencyPenalty`, and `presencePenalty` on `CompletionRequest`, mapped per provider.
|
|
92
|
+
- **Structured usage and numeric cost.** `ResponseMeta.usage` reports input, output, cached-read,
|
|
93
|
+
cached-write, and reasoning tokens; `ResponseMeta.cost` reports a numeric amount with a currency
|
|
94
|
+
and an `estimated` or `reported` basis. Cached reads and cache writes are priced at their own
|
|
95
|
+
rates, with a long-lived write costing more than a short-lived one. `models.cachePricing`
|
|
96
|
+
overrides the bundled multipliers.
|
|
97
|
+
- **Capability negotiation.** `negotiateCompletionRequest()` reconciles a request against the routed
|
|
98
|
+
model under a `strict`, `warn`, or `off` policy, set through `capabilities.policy` or per request
|
|
99
|
+
through `capabilityPolicy`. Refused options are reported on `ResponseMeta.capabilityWarnings` and
|
|
100
|
+
in `plan()` warnings. An option the registry does not mention is passed through: absence means
|
|
101
|
+
unknown, not unsupported, so an application-registered model is never restricted by fields it does
|
|
102
|
+
not declare, and `off` guarantees a newer provider feature is never blocked by stale metadata.
|
|
103
|
+
- **Registry provenance.** Model entries accept `verifiedAt` and `source`; `MODEL_ALIAS_METADATA`
|
|
104
|
+
reports each alias's stage and whether its target floats between releases. `describeModel()`,
|
|
105
|
+
`checkRegistryFreshness()`, and `assertRegistryFreshness()` make drift visible instead of silent.
|
|
106
|
+
- **Streamed usage on OpenAI.** `stream_options.include_usage` is requested for OpenAI and Azure, so
|
|
107
|
+
a streamed response reports real tokens and cost rather than zeros. Other OpenAI-compatible
|
|
108
|
+
servers opt in with the new `streamUsage` provider option.
|
|
109
|
+
- A `nexus-ai-pro/capabilities` subpath for the negotiation API.
|
|
110
|
+
|
|
111
|
+
### Fixed
|
|
112
|
+
|
|
113
|
+
- Claude 5 models were declared as non-reasoning. The registry decided extended-thinking support by
|
|
114
|
+
looking for a `4` in the family name, which is absent from `claude-sonnet-5.0`, `claude-haiku-5.0`,
|
|
115
|
+
and `claude-fable-5.0`. Support is now derived from the family version, so every release from 3.7
|
|
116
|
+
onward is reported correctly, together with the thinking budget each model can accept.
|
|
117
|
+
- The Anthropic adapter priced every completion at a hardcoded $0.003/$0.015 per 1k tokens instead of
|
|
118
|
+
using the model registry, so cost was wrong for every Claude model except one. All adapters now
|
|
119
|
+
share one pricing path.
|
|
120
|
+
- Streamed Anthropic and Google responses reported zero tokens and `$0.00`. Both now carry the
|
|
121
|
+
provider's own usage totals on the final chunk.
|
|
122
|
+
- Google reasoning summaries could be concatenated into visible output. Parts marked `thought` are
|
|
123
|
+
excluded from content and emitted as `'reasoning'` chunks instead.
|
|
124
|
+
- A chat stream that ended without a finish reason produced no `done` chunk, leaving consumers
|
|
125
|
+
without terminal metadata.
|
|
126
|
+
|
|
127
|
+
### Changed
|
|
128
|
+
|
|
129
|
+
- `ResponseMeta.estimatedCost` is deprecated in favor of the numeric `cost` object. It is still
|
|
130
|
+
populated and stays until the next major release. The metrics path no longer parses money out of
|
|
131
|
+
its own display string.
|
|
132
|
+
- `ResponseMeta.tokensInput` keeps its original meaning of every prompt token; the uncached share
|
|
133
|
+
billed at the standard rate is `usage.inputTokens`. Adapters whose provider folds cached tokens
|
|
134
|
+
into one prompt total subtract them so no token is priced twice.
|
|
135
|
+
- `resolveModel()` no longer merges the bundled and application registries into a new object on each
|
|
136
|
+
call. It reads both maps directly, which removes a per-request allocation from the hot path;
|
|
137
|
+
`getModelRegistry()` and `getModelAliases()` are unchanged as the merged views.
|
|
138
|
+
- Coverage gates raised from 70/60/60 to 82% lines, 67% branches, and 73% functions, with new tests
|
|
139
|
+
for the agent loop, the rules router, the evaluation metric library, and the Google, Ollama, and
|
|
140
|
+
Cohere adapters. The gates sit a couple of points below the lowest figure the supported Node
|
|
141
|
+
versions report, because Node 22 and Node 24 do not count functions identically: the same suite
|
|
142
|
+
measures 78.7% on Node 22 and 75.9% on Node 24. A gate set from one version alone fails on the
|
|
143
|
+
other.
|
|
144
|
+
|
|
145
|
+
### Notes
|
|
146
|
+
|
|
147
|
+
Image operations keep their existing strict capability behavior. An unsupported image option changes
|
|
148
|
+
the artifact that comes back, so silently dropping one is worse than refusing the request; the
|
|
149
|
+
shared policy vocabulary is in place for a future release that revisits this.
|
|
150
|
+
|
|
151
|
+
## [1.3.0] - 2026-08-17
|
|
152
|
+
|
|
7
153
|
### Added
|
|
8
154
|
|
|
9
155
|
- SMS routing on `updatePhoneNumber`. `UpdatePhoneNumberRequest` now carries `smsUrl`, `smsMethod`,
|
|
@@ -120,6 +266,12 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
120
266
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
121
267
|
- CLI and audit findings no longer disclose detected secret values.
|
|
122
268
|
|
|
123
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.
|
|
269
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.5.0...HEAD
|
|
270
|
+
[1.5.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.4.0...v1.5.0
|
|
271
|
+
[1.4.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.3.0...v1.4.0
|
|
272
|
+
[1.3.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.2.1...v1.3.0
|
|
273
|
+
[1.2.1]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.2.0...v1.2.1
|
|
274
|
+
[1.2.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.1.0...v1.2.0
|
|
275
|
+
[1.1.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.0.0...v1.1.0
|
|
124
276
|
[1.0.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v1.0.0
|
|
125
277
|
[0.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v0.9.0
|
package/README.md
CHANGED
|
@@ -83,6 +83,7 @@ You can still pass a plain `NexusAIConfig` to `new NexusAI(...)` when you want f
|
|
|
83
83
|
- estimate tokens and cost before provider calls
|
|
84
84
|
- cache exact or semantically similar prompts
|
|
85
85
|
- add tools, agents, RAG context, evals, batch jobs, and queues
|
|
86
|
+
- embed text through the same routing, caching, batching, budget, retry, and metrics as a completion
|
|
86
87
|
- build persistent realtime voice agents with interruption, live tools, and normalized conversation state
|
|
87
88
|
- keep TypeScript types around every request and response
|
|
88
89
|
|
|
@@ -239,7 +240,112 @@ console.log(plan.fitsContext);
|
|
|
239
240
|
console.log(plan.warnings);
|
|
240
241
|
```
|
|
241
242
|
|
|
242
|
-
`plan()` does not call a provider. It estimates route, token use, context fit, cost, guardrail findings, and warnings.
|
|
243
|
+
`plan()` does not call a provider. It estimates route, token use, context fit, cost, guardrail findings, and warnings, including any option the routed model cannot honor.
|
|
244
|
+
|
|
245
|
+
### Reasoning
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
const response = await ai.complete({
|
|
249
|
+
model: 'auto',
|
|
250
|
+
messages: [{ role: 'user', content: 'Find the bug in this migration plan.' }],
|
|
251
|
+
reasoning: { effort: 'high', summary: 'auto' },
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
console.log(response.meta.usage?.reasoningTokens);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
`effort` is the portable control. It maps to OpenAI `reasoning_effort` and the Responses `reasoning`
|
|
258
|
+
field, Anthropic extended thinking, and Gemini `thinkingConfig`. Use `reasoning.maxTokens` when you
|
|
259
|
+
want to set a thinking budget directly instead of by level.
|
|
260
|
+
|
|
261
|
+
Requesting a summary emits `reasoning` stream chunks, which stay separate from visible output:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
for await (const chunk of ai.stream({ model: 'auto', messages, reasoning: { summary: 'auto' } })) {
|
|
265
|
+
if (chunk.type === 'reasoning') process.stderr.write(chunk.content ?? '');
|
|
266
|
+
if (chunk.type === 'text') process.stdout.write(chunk.content ?? '');
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Prompt Caching
|
|
271
|
+
|
|
272
|
+
Providers charge far less for a prompt prefix they have already processed. `mode: 'auto'` is the
|
|
273
|
+
default and reports whatever the provider reused on its own. `mode: 'explicit'` sends caller-placed
|
|
274
|
+
breakpoints to providers that accept them, such as Anthropic:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
const response = await ai.complete({
|
|
278
|
+
model: 'anthropic/best',
|
|
279
|
+
cache: { mode: 'explicit', ttl: '1h' },
|
|
280
|
+
messages: [
|
|
281
|
+
{ role: 'system', content: longPolicyDocument, cache: true },
|
|
282
|
+
{ role: 'user', content: 'Does clause 14 apply here?' },
|
|
283
|
+
],
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
console.log(response.meta.usage?.cachedReadTokens);
|
|
287
|
+
console.log(response.meta.cost?.amount);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Mark the end of the stable prefix, not every message. A provider caps how many breakpoints it
|
|
291
|
+
accepts (Anthropic allows four); when there are more marks than slots, the deepest ones are kept,
|
|
292
|
+
because a deeper breakpoint caches strictly more of the prompt.
|
|
293
|
+
|
|
294
|
+
### Usage and Cost
|
|
295
|
+
|
|
296
|
+
Every response carries a numeric cost and a full token breakdown:
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
const { usage, cost } = response.meta;
|
|
300
|
+
|
|
301
|
+
console.log(usage?.inputTokens); // billed at the standard input rate
|
|
302
|
+
console.log(usage?.cachedReadTokens); // served from the provider cache
|
|
303
|
+
console.log(usage?.cachedWriteTokens); // written into the provider cache
|
|
304
|
+
console.log(usage?.reasoningTokens); // share of output spent on reasoning
|
|
305
|
+
console.log(cost?.amount, cost?.currency, cost?.basis);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
`meta.tokensInput` keeps its original meaning of every prompt token, cached or not.
|
|
309
|
+
`meta.estimatedCost` is deprecated in favor of `cost.amount`. Bundled prices are defaults, not
|
|
310
|
+
financial truth; override them with `models.registry`, or adjust cache rates with
|
|
311
|
+
`models.cachePricing`.
|
|
312
|
+
|
|
313
|
+
### Capability Negotiation
|
|
314
|
+
|
|
315
|
+
Requests are reconciled against the routed model before the provider is called:
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
const ai = new NexusAI({
|
|
319
|
+
providers: { openai: { apiKey: process.env.OPENAI_API_KEY! } },
|
|
320
|
+
capabilities: { policy: 'warn' }, // 'strict' | 'warn' (default) | 'off'
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const response = await ai.complete({ model: 'auto', messages, seed: 7 });
|
|
324
|
+
console.log(response.meta.capabilityWarnings);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
- `strict` throws a `NexusCapabilityError` before spending anything.
|
|
328
|
+
- `warn` drops or clamps the option and records it on `meta.capabilityWarnings`.
|
|
329
|
+
- `off` sends the request exactly as written.
|
|
330
|
+
|
|
331
|
+
An option a model does not declare is always passed through — absence means the registry does not
|
|
332
|
+
know, not that the provider refuses — so a model you register yourself is never restricted by fields
|
|
333
|
+
it omits. Set `capabilityPolicy: 'off'` on a single request to reach a provider feature that is
|
|
334
|
+
newer than the bundled registry.
|
|
335
|
+
|
|
336
|
+
Registry provenance is inspectable, and a release check can fail on stale data:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
import { describeModel, assertRegistryFreshness } from 'nexus-ai-pro';
|
|
340
|
+
|
|
341
|
+
console.log(describeModel('anthropic/best'));
|
|
342
|
+
// { model: 'claude-opus-4-8', verifiedAt: '…', alias: { stage: 'stable', floating: true }, … }
|
|
343
|
+
|
|
344
|
+
assertRegistryFreshness({ maxAgeDays: 120 });
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
A `floating` alias resolves by intent rather than to a pinned model, so its target can change between
|
|
348
|
+
releases. Pin the resolved model when a run has to be reproducible.
|
|
243
349
|
|
|
244
350
|
### Streaming
|
|
245
351
|
|
|
@@ -254,7 +360,9 @@ for await (const chunk of stream) {
|
|
|
254
360
|
}
|
|
255
361
|
```
|
|
256
362
|
|
|
257
|
-
All providers normalize streaming chunks to `text`, `tool_call`, `done`, or `error`.
|
|
363
|
+
All providers normalize streaming chunks to `text`, `reasoning`, `tool_call`, `done`, or `error`.
|
|
364
|
+
Reasoning summaries only arrive when the request asks for them, so a consumer that switches on
|
|
365
|
+
`chunk.type` keeps receiving visible output only.
|
|
258
366
|
|
|
259
367
|
When security is enabled, output streams are correctness-first: Nexus buffers and validates the
|
|
260
368
|
complete output before yielding any chunk, up to 1 MiB or 100,000 chunks. This prevents secrets,
|
|
@@ -309,6 +417,98 @@ const response = await ai.completeVerified(
|
|
|
309
417
|
);
|
|
310
418
|
```
|
|
311
419
|
|
|
420
|
+
## Embeddings
|
|
421
|
+
|
|
422
|
+
`ai.embed()` is a first-class operation, not a helper: it gets the same routing, caching, batching,
|
|
423
|
+
budget, retry, audit, and metrics as a completion, so embedding spend shows up next to completion
|
|
424
|
+
spend instead of being invisible.
|
|
425
|
+
|
|
426
|
+
The smallest call is one line, and needs no embedding-specific configuration — adapters are derived
|
|
427
|
+
from the provider credentials already in `providers`:
|
|
428
|
+
|
|
429
|
+
```ts
|
|
430
|
+
import { NexusAI } from 'nexus-ai-pro';
|
|
431
|
+
|
|
432
|
+
const ai = new NexusAI({ providers: { openai: { apiKey: process.env.OPENAI_API_KEY! } } });
|
|
433
|
+
|
|
434
|
+
const vector = await ai.embedOne('Provider-neutral embeddings.');
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
A batch returns vectors in input order regardless of how many provider calls the model's batch
|
|
438
|
+
limit required, and reports what the call cost:
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
const response = await ai.embed({
|
|
442
|
+
input: documents.map((document) => document.text),
|
|
443
|
+
model: 'embed-quality',
|
|
444
|
+
inputType: 'document',
|
|
445
|
+
normalize: true,
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
response.vectors; // number[][], in input order
|
|
449
|
+
response.meta.batches; // provider calls the split required
|
|
450
|
+
response.meta.usage.inputTokens; // reported by the provider, or estimated when it reports none
|
|
451
|
+
response.meta.cost.amount; // numeric, priced from the embedding registry
|
|
452
|
+
response.meta.cachedInputs; // inputs answered from cache
|
|
453
|
+
response.meta.deduplicatedInputs; // repeated inputs answered from one call
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Caching is per input rather than per request, so a partially repeated batch only sends the texts it
|
|
457
|
+
has not seen. Repeated texts inside one batch are collapsed into a single provider call:
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
const ai = new NexusAI({
|
|
461
|
+
providers: { openai: { apiKey: process.env.OPENAI_API_KEY! } },
|
|
462
|
+
embeddings: {
|
|
463
|
+
cache: { enabled: true, ttlSeconds: 86_400 },
|
|
464
|
+
costBudget: { enabled: true, maxEstimatedCost: 5 },
|
|
465
|
+
retry: { enabled: true, maxRetries: 2 },
|
|
466
|
+
fallback: [{ provider: 'cohere', model: 'embed-v4.0' }],
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Unlike a completion, an unsupported embedding option is **refused rather than dropped**. A vector
|
|
472
|
+
built with different dimensions or a different input type is silently incompatible with the vectors
|
|
473
|
+
already in a store, and the mismatch only surfaces later as unexplained retrieval quality loss:
|
|
474
|
+
|
|
475
|
+
```ts
|
|
476
|
+
await ai.embed({ input: 'x', model: 'embed-english-v3.0', dimensions: 512 });
|
|
477
|
+
// EmbeddingCapabilityError: model has a fixed size of 1024 dimensions
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
An option the registry says nothing about is still passed through, because an undeclared capability
|
|
481
|
+
means unknown rather than unsupported, and `providerOptions` reaches the provider body untouched for
|
|
482
|
+
anything the neutral contract does not model yet.
|
|
483
|
+
|
|
484
|
+
Existing vector stores keep their contract. `toEmbeddingFunction()` adapts the family to the plain
|
|
485
|
+
function `MemoryVectorStore`, the semantic cache, and RAG ingestion already accept:
|
|
486
|
+
|
|
487
|
+
```ts
|
|
488
|
+
import { MemoryVectorStore, toEmbeddingFunction } from 'nexus-ai-pro';
|
|
489
|
+
|
|
490
|
+
const store = new MemoryVectorStore(toEmbeddingFunction(ai, { inputType: 'document' }));
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
Bundled adapters cover OpenAI (and any OpenAI-compatible `/embeddings` server), Google, Cohere,
|
|
494
|
+
Mistral, and Ollama. A custom adapter implements `EmbeddingsProvider` and is checked against the
|
|
495
|
+
neutral contract by `runEmbeddingProviderConformance()`:
|
|
496
|
+
|
|
497
|
+
```ts
|
|
498
|
+
import { OpenAIEmbeddingProvider } from 'nexus-ai-pro/embeddings/adapters';
|
|
499
|
+
import { MockEmbeddingProvider } from 'nexus-ai-pro/embeddings/mock';
|
|
500
|
+
|
|
501
|
+
ai.registerEmbeddingProvider('gateway', new OpenAIEmbeddingProvider({
|
|
502
|
+
apiKey: process.env.GATEWAY_KEY!,
|
|
503
|
+
baseUrl: 'https://gateway.internal/v1',
|
|
504
|
+
providerName: 'gateway',
|
|
505
|
+
}));
|
|
506
|
+
ai.registerEmbeddingProvider('mock', new MockEmbeddingProvider());
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Bundled embedding dimensions and prices are defaults, not financial truth. Override them through
|
|
510
|
+
`embeddings.models.registry` when exact numbers matter.
|
|
511
|
+
|
|
312
512
|
## Image Generation and Editing (Experimental)
|
|
313
513
|
|
|
314
514
|
Image operations use a separate provider-neutral manager because generated assets have different
|
|
@@ -1022,9 +1222,14 @@ import { NexusAI } from 'nexus-ai-pro/core';
|
|
|
1022
1222
|
import { createNexusConfig } from 'nexus-ai-pro/config';
|
|
1023
1223
|
import { TokenOptimizer } from 'nexus-ai-pro/optimizer';
|
|
1024
1224
|
import { ContextWindowManager } from 'nexus-ai-pro/context';
|
|
1225
|
+
import { negotiateCompletionRequest } from 'nexus-ai-pro/capabilities';
|
|
1025
1226
|
import { guardrailPolicy } from 'nexus-ai-pro/security';
|
|
1026
1227
|
import { RedisCacheAdapter } from 'nexus-ai-pro/cache';
|
|
1027
1228
|
import { DeepSeekProvider } from 'nexus-ai-pro/providers/deepseek';
|
|
1229
|
+
import { EmbeddingManager } from 'nexus-ai-pro/embeddings';
|
|
1230
|
+
import { OpenAIEmbeddingProvider } from 'nexus-ai-pro/embeddings/adapters';
|
|
1231
|
+
import { MockEmbeddingProvider } from 'nexus-ai-pro/embeddings/mock';
|
|
1232
|
+
import { KNOWN_EMBEDDING_MODELS } from 'nexus-ai-pro/embeddings/models';
|
|
1028
1233
|
import { ImageManager } from 'nexus-ai-pro/images';
|
|
1029
1234
|
import { MemoryAssetStore } from 'nexus-ai-pro/images/assets';
|
|
1030
1235
|
import { MockImageProvider } from 'nexus-ai-pro/images/mock';
|
|
@@ -1086,10 +1291,12 @@ npm run test:conformance:real
|
|
|
1086
1291
|
|
|
1087
1292
|
## Roadmap
|
|
1088
1293
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1294
|
+
1.4.0 closed the completion-request gap: prompt caching, reasoning controls, tool and sampling
|
|
1295
|
+
controls, structured usage with numeric cost, and capability negotiation with registry provenance.
|
|
1296
|
+
|
|
1297
|
+
Next is durable execution — an operation state machine, provider batch APIs, distributed rate
|
|
1298
|
+
limiting and circuit breaking, first-class embeddings, and filesystem/S3 asset stores — followed by
|
|
1299
|
+
image portability and promotion out of experimental. See [ROADMAP.md](./ROADMAP.md).
|
|
1093
1300
|
|
|
1094
1301
|
## Production Notes
|
|
1095
1302
|
|