nexus-ai-pro 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -6
- package/README.md +84 -0
- package/dist/embeddings/manager.js +1 -1
- package/dist/embeddings/models.js +1 -1
- package/dist/optimizer/cost-budget.d.ts +20 -0
- package/dist/optimizer/cost-budget.js +30 -0
- package/dist/optimizer/cost.d.ts +5 -7
- package/dist/optimizer/cost.js +6 -18
- package/dist-cjs/embeddings/manager.js +2 -2
- package/dist-cjs/embeddings/models.js +4 -4
- package/dist-cjs/optimizer/cost-budget.d.ts +20 -0
- package/dist-cjs/optimizer/cost-budget.js +36 -0
- package/dist-cjs/optimizer/cost.d.ts +5 -7
- package/dist-cjs/optimizer/cost.js +13 -24
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,19 +6,46 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.9.0] - 2026-09-15
|
|
10
|
+
|
|
11
|
+
Install weight, made measurable and enforced. Every export subpath now has a size budget that
|
|
12
|
+
CI holds it to, the README publishes what each import costs, and enforcing a cost budget no
|
|
13
|
+
longer loads the model catalogue. No public API changed.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **A per-subpath size budget, enforced in CI.** `npm run size:check` measures the transitive import
|
|
18
|
+
graph of every one of the 70 export subpaths and fails when an entry point grows past its recorded
|
|
19
|
+
budget. The package already budgeted the whole tarball, which is exactly why per-entry growth went
|
|
20
|
+
unnoticed across three releases while the total budget was raised three times: a shared module
|
|
21
|
+
pulled into an otherwise small entry point does not move the tarball at all, it only moves what a
|
|
22
|
+
consumer pays to import one piece. `npm run size:update` rewrites the budgets and regenerates the
|
|
23
|
+
README table.
|
|
24
|
+
- **A published size table.** The README now carries what each import actually costs, generated from
|
|
25
|
+
the build rather than written by hand, and the check fails if it goes stale. The claim is now
|
|
26
|
+
verifiable before installing.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **Enforcing a cost budget no longer loads the model catalogue.** `assertWithinCostBudget`,
|
|
31
|
+
`CostBudgetError`, `formatCost`, and `DEFAULT_CURRENCY` moved to `optimizer/cost-budget.ts`, which
|
|
32
|
+
has no registry dependency; `optimizer/cost.ts` re-exports all four, so no import changes and the
|
|
33
|
+
error classes stay identical rather than becoming copies. Comparing two numbers had been dragging
|
|
34
|
+
30 KB of chat-model data along with it.
|
|
35
|
+
- **`nexus-ai-pro/embeddings` is 29% smaller**, 129 KB down to 91 KB, and no longer reaches
|
|
36
|
+
`types/providers.js` at all. A test pins that, not just the budget.
|
|
37
|
+
|
|
9
38
|
## [1.8.0] - 2026-09-14
|
|
10
39
|
|
|
11
40
|
Graphs. Nodes, edges, cycles, fan-out and subgraphs over typed state, with every superstep
|
|
12
41
|
checkpointed so a run is resumable, inspectable and interruptible by construction rather than
|
|
13
|
-
after opting in
|
|
14
|
-
costs 5% of the root import.
|
|
42
|
+
after opting in, on a subpath that costs 5% of the root import.
|
|
15
43
|
|
|
16
44
|
### Added
|
|
17
45
|
|
|
18
46
|
- **Typed state graphs.** `nexus-ai-pro/graph` adds nodes, edges, conditional edges, cycles, fan-out,
|
|
19
|
-
and subgraphs over typed state channels
|
|
20
|
-
|
|
21
|
-
interrupts, and complex branching.
|
|
47
|
+
and subgraphs over typed state channels: explicit nodes and edges, persistent graph state,
|
|
48
|
+
checkpoint and resume, human-in-the-loop interrupts, and complex branching.
|
|
22
49
|
- **Durable by construction.** Every superstep is checkpointed, so a run is resumable without opting
|
|
23
50
|
into a checkpointer first. `MemoryGraphCheckpointer` covers a single process;
|
|
24
51
|
`OperationStoreCheckpointer` persists through the `OperationStore` that already backs durable
|
|
@@ -430,7 +457,8 @@ shared policy vocabulary is in place for a future release that revisits this.
|
|
|
430
457
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
431
458
|
- CLI and audit findings no longer disclose detected secret values.
|
|
432
459
|
|
|
433
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.
|
|
460
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.9.0...HEAD
|
|
461
|
+
[1.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.8.0...v1.9.0
|
|
434
462
|
[1.8.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.7.0...v1.8.0
|
|
435
463
|
[1.7.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.6.0...v1.7.0
|
|
436
464
|
[1.6.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.5.0...v1.6.0
|
package/README.md
CHANGED
|
@@ -1624,6 +1624,90 @@ import { createTelephonyRealtimeBridge } from 'nexus-ai-pro/telephony/realtime-b
|
|
|
1624
1624
|
|
|
1625
1625
|
Provider SDKs are optional peer dependencies. The package ships ESM and CommonJS builds, supports Node.js 22+, and is marked with `sideEffects: false`. Only the entry points listed in the package export map are public; deep imports into `dist`, `dist-cjs`, or `src` are unsupported.
|
|
1626
1626
|
|
|
1627
|
+
### What each import actually costs
|
|
1628
|
+
|
|
1629
|
+
Importing one piece loads one piece. The figures below are the transitive import graph of each entry
|
|
1630
|
+
point, generated from the build by `npm run size:check`, which fails CI when an entry point grows
|
|
1631
|
+
past its budget — so the numbers stay true rather than aspirational.
|
|
1632
|
+
|
|
1633
|
+
<!-- size-table:start -->
|
|
1634
|
+
| Import | Size | Share of root |
|
|
1635
|
+
| --- | --- | --- |
|
|
1636
|
+
| `nexus-ai-pro` | 606 KB | 100% |
|
|
1637
|
+
| `nexus-ai-pro/config` | 465 KB | 77% |
|
|
1638
|
+
| `nexus-ai-pro/core` | 459 KB | 76% |
|
|
1639
|
+
| `nexus-ai-pro/realtime` | 157 KB | 26% |
|
|
1640
|
+
| `nexus-ai-pro/batch` | 118 KB | 19% |
|
|
1641
|
+
| `nexus-ai-pro/realtime/session` | 94 KB | 16% |
|
|
1642
|
+
| `nexus-ai-pro/embeddings` | 91 KB | 15% |
|
|
1643
|
+
| `nexus-ai-pro/providers/groq` | 79 KB | 13% |
|
|
1644
|
+
| `nexus-ai-pro/providers/mistral` | 79 KB | 13% |
|
|
1645
|
+
| `nexus-ai-pro/providers/azure-openai` | 78 KB | 13% |
|
|
1646
|
+
| `nexus-ai-pro/providers/openrouter` | 78 KB | 13% |
|
|
1647
|
+
| `nexus-ai-pro/providers/deepseek` | 77 KB | 13% |
|
|
1648
|
+
| `nexus-ai-pro/providers/llamacpp` | 77 KB | 13% |
|
|
1649
|
+
| `nexus-ai-pro/providers/lmstudio` | 77 KB | 13% |
|
|
1650
|
+
| `nexus-ai-pro/providers/openai` | 77 KB | 13% |
|
|
1651
|
+
| `nexus-ai-pro/providers/anthropic` | 70 KB | 12% |
|
|
1652
|
+
| `nexus-ai-pro/providers/google` | 66 KB | 11% |
|
|
1653
|
+
| `nexus-ai-pro/images` | 63 KB | 10% |
|
|
1654
|
+
| `nexus-ai-pro/providers/ollama` | 58 KB | 10% |
|
|
1655
|
+
| `nexus-ai-pro/batch/openai` | 52 KB | 9% |
|
|
1656
|
+
| `nexus-ai-pro/batch/anthropic` | 52 KB | 9% |
|
|
1657
|
+
| `nexus-ai-pro/operations` | 49 KB | 8% |
|
|
1658
|
+
| `nexus-ai-pro/batch/mock` | 47 KB | 8% |
|
|
1659
|
+
| `nexus-ai-pro/providers/cohere` | 46 KB | 8% |
|
|
1660
|
+
| `nexus-ai-pro/realtime/openai-webrtc` | 46 KB | 8% |
|
|
1661
|
+
| `nexus-ai-pro/security` | 40 KB | 7% |
|
|
1662
|
+
| `nexus-ai-pro/models` | 35 KB | 6% |
|
|
1663
|
+
| `nexus-ai-pro/graph` | 29 KB | 5% |
|
|
1664
|
+
| `nexus-ai-pro/realtime/openai-websocket` | 29 KB | 5% |
|
|
1665
|
+
| `nexus-ai-pro/evals` | 23 KB | 4% |
|
|
1666
|
+
| `nexus-ai-pro/images/stores` | 22 KB | 4% |
|
|
1667
|
+
| `nexus-ai-pro/telephony/twilio` | 21 KB | 3% |
|
|
1668
|
+
| `nexus-ai-pro/telephony` | 20 KB | 3% |
|
|
1669
|
+
| `nexus-ai-pro/realtime/mock` | 19 KB | 3% |
|
|
1670
|
+
| `nexus-ai-pro/voice` | 18 KB | 3% |
|
|
1671
|
+
| `nexus-ai-pro/images/openai` | 18 KB | 3% |
|
|
1672
|
+
| `nexus-ai-pro/embeddings/adapters` | 17 KB | 3% |
|
|
1673
|
+
| `nexus-ai-pro/realtime/conversation` | 16 KB | 3% |
|
|
1674
|
+
| `nexus-ai-pro/images/assets` | 14 KB | 2% |
|
|
1675
|
+
| `nexus-ai-pro/context` | 13 KB | 2% |
|
|
1676
|
+
| `nexus-ai-pro/operations/adapters` | 13 KB | 2% |
|
|
1677
|
+
| `nexus-ai-pro/realtime/tools` | 13 KB | 2% |
|
|
1678
|
+
| `nexus-ai-pro/workflows` | 13 KB | 2% |
|
|
1679
|
+
| `nexus-ai-pro/images/mock` | 12 KB | 2% |
|
|
1680
|
+
| `nexus-ai-pro/optimizer` | 11 KB | 2% |
|
|
1681
|
+
| `nexus-ai-pro/voice/session` | 11 KB | 2% |
|
|
1682
|
+
| `nexus-ai-pro/providers` | 10 KB | 2% |
|
|
1683
|
+
| `nexus-ai-pro/providers/base` | 10 KB | 2% |
|
|
1684
|
+
| `nexus-ai-pro/embeddings/models` | 10 KB | 2% |
|
|
1685
|
+
| `nexus-ai-pro/voice/openai` | 9 KB | 1% |
|
|
1686
|
+
| `nexus-ai-pro/ops/circuit-breaker` | 8 KB | 1% |
|
|
1687
|
+
| `nexus-ai-pro/realtime/openai-server` | 8 KB | 1% |
|
|
1688
|
+
| `nexus-ai-pro/capabilities` | 8 KB | 1% |
|
|
1689
|
+
| `nexus-ai-pro/telephony/realtime-bridge` | 7 KB | 1% |
|
|
1690
|
+
| `nexus-ai-pro/providers/errors` | 5 KB | 0.8% |
|
|
1691
|
+
| `nexus-ai-pro/embeddings/mock` | 5 KB | 0.8% |
|
|
1692
|
+
| `nexus-ai-pro/cache/semantic-cache` | 5 KB | 0.8% |
|
|
1693
|
+
| `nexus-ai-pro/evals/judge` | 5 KB | 0.8% |
|
|
1694
|
+
| `nexus-ai-pro/operations/webhooks` | 4 KB | 0.7% |
|
|
1695
|
+
| `nexus-ai-pro/ops/rate-limit-adapters` | 3 KB | 0.5% |
|
|
1696
|
+
| `nexus-ai-pro/cache/memory-cache` | 3 KB | 0.5% |
|
|
1697
|
+
| `nexus-ai-pro/cache` | 2 KB | 0.3% |
|
|
1698
|
+
| `nexus-ai-pro/cache/adapters` | 2 KB | 0.3% |
|
|
1699
|
+
| `nexus-ai-pro/rag` | 2 KB | 0.3% |
|
|
1700
|
+
| `nexus-ai-pro/jobs` | 2 KB | 0.3% |
|
|
1701
|
+
| `nexus-ai-pro/jobs/durable-adapters` | 2 KB | 0.3% |
|
|
1702
|
+
| `nexus-ai-pro/jobs/queue` | 2 KB | 0.3% |
|
|
1703
|
+
| `nexus-ai-pro/streaming` | 1 KB | 0.2% |
|
|
1704
|
+
| `nexus-ai-pro/providers/type-guards` | 1 KB | 0.2% |
|
|
1705
|
+
| `nexus-ai-pro/jobs/batch` | 1 KB | 0.2% |
|
|
1706
|
+
<!-- size-table:end -->
|
|
1707
|
+
|
|
1708
|
+
A capability that only works by importing the whole runtime is treated as a design problem, not an
|
|
1709
|
+
acceptable cost.
|
|
1710
|
+
|
|
1627
1711
|
## Examples
|
|
1628
1712
|
|
|
1629
1713
|
```bash
|
|
@@ -3,7 +3,7 @@ import { AuditLogger } from '../ops/audit-logger.js';
|
|
|
3
3
|
import { MetricsCollector } from '../ops/metrics.js';
|
|
4
4
|
import { RateLimiter } from '../ops/rate-limiter.js';
|
|
5
5
|
import { NexusProviderError, createTimeoutProviderError, isAbortError } from '../providers/errors.js';
|
|
6
|
-
import { assertWithinCostBudget } from '../optimizer/cost.js';
|
|
6
|
+
import { assertWithinCostBudget } from '../optimizer/cost-budget.js';
|
|
7
7
|
import { Tokenizer } from '../utils/tokenizer.js';
|
|
8
8
|
import { generateRequestId } from '../utils/ids.js';
|
|
9
9
|
import { EmbeddingCapabilityError, EmbeddingError, EmbeddingProviderError, EmbeddingProviderNotFoundError, EmbeddingProviderResponseError, EmbeddingValidationError, } from './errors.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CostEstimate } from '../types/planning.js';
|
|
2
|
+
/**
|
|
3
|
+
* Currency and cost-budget enforcement, with no dependency on the model registry.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `optimizer/cost.ts` because enforcing a budget only compares two numbers, while
|
|
6
|
+
* looking a price up needs the 101-model catalogue. Keeping them in one module meant every family
|
|
7
|
+
* that merely enforces a budget — embeddings among them — dragged 30 KB of model data into its
|
|
8
|
+
* import graph to do arithmetic. `optimizer/cost.ts` re-exports everything here, so no public
|
|
9
|
+
* import changes.
|
|
10
|
+
*
|
|
11
|
+
* Distinct from `optimizer/budget.ts`, which enforces *token* budgets on a request before it is
|
|
12
|
+
* sent. This module deals in money after a usage figure exists.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_CURRENCY = "USD";
|
|
15
|
+
export declare class CostBudgetError extends Error {
|
|
16
|
+
constructor(message: string);
|
|
17
|
+
}
|
|
18
|
+
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
19
|
+
export declare function formatCost(amount: number): string;
|
|
20
|
+
export declare function assertWithinCostBudget(estimate: CostEstimate, maxEstimatedCost?: number): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Currency and cost-budget enforcement, with no dependency on the model registry.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `optimizer/cost.ts` because enforcing a budget only compares two numbers, while
|
|
5
|
+
* looking a price up needs the 101-model catalogue. Keeping them in one module meant every family
|
|
6
|
+
* that merely enforces a budget — embeddings among them — dragged 30 KB of model data into its
|
|
7
|
+
* import graph to do arithmetic. `optimizer/cost.ts` re-exports everything here, so no public
|
|
8
|
+
* import changes.
|
|
9
|
+
*
|
|
10
|
+
* Distinct from `optimizer/budget.ts`, which enforces *token* budgets on a request before it is
|
|
11
|
+
* sent. This module deals in money after a usage figure exists.
|
|
12
|
+
*/
|
|
13
|
+
export const DEFAULT_CURRENCY = 'USD';
|
|
14
|
+
export class CostBudgetError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'CostBudgetError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
21
|
+
export function formatCost(amount) {
|
|
22
|
+
return `$${amount.toFixed(4)}`;
|
|
23
|
+
}
|
|
24
|
+
export function assertWithinCostBudget(estimate, maxEstimatedCost) {
|
|
25
|
+
if (maxEstimatedCost === undefined)
|
|
26
|
+
return;
|
|
27
|
+
if (estimate.totalCost > maxEstimatedCost) {
|
|
28
|
+
throw new CostBudgetError(`Estimated cost ${estimate.formatted} exceeds maxEstimatedCost $${maxEstimatedCost.toFixed(4)}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
package/dist/optimizer/cost.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { NexusAIConfig } from '../types/config.js';
|
|
2
2
|
import type { CostEstimate } from '../types/planning.js';
|
|
3
3
|
import type { CacheTtl } from '../types/providers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Budget enforcement lives in `optimizer/budget.ts`, which carries no registry dependency, and is
|
|
6
|
+
* re-exported here so every existing import of this module keeps resolving.
|
|
7
|
+
*/
|
|
8
|
+
export { CostBudgetError, DEFAULT_CURRENCY, assertWithinCostBudget, formatCost } from './cost-budget.js';
|
|
4
9
|
export interface CostEstimateInput {
|
|
5
10
|
model: string;
|
|
6
11
|
inputTokens: number;
|
|
@@ -13,11 +18,4 @@ export interface CostEstimateInput {
|
|
|
13
18
|
cacheTtl?: CacheTtl;
|
|
14
19
|
config?: Pick<NexusAIConfig, 'models'>;
|
|
15
20
|
}
|
|
16
|
-
export declare class CostBudgetError extends Error {
|
|
17
|
-
constructor(message: string);
|
|
18
|
-
}
|
|
19
|
-
export declare const DEFAULT_CURRENCY = "USD";
|
|
20
21
|
export declare function estimateCost(input: CostEstimateInput): CostEstimate;
|
|
21
|
-
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
22
|
-
export declare function formatCost(amount: number): string;
|
|
23
|
-
export declare function assertWithinCostBudget(estimate: CostEstimate, maxEstimatedCost?: number): void;
|
package/dist/optimizer/cost.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { DEFAULT_CACHE_PRICING } from '../types/providers.js';
|
|
2
2
|
import { resolveModel } from '../models/registry.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
export const DEFAULT_CURRENCY = 'USD';
|
|
3
|
+
import { DEFAULT_CURRENCY, formatCost } from './cost-budget.js';
|
|
4
|
+
/**
|
|
5
|
+
* Budget enforcement lives in `optimizer/budget.ts`, which carries no registry dependency, and is
|
|
6
|
+
* re-exported here so every existing import of this module keeps resolving.
|
|
7
|
+
*/
|
|
8
|
+
export { CostBudgetError, DEFAULT_CURRENCY, assertWithinCostBudget, formatCost } from './cost-budget.js';
|
|
10
9
|
/**
|
|
11
10
|
* Resolves the per-1k prices for cached reads and cache writes.
|
|
12
11
|
*
|
|
@@ -70,14 +69,3 @@ export function estimateCost(input) {
|
|
|
70
69
|
formatted: formatCost(totalCost),
|
|
71
70
|
};
|
|
72
71
|
}
|
|
73
|
-
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
74
|
-
export function formatCost(amount) {
|
|
75
|
-
return `$${amount.toFixed(4)}`;
|
|
76
|
-
}
|
|
77
|
-
export function assertWithinCostBudget(estimate, maxEstimatedCost) {
|
|
78
|
-
if (maxEstimatedCost === undefined)
|
|
79
|
-
return;
|
|
80
|
-
if (estimate.totalCost > maxEstimatedCost) {
|
|
81
|
-
throw new CostBudgetError(`Estimated cost ${estimate.formatted} exceeds maxEstimatedCost $${maxEstimatedCost.toFixed(4)}`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -6,7 +6,7 @@ const audit_logger_js_1 = require("../ops/audit-logger.js");
|
|
|
6
6
|
const metrics_js_1 = require("../ops/metrics.js");
|
|
7
7
|
const rate_limiter_js_1 = require("../ops/rate-limiter.js");
|
|
8
8
|
const errors_js_1 = require("../providers/errors.js");
|
|
9
|
-
const
|
|
9
|
+
const cost_budget_js_1 = require("../optimizer/cost-budget.js");
|
|
10
10
|
const tokenizer_js_1 = require("../utils/tokenizer.js");
|
|
11
11
|
const ids_js_1 = require("../utils/ids.js");
|
|
12
12
|
const errors_js_2 = require("./errors.js");
|
|
@@ -438,7 +438,7 @@ class EmbeddingManager {
|
|
|
438
438
|
}
|
|
439
439
|
return;
|
|
440
440
|
}
|
|
441
|
-
(0,
|
|
441
|
+
(0, cost_budget_js_1.assertWithinCostBudget)(estimate, budget.maxEstimatedCost);
|
|
442
442
|
}
|
|
443
443
|
// ── Cache ────────────────────────────────────────────────────────
|
|
444
444
|
cacheContext(route, request) {
|
|
@@ -11,7 +11,7 @@ exports.estimateEmbeddingCost = estimateEmbeddingCost;
|
|
|
11
11
|
exports.priceEmbeddingUsage = priceEmbeddingUsage;
|
|
12
12
|
exports.embeddingDimensions = embeddingDimensions;
|
|
13
13
|
exports.resolveMaxBatchSize = resolveMaxBatchSize;
|
|
14
|
-
const
|
|
14
|
+
const cost_budget_js_1 = require("../optimizer/cost-budget.js");
|
|
15
15
|
/**
|
|
16
16
|
* Default provenance for bundled embedding entries.
|
|
17
17
|
*
|
|
@@ -228,15 +228,15 @@ function estimateEmbeddingCost(input) {
|
|
|
228
228
|
inputCost,
|
|
229
229
|
outputCost: 0,
|
|
230
230
|
totalCost: inputCost,
|
|
231
|
-
currency:
|
|
232
|
-
formatted: (0,
|
|
231
|
+
currency: cost_budget_js_1.DEFAULT_CURRENCY,
|
|
232
|
+
formatted: (0, cost_budget_js_1.formatCost)(inputCost),
|
|
233
233
|
};
|
|
234
234
|
}
|
|
235
235
|
function priceEmbeddingUsage(model, usage, config) {
|
|
236
236
|
const estimate = estimateEmbeddingCost({ model, inputTokens: usage.inputTokens, config });
|
|
237
237
|
return {
|
|
238
238
|
amount: estimate.totalCost,
|
|
239
|
-
currency: estimate.currency ||
|
|
239
|
+
currency: estimate.currency || cost_budget_js_1.DEFAULT_CURRENCY,
|
|
240
240
|
basis: 'estimated',
|
|
241
241
|
input: estimate.inputCost,
|
|
242
242
|
output: 0,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CostEstimate } from '../types/planning.js';
|
|
2
|
+
/**
|
|
3
|
+
* Currency and cost-budget enforcement, with no dependency on the model registry.
|
|
4
|
+
*
|
|
5
|
+
* Split out of `optimizer/cost.ts` because enforcing a budget only compares two numbers, while
|
|
6
|
+
* looking a price up needs the 101-model catalogue. Keeping them in one module meant every family
|
|
7
|
+
* that merely enforces a budget — embeddings among them — dragged 30 KB of model data into its
|
|
8
|
+
* import graph to do arithmetic. `optimizer/cost.ts` re-exports everything here, so no public
|
|
9
|
+
* import changes.
|
|
10
|
+
*
|
|
11
|
+
* Distinct from `optimizer/budget.ts`, which enforces *token* budgets on a request before it is
|
|
12
|
+
* sent. This module deals in money after a usage figure exists.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DEFAULT_CURRENCY = "USD";
|
|
15
|
+
export declare class CostBudgetError extends Error {
|
|
16
|
+
constructor(message: string);
|
|
17
|
+
}
|
|
18
|
+
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
19
|
+
export declare function formatCost(amount: number): string;
|
|
20
|
+
export declare function assertWithinCostBudget(estimate: CostEstimate, maxEstimatedCost?: number): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CostBudgetError = exports.DEFAULT_CURRENCY = void 0;
|
|
4
|
+
exports.formatCost = formatCost;
|
|
5
|
+
exports.assertWithinCostBudget = assertWithinCostBudget;
|
|
6
|
+
/**
|
|
7
|
+
* Currency and cost-budget enforcement, with no dependency on the model registry.
|
|
8
|
+
*
|
|
9
|
+
* Split out of `optimizer/cost.ts` because enforcing a budget only compares two numbers, while
|
|
10
|
+
* looking a price up needs the 101-model catalogue. Keeping them in one module meant every family
|
|
11
|
+
* that merely enforces a budget — embeddings among them — dragged 30 KB of model data into its
|
|
12
|
+
* import graph to do arithmetic. `optimizer/cost.ts` re-exports everything here, so no public
|
|
13
|
+
* import changes.
|
|
14
|
+
*
|
|
15
|
+
* Distinct from `optimizer/budget.ts`, which enforces *token* budgets on a request before it is
|
|
16
|
+
* sent. This module deals in money after a usage figure exists.
|
|
17
|
+
*/
|
|
18
|
+
exports.DEFAULT_CURRENCY = 'USD';
|
|
19
|
+
class CostBudgetError extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'CostBudgetError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
exports.CostBudgetError = CostBudgetError;
|
|
26
|
+
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
27
|
+
function formatCost(amount) {
|
|
28
|
+
return `$${amount.toFixed(4)}`;
|
|
29
|
+
}
|
|
30
|
+
function assertWithinCostBudget(estimate, maxEstimatedCost) {
|
|
31
|
+
if (maxEstimatedCost === undefined)
|
|
32
|
+
return;
|
|
33
|
+
if (estimate.totalCost > maxEstimatedCost) {
|
|
34
|
+
throw new CostBudgetError(`Estimated cost ${estimate.formatted} exceeds maxEstimatedCost $${maxEstimatedCost.toFixed(4)}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { NexusAIConfig } from '../types/config.js';
|
|
2
2
|
import type { CostEstimate } from '../types/planning.js';
|
|
3
3
|
import type { CacheTtl } from '../types/providers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Budget enforcement lives in `optimizer/budget.ts`, which carries no registry dependency, and is
|
|
6
|
+
* re-exported here so every existing import of this module keeps resolving.
|
|
7
|
+
*/
|
|
8
|
+
export { CostBudgetError, DEFAULT_CURRENCY, assertWithinCostBudget, formatCost } from './cost-budget.js';
|
|
4
9
|
export interface CostEstimateInput {
|
|
5
10
|
model: string;
|
|
6
11
|
inputTokens: number;
|
|
@@ -13,11 +18,4 @@ export interface CostEstimateInput {
|
|
|
13
18
|
cacheTtl?: CacheTtl;
|
|
14
19
|
config?: Pick<NexusAIConfig, 'models'>;
|
|
15
20
|
}
|
|
16
|
-
export declare class CostBudgetError extends Error {
|
|
17
|
-
constructor(message: string);
|
|
18
|
-
}
|
|
19
|
-
export declare const DEFAULT_CURRENCY = "USD";
|
|
20
21
|
export declare function estimateCost(input: CostEstimateInput): CostEstimate;
|
|
21
|
-
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
22
|
-
export declare function formatCost(amount: number): string;
|
|
23
|
-
export declare function assertWithinCostBudget(estimate: CostEstimate, maxEstimatedCost?: number): void;
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_CURRENCY = exports.CostBudgetError = void 0;
|
|
3
|
+
exports.formatCost = exports.assertWithinCostBudget = exports.DEFAULT_CURRENCY = exports.CostBudgetError = void 0;
|
|
4
4
|
exports.estimateCost = estimateCost;
|
|
5
|
-
exports.formatCost = formatCost;
|
|
6
|
-
exports.assertWithinCostBudget = assertWithinCostBudget;
|
|
7
5
|
const providers_js_1 = require("../types/providers.js");
|
|
8
6
|
const registry_js_1 = require("../models/registry.js");
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
exports
|
|
16
|
-
exports.DEFAULT_CURRENCY
|
|
7
|
+
const cost_budget_js_1 = require("./cost-budget.js");
|
|
8
|
+
/**
|
|
9
|
+
* Budget enforcement lives in `optimizer/budget.ts`, which carries no registry dependency, and is
|
|
10
|
+
* re-exported here so every existing import of this module keeps resolving.
|
|
11
|
+
*/
|
|
12
|
+
var cost_budget_js_2 = require("./cost-budget.js");
|
|
13
|
+
Object.defineProperty(exports, "CostBudgetError", { enumerable: true, get: function () { return cost_budget_js_2.CostBudgetError; } });
|
|
14
|
+
Object.defineProperty(exports, "DEFAULT_CURRENCY", { enumerable: true, get: function () { return cost_budget_js_2.DEFAULT_CURRENCY; } });
|
|
15
|
+
Object.defineProperty(exports, "assertWithinCostBudget", { enumerable: true, get: function () { return cost_budget_js_2.assertWithinCostBudget; } });
|
|
16
|
+
Object.defineProperty(exports, "formatCost", { enumerable: true, get: function () { return cost_budget_js_2.formatCost; } });
|
|
17
17
|
/**
|
|
18
18
|
* Resolves the per-1k prices for cached reads and cache writes.
|
|
19
19
|
*
|
|
@@ -73,18 +73,7 @@ function estimateCost(input) {
|
|
|
73
73
|
cachedReadCost: cachedReadTokens ? cachedReadCost : undefined,
|
|
74
74
|
cachedWriteCost: cachedWriteTokens ? cachedWriteCost : undefined,
|
|
75
75
|
totalCost,
|
|
76
|
-
currency:
|
|
77
|
-
formatted: formatCost(totalCost),
|
|
76
|
+
currency: cost_budget_js_1.DEFAULT_CURRENCY,
|
|
77
|
+
formatted: (0, cost_budget_js_1.formatCost)(totalCost),
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
-
/** Formats an amount the way `ResponseMeta.estimatedCost` has always presented it. */
|
|
81
|
-
function formatCost(amount) {
|
|
82
|
-
return `$${amount.toFixed(4)}`;
|
|
83
|
-
}
|
|
84
|
-
function assertWithinCostBudget(estimate, maxEstimatedCost) {
|
|
85
|
-
if (maxEstimatedCost === undefined)
|
|
86
|
-
return;
|
|
87
|
-
if (estimate.totalCost > maxEstimatedCost) {
|
|
88
|
-
throw new CostBudgetError(`Estimated cost ${estimate.formatted} exceeds maxEstimatedCost $${maxEstimatedCost.toFixed(4)}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-ai-pro",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "A typed multi-provider AI pipeline for Node.js with routing, streaming, tools, and guardrails",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist-cjs/index.js",
|
|
@@ -726,6 +726,8 @@
|
|
|
726
726
|
"example:optimizer": "tsx examples/optimizer.ts",
|
|
727
727
|
"example:agent": "tsx examples/agent.ts",
|
|
728
728
|
"example:realtime": "tsx examples/realtime-scheduling.ts",
|
|
729
|
+
"size:check": "node scripts/check-subpath-sizes.mjs",
|
|
730
|
+
"size:update": "node scripts/check-subpath-sizes.mjs --update",
|
|
729
731
|
"registry:generate": "node scripts/generate-model-registry.mjs",
|
|
730
732
|
"registry:check": "node scripts/generate-model-registry.mjs --check",
|
|
731
733
|
"lint": "biome lint .",
|
|
@@ -735,7 +737,7 @@
|
|
|
735
737
|
"typecheck:tests": "tsc -p tsconfig.tests.json --noEmit",
|
|
736
738
|
"typecheck:examples": "tsc -p tsconfig.examples.json --noEmit",
|
|
737
739
|
"typecheck:examples:browser": "tsc -p tsconfig.examples.browser.json --noEmit",
|
|
738
|
-
"test": "npm run build && npm run test:unit && npm run test:conformance:mock && npm run test:smoke && npm run test:api && npm run test:types",
|
|
740
|
+
"test": "npm run build && npm run test:unit && npm run test:conformance:mock && npm run size:check && npm run test:smoke && npm run test:api && npm run test:types",
|
|
739
741
|
"test:unit": "node --import tsx --test tests/unit.ts tests/*.test.ts",
|
|
740
742
|
"test:coverage": "node --import tsx --test --experimental-test-coverage --test-coverage-include=src/**/*.ts --test-coverage-lines=82 --test-coverage-branches=67 --test-coverage-functions=73 tests/unit.ts tests/*.test.ts",
|
|
741
743
|
"test:smoke": "node tests/package-smoke.mjs",
|