nexus-ai-pro 1.0.0 → 1.2.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 +24 -6
- package/CHANGELOG.md +46 -2
- package/README.md +147 -7
- package/ROADMAP.md +17 -1
- package/dist/core/config-builder.d.ts +3 -0
- package/dist/core/config-builder.js +5 -0
- package/dist/core/nexus.d.ts +32 -1
- package/dist/core/nexus.js +48 -0
- package/dist/images/assets.d.ts +115 -0
- package/dist/images/assets.js +343 -0
- package/dist/images/errors.d.ts +35 -0
- package/dist/images/errors.js +79 -0
- package/dist/images/index.d.ts +4 -0
- package/dist/images/index.js +2 -0
- package/dist/images/manager.d.ts +23 -0
- package/dist/images/manager.js +574 -0
- package/dist/images/mock.d.ts +17 -0
- package/dist/images/mock.js +237 -0
- package/dist/images/openai.d.ts +46 -0
- package/dist/images/openai.js +355 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/telephony/index.d.ts +3 -1
- package/dist/telephony/index.js +1 -0
- package/dist/telephony/manager.d.ts +6 -1
- package/dist/telephony/manager.js +59 -0
- package/dist/telephony/providers/twilio.d.ts +9 -1
- package/dist/telephony/providers/twilio.js +165 -12
- package/dist/telephony/realtime-bridge.d.ts +58 -0
- package/dist/telephony/realtime-bridge.js +180 -0
- package/dist/testing/image-provider-conformance.d.ts +33 -0
- package/dist/testing/image-provider-conformance.js +324 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/images.d.ts +245 -0
- package/dist/types/images.js +1 -0
- package/dist/types/telephony.d.ts +87 -0
- package/dist-cjs/agent/loop.js +93 -0
- package/dist-cjs/agent/tool.js +50 -0
- package/dist-cjs/cache/adapters.js +84 -0
- package/dist-cjs/cache/memory-cache.js +106 -0
- package/dist-cjs/cache/semantic-cache.js +75 -0
- package/dist-cjs/connectors/web.js +401 -0
- package/dist-cjs/context/index.js +5 -0
- package/dist-cjs/context/window.js +284 -0
- package/dist-cjs/core/config-builder.js +203 -0
- package/dist-cjs/core/create-nexus.js +184 -0
- package/dist-cjs/core/nexus.js +897 -0
- package/dist-cjs/core/response-format.js +109 -0
- package/dist-cjs/core/secure-stream.js +153 -0
- package/dist-cjs/core/streaming.js +35 -0
- package/dist-cjs/embeddings/providers.js +65 -0
- package/dist-cjs/evals/index.js +24 -0
- package/dist-cjs/evals/judge.js +158 -0
- package/dist-cjs/evals/metrics.js +171 -0
- package/dist-cjs/evals/runner.js +64 -0
- package/dist-cjs/hallucination/consistency.js +92 -0
- package/dist-cjs/hallucination/factual.js +37 -0
- package/dist-cjs/hallucination/knowledge-graph.js +74 -0
- package/dist-cjs/hallucination/rag.js +53 -0
- package/dist-cjs/hallucination/retrieval.js +78 -0
- package/dist-cjs/hallucination/verification.js +139 -0
- package/dist-cjs/images/assets.js +351 -0
- package/dist-cjs/images/errors.js +90 -0
- package/dist-cjs/images/index.js +14 -0
- package/dist-cjs/images/manager.js +578 -0
- package/dist-cjs/images/mock.js +241 -0
- package/dist-cjs/images/openai.js +360 -0
- package/dist-cjs/index.js +230 -0
- package/dist-cjs/jobs/batch.js +35 -0
- package/dist-cjs/jobs/durable-adapters.js +55 -0
- package/dist-cjs/jobs/queue.js +61 -0
- package/dist-cjs/models/registry.js +52 -0
- package/dist-cjs/next/route-handler.js +38 -0
- package/dist-cjs/ops/audit-logger.js +51 -0
- package/dist-cjs/ops/health.js +71 -0
- package/dist-cjs/ops/metrics.js +131 -0
- package/dist-cjs/ops/otel-tracing.js +54 -0
- package/dist-cjs/ops/rate-limiter.js +38 -0
- package/dist-cjs/optimizer/budget.js +93 -0
- package/dist-cjs/optimizer/cost.js +37 -0
- package/dist-cjs/optimizer/densifier.js +84 -0
- package/dist-cjs/optimizer/index.js +65 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/pipeline/pipeline.js +111 -0
- package/dist-cjs/pipeline/types.js +2 -0
- package/dist-cjs/providers/anthropic.js +253 -0
- package/dist-cjs/providers/azure-openai.js +30 -0
- package/dist-cjs/providers/base.js +172 -0
- package/dist-cjs/providers/cohere.js +123 -0
- package/dist-cjs/providers/deepseek.js +18 -0
- package/dist-cjs/providers/errors.js +141 -0
- package/dist-cjs/providers/google.js +251 -0
- package/dist-cjs/providers/groq.js +54 -0
- package/dist-cjs/providers/llamacpp.js +19 -0
- package/dist-cjs/providers/lmstudio.js +19 -0
- package/dist-cjs/providers/mistral.js +54 -0
- package/dist-cjs/providers/ollama.js +163 -0
- package/dist-cjs/providers/openai.js +474 -0
- package/dist-cjs/providers/openrouter.js +23 -0
- package/dist-cjs/providers/type-guards.js +43 -0
- package/dist-cjs/rag/file-ingestion.js +60 -0
- package/dist-cjs/rag/ingestion.js +52 -0
- package/dist-cjs/realtime/conversation.js +414 -0
- package/dist-cjs/realtime/errors.js +79 -0
- package/dist-cjs/realtime/events.js +43 -0
- package/dist-cjs/realtime/id.js +12 -0
- package/dist-cjs/realtime/index.js +41 -0
- package/dist-cjs/realtime/mock.transport.js +173 -0
- package/dist-cjs/realtime/openai-events.js +409 -0
- package/dist-cjs/realtime/openai-server.js +143 -0
- package/dist-cjs/realtime/openai-webrtc.transport.js +875 -0
- package/dist-cjs/realtime/openai-websocket.transport.js +424 -0
- package/dist-cjs/realtime/provider.js +64 -0
- package/dist-cjs/realtime/session.js +967 -0
- package/dist-cjs/realtime/tools.js +364 -0
- package/dist-cjs/realtime/transport-utils.js +259 -0
- package/dist-cjs/realtime/types.js +2 -0
- package/dist-cjs/router/auto-router.js +255 -0
- package/dist-cjs/router/failover.js +382 -0
- package/dist-cjs/router/index.js +36 -0
- package/dist-cjs/router/rules-router.js +72 -0
- package/dist-cjs/router/types.js +2 -0
- package/dist-cjs/security/index.js +223 -0
- package/dist-cjs/security/injection-calibration.js +56 -0
- package/dist-cjs/security/injection-detector.js +84 -0
- package/dist-cjs/security/input-guard.js +127 -0
- package/dist-cjs/security/output-guard.js +238 -0
- package/dist-cjs/security/pii-detector.js +70 -0
- package/dist-cjs/security/policies.js +65 -0
- package/dist-cjs/security/prompt-hardening.js +22 -0
- package/dist-cjs/security/schema-validator.js +69 -0
- package/dist-cjs/security/semantic-injection-classifier.js +79 -0
- package/dist-cjs/security/upload-scanner.js +79 -0
- package/dist-cjs/telephony/errors.js +21 -0
- package/dist-cjs/telephony/index.js +13 -0
- package/dist-cjs/telephony/manager.js +141 -0
- package/dist-cjs/telephony/providers/twilio.js +435 -0
- package/dist-cjs/telephony/realtime-bridge.js +184 -0
- package/dist-cjs/telephony/twiml.js +90 -0
- package/dist-cjs/testing/image-provider-conformance.js +328 -0
- package/dist-cjs/testing/provider-conformance.js +158 -0
- package/dist-cjs/types/agent.js +2 -0
- package/dist-cjs/types/config.js +2 -0
- package/dist-cjs/types/context-window.js +2 -0
- package/dist-cjs/types/images.js +2 -0
- package/dist-cjs/types/messages.js +2 -0
- package/dist-cjs/types/optimizer.js +2 -0
- package/dist-cjs/types/planning.js +2 -0
- package/dist-cjs/types/providers.js +604 -0
- package/dist-cjs/types/response.js +2 -0
- package/dist-cjs/types/security.js +2 -0
- package/dist-cjs/types/telephony.js +2 -0
- package/dist-cjs/types/voice.js +2 -0
- package/dist-cjs/utils/ids.js +7 -0
- package/dist-cjs/utils/logger.js +71 -0
- package/dist-cjs/utils/tokenizer.js +45 -0
- package/dist-cjs/voice/errors.js +21 -0
- package/dist-cjs/voice/index.js +10 -0
- package/dist-cjs/voice/manager.js +110 -0
- package/dist-cjs/voice/providers/openai.js +287 -0
- package/dist-cjs/voice/session.js +230 -0
- package/dist-cjs/workflow/chains.js +135 -0
- package/dist-cjs/workflow/domain.js +118 -0
- package/package.json +135 -55
package/API_STABILITY.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# API Stability Policy
|
|
2
2
|
|
|
3
|
-
This policy describes compatibility guarantees for `nexus-ai-pro
|
|
3
|
+
This policy describes compatibility guarantees for `nexus-ai-pro`. The 1.x compatibility guarantees
|
|
4
|
+
apply beginning with version 1.0.0.
|
|
4
5
|
|
|
5
6
|
## Release stages
|
|
6
7
|
|
|
7
|
-
The package
|
|
8
|
+
The package follows semantic versioning. Within the 1.x line, incompatible changes to stable public
|
|
9
|
+
APIs require a major release. Minor releases may add backward-compatible features, and patch releases
|
|
10
|
+
are intended to remain backward compatible.
|
|
8
11
|
|
|
9
12
|
The following surfaces are public and covered by this policy:
|
|
10
13
|
|
|
@@ -33,11 +36,12 @@ explicit `realtime/session`, `realtime/tools`, `realtime/conversation`, `realtim
|
|
|
33
36
|
normalized event names, configuration fields, and conversation/export shapes follow the same patch
|
|
34
37
|
compatibility rules as the rest of the package.
|
|
35
38
|
|
|
36
|
-
The realtime surface
|
|
39
|
+
The realtime surface follows the 1.x compatibility rules for its normalized public API. Provider-specific
|
|
40
|
+
wire events returned by `openai-events`, values
|
|
37
41
|
under `raw`, SDP/ICE behavior, and upstream model or voice availability are controlled by the provider
|
|
38
42
|
and are not normalized compatibility guarantees. New normalized event variants or optional metrics may
|
|
39
|
-
be added in a minor release.
|
|
40
|
-
|
|
43
|
+
be added in a minor release. Incompatible normalized API changes require a major release unless an urgent
|
|
44
|
+
security fix makes preserving the old behavior unsafe.
|
|
41
45
|
|
|
42
46
|
Platform interfaces for WebRTC and WebSocket are structural so applications can inject browser, server,
|
|
43
47
|
mobile, or test adapters without a framework dependency. A documented structural member is public;
|
|
@@ -48,8 +52,22 @@ turn-oriented transcription/completion/speech workflow. `RealtimeSession` owns a
|
|
|
48
52
|
live events, interruption, and normalized realtime conversation state. Neither is a compatibility alias
|
|
49
53
|
for the other.
|
|
50
54
|
|
|
55
|
+
## Image API stage
|
|
56
|
+
|
|
57
|
+
The `nexus-ai-pro/images` family is experimental in production-readiness, but published normalized
|
|
58
|
+
types, manager methods, operation events, and explicit subpath exports still follow the 1.x semantic
|
|
59
|
+
versioning rules. The experimental label does not permit an incompatible minor or patch release.
|
|
60
|
+
|
|
61
|
+
Provider payloads under `raw`, provider-specific error metadata, temporary delivery URLs, upstream model
|
|
62
|
+
availability, and generative output are not normalized compatibility guarantees. The current local
|
|
63
|
+
operation handle is process-bound and does not promise durable recovery, distributed cancellation, or
|
|
64
|
+
exactly-once provider execution. Those capabilities will use additive adapters and contracts when added.
|
|
65
|
+
`MemoryAssetStore` is likewise process-local and does not promise cross-process durability or shared
|
|
66
|
+
tenant state.
|
|
67
|
+
|
|
51
68
|
## Deprecation process
|
|
52
69
|
|
|
53
|
-
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog.
|
|
70
|
+
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. Removals
|
|
71
|
+
are reserved for major releases, except when an urgent security issue requires otherwise.
|
|
54
72
|
|
|
55
73
|
Report accidental compatibility regressions through the project issue tracker. Security issues should follow [SECURITY.md](./SECURITY.md).
|
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
Notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use semantic versioning
|
|
3
|
+
Notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases use semantic versioning.
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.0] - 2026-08-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- A `telephony/realtime-bridge` subpath joining a provider media stream to a realtime session:
|
|
12
|
+
inbound-only caller audio forwarding, outbound audio framing in emission order, barge-in that clears
|
|
13
|
+
provider-queued audio before cancelling the response, playback marks that resolve
|
|
14
|
+
`markAudioPlayed()`, stream lifecycle, and custom stream parameters for tenant routing.
|
|
15
|
+
- `twilioRealtimeAudioOptions()` pinning both directions to 8 kHz G.711 mu-law so telephony audio
|
|
16
|
+
reaches the model without transcoding.
|
|
17
|
+
- Call control and usage metering on `TelephonyProvider` and the Twilio adapter: `getCall`, `endCall`,
|
|
18
|
+
and `parseStatusCallback`, surfaced on `NexusAI` as `getCall`, `endCall`, and
|
|
19
|
+
`parseTelephonyStatusCallback`. Status callbacks carry the authoritative billable call duration.
|
|
20
|
+
- Phone-number management on `TelephonyProvider` and the Twilio adapter: `listPhoneNumbers` and
|
|
21
|
+
`updatePhoneNumber`, so an app can point a number at its own voice webhook and status callback.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- The package now ships parallel ESM and CommonJS builds. Every export subpath gained a `require`
|
|
26
|
+
condition, so NestJS and other `"module": "commonjs"` consumers can load it without a dynamic-import
|
|
27
|
+
shim. Types stay shared between both builds, and the packed-size guards were raised to account for the
|
|
28
|
+
duplicated JS payload.
|
|
29
|
+
|
|
30
|
+
## [1.1.0] - 2026-07-28
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- An experimental provider-neutral image operation family with portable asset locations,
|
|
35
|
+
`ImageManager`, generation/editing, strict capability negotiation, runtime provider registration,
|
|
36
|
+
visual-safety hooks, and cancellable local operation handles.
|
|
37
|
+
- Opt-in `images`, `images/assets`, `images/mock`, and `images/openai` subpaths with a deterministic
|
|
38
|
+
mock provider and an OpenAI Image API adapter for one-shot generation and reference-based editing.
|
|
39
|
+
- An image-provider conformance harness covering normalized assets, metadata, generation, editing, and
|
|
40
|
+
pre-aborted calls.
|
|
41
|
+
- A bounded tenant-isolated `MemoryAssetStore` with retention, defensive byte copies, computed SHA-256
|
|
42
|
+
checksums, capacity enforcement, and optional HTTP(S) signing.
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- Reconciled the changelog and API stability policy with the tagged 1.0.0 release.
|
|
47
|
+
|
|
48
|
+
## [1.0.0] - 2026-07-17
|
|
49
|
+
|
|
7
50
|
### Added
|
|
8
51
|
|
|
9
52
|
- An opt-in realtime package family with `realtime`, `realtime/session`, `realtime/tools`,
|
|
@@ -55,5 +98,6 @@ Notable changes to this project are recorded here. The format follows [Keep a Ch
|
|
|
55
98
|
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
56
99
|
- CLI and audit findings no longer disclose detected secret values.
|
|
57
100
|
|
|
58
|
-
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/
|
|
101
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v1.0.0...HEAD
|
|
102
|
+
[1.0.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v1.0.0
|
|
59
103
|
[0.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v0.9.0
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Use the whole pipeline for production AI features, or turn pieces off when you o
|
|
|
7
7
|
- NPM: https://www.npmjs.com/package/nexus-ai-pro
|
|
8
8
|
- GitHub: https://github.com/mkhitar-abrahamyan/nexus-ai
|
|
9
9
|
- Full technical notes and manual test cases: [NEXUS.md](./NEXUS.md)
|
|
10
|
-
-
|
|
10
|
+
- Image generation status and remaining infrastructure work: [ROADMAP.md](./ROADMAP.md)
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
@@ -15,7 +15,9 @@ Use the whole pipeline for production AI features, or turn pieces off when you o
|
|
|
15
15
|
npm install nexus-ai-pro
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Requires Node.js 22 or newer.
|
|
18
|
+
Requires Node.js 22 or newer. The package is authored as ESM and ships both an ESM and a CommonJS build,
|
|
19
|
+
so `import` and `require()` both work — including from NestJS and other apps compiled with
|
|
20
|
+
`"module": "commonjs"`. Types are shared between both builds.
|
|
19
21
|
The main Nexus pipeline is Node-oriented; the isolated realtime subpaths use portable structural
|
|
20
22
|
interfaces and can be bundled for modern browsers.
|
|
21
23
|
|
|
@@ -307,6 +309,63 @@ const response = await ai.completeVerified(
|
|
|
307
309
|
);
|
|
308
310
|
```
|
|
309
311
|
|
|
312
|
+
## Image Generation and Editing (Experimental)
|
|
313
|
+
|
|
314
|
+
Image operations use a separate provider-neutral manager because generated assets have different
|
|
315
|
+
capabilities, delivery modes, safety checks, and lifecycles from text completions.
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
import { NexusAI } from 'nexus-ai-pro';
|
|
319
|
+
import { OpenAIImageProvider } from 'nexus-ai-pro/images/openai';
|
|
320
|
+
|
|
321
|
+
const openaiImages = new OpenAIImageProvider({
|
|
322
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const mediaAi = new NexusAI({
|
|
326
|
+
providers: {},
|
|
327
|
+
images: {
|
|
328
|
+
defaultProvider: 'openai',
|
|
329
|
+
providers: { openai: openaiImages },
|
|
330
|
+
},
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
const image = await mediaAi.images.generate({
|
|
334
|
+
model: 'auto',
|
|
335
|
+
prompt: 'A clean product photograph of a red mechanical keyboard',
|
|
336
|
+
dimensions: { width: 1536, height: 1024 },
|
|
337
|
+
quality: 'high',
|
|
338
|
+
delivery: { kind: 'bytes', format: 'png' },
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
console.log(image.assets[0]?.location);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
`ImageProvider` is independent from completion providers. Explicit options are negotiated against the
|
|
345
|
+
selected provider's declared capabilities, so unsupported formats, delivery kinds, masks, seeds, or
|
|
346
|
+
dimensions fail before a provider call. The OpenAI adapter supports one-shot generation and
|
|
347
|
+
reference-based editing through byte assets. Masked OpenAI edits remain disabled until a transformer can
|
|
348
|
+
verify dimensions and convert the neutral mask contract to OpenAI's alpha-channel semantics.
|
|
349
|
+
|
|
350
|
+
Use `submit()` for a cancellable local operation handle with replayable lifecycle events:
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
const operation = mediaAi.images.submit('generate', {
|
|
354
|
+
prompt: 'A minimal blue geometric poster',
|
|
355
|
+
delivery: { kind: 'bytes', format: 'png' },
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
for await (const event of operation.events()) {
|
|
359
|
+
console.log(event.type);
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
For deterministic tests, register `MockImageProvider` from `nexus-ai-pro/images/mock`. The current
|
|
364
|
+
`submit()` handle is in-process; durable leases, recovery, distributed deduplication, and webhooks remain
|
|
365
|
+
future infrastructure work. `nexus-ai-pro/images/assets` includes a bounded, tenant-isolated
|
|
366
|
+
`MemoryAssetStore` for local development and single-process workloads; it computes SHA-256 checksums,
|
|
367
|
+
copies bytes at its boundaries, enforces retention and capacity, and never silently evicts live assets.
|
|
368
|
+
|
|
310
369
|
## Voice Integrations
|
|
311
370
|
|
|
312
371
|
Voice support is optional and split into small imports.
|
|
@@ -734,6 +793,80 @@ const call = await ai.createCall({
|
|
|
734
793
|
|
|
735
794
|
For smaller apps, skip Twilio entirely and register your own `TelephonyProvider`.
|
|
736
795
|
|
|
796
|
+
### Phone Agents: Bridging a Call to a Realtime Session
|
|
797
|
+
|
|
798
|
+
A phone agent needs the telephony media stream and a realtime session joined together. The bridge owns
|
|
799
|
+
that audio path — caller audio in, assistant audio out, barge-in, playback marks, and stream lifecycle —
|
|
800
|
+
while session configuration, tools, and authorization stay in application code.
|
|
801
|
+
|
|
802
|
+
```ts
|
|
803
|
+
import { createTelephonyRealtimeBridge, twilioRealtimeAudioOptions } from 'nexus-ai-pro/telephony/realtime-bridge';
|
|
804
|
+
import { OpenAIWebSocketTransport } from 'nexus-ai-pro/realtime/openai-websocket';
|
|
805
|
+
import { createRealtimeSession } from 'nexus-ai-pro/realtime/session';
|
|
806
|
+
|
|
807
|
+
// One socket per call, from your WebSocket server.
|
|
808
|
+
function handleCallSocket(socket: AppWebSocket) {
|
|
809
|
+
const session = createRealtimeSession({
|
|
810
|
+
provider: 'openai',
|
|
811
|
+
model: 'gpt-realtime',
|
|
812
|
+
transport: new OpenAIWebSocketTransport({ apiKey: process.env.OPENAI_API_KEY!, webSocketFactory }),
|
|
813
|
+
modalities: ['audio'],
|
|
814
|
+
instructions: 'You are a scheduling assistant.',
|
|
815
|
+
tools: [checkAvailability, createBooking],
|
|
816
|
+
// Telephony audio is 8 kHz G.711 mu-law; this passes it through untranscoded.
|
|
817
|
+
audio: twilioRealtimeAudioOptions({ output: { voice: 'alloy' } }),
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
const bridge = createTelephonyRealtimeBridge({
|
|
821
|
+
session,
|
|
822
|
+
telephony,
|
|
823
|
+
send: (message) => socket.send(message.body),
|
|
824
|
+
onStart: (event) => logger.info(`call ${event.callId} started for ${event.parameters?.tenant}`),
|
|
825
|
+
onStop: () => persistTranscript(session.export('json')),
|
|
826
|
+
onError: (error) => logger.error(error),
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
socket.on('message', (raw) => bridge.handleMessage(String(raw)));
|
|
830
|
+
socket.on('close', () => bridge.close());
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
The bridge feeds only inbound caller audio to the model, so an echoed outbound track never loops back.
|
|
835
|
+
On caller speech it clears audio already queued at the provider and cancels the in-flight response, which
|
|
836
|
+
is what stops the assistant talking over an interruption. Custom `<Parameter>` values from the stream
|
|
837
|
+
instruction are exposed as `bridge.parameters` for tenant and worker routing.
|
|
838
|
+
|
|
839
|
+
Pass `bargeIn: false` to keep queued audio playing, `autoConnect: false` to connect the session yourself,
|
|
840
|
+
and `await bridge.flush()` when you need outstanding sends to settle.
|
|
841
|
+
|
|
842
|
+
### Call Control and Usage Metering
|
|
843
|
+
|
|
844
|
+
Meter billable time from the provider's own record rather than from stream lifecycle events, which do not
|
|
845
|
+
account for ring time or provider-side teardown:
|
|
846
|
+
|
|
847
|
+
```ts
|
|
848
|
+
// From your status webhook.
|
|
849
|
+
const status = ai.parseTelephonyStatusCallback('twilio', requestBody);
|
|
850
|
+
if (status?.status === 'completed') {
|
|
851
|
+
await usage.recordCallMinutes({ callId: status.callId, seconds: status.durationSeconds ?? 0 });
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Or read it directly, and hang up from a tool.
|
|
855
|
+
const details = await ai.getCall({ callId });
|
|
856
|
+
await ai.endCall({ callId });
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
### Pointing a Number at Your Webhook
|
|
860
|
+
|
|
861
|
+
```ts
|
|
862
|
+
const [number] = await ai.listPhoneNumbers({ phoneNumber: '+15557650000' });
|
|
863
|
+
await ai.updatePhoneNumber({
|
|
864
|
+
id: number.id,
|
|
865
|
+
voiceUrl: 'https://api.example.com/voice/incoming',
|
|
866
|
+
statusCallbackUrl: 'https://api.example.com/voice/status',
|
|
867
|
+
});
|
|
868
|
+
```
|
|
869
|
+
|
|
737
870
|
## Security
|
|
738
871
|
|
|
739
872
|
Security is enabled by default with `standard` mode.
|
|
@@ -892,11 +1025,18 @@ import { ContextWindowManager } from 'nexus-ai-pro/context';
|
|
|
892
1025
|
import { guardrailPolicy } from 'nexus-ai-pro/security';
|
|
893
1026
|
import { RedisCacheAdapter } from 'nexus-ai-pro/cache';
|
|
894
1027
|
import { DeepSeekProvider } from 'nexus-ai-pro/providers/deepseek';
|
|
1028
|
+
import { ImageManager } from 'nexus-ai-pro/images';
|
|
1029
|
+
import { MemoryAssetStore } from 'nexus-ai-pro/images/assets';
|
|
1030
|
+
import { MockImageProvider } from 'nexus-ai-pro/images/mock';
|
|
1031
|
+
import { OpenAIImageProvider } from 'nexus-ai-pro/images/openai';
|
|
895
1032
|
import { createRealtimeSession } from 'nexus-ai-pro/realtime/session';
|
|
896
1033
|
import { OpenAIWebRTCTransport } from 'nexus-ai-pro/realtime/openai-webrtc';
|
|
1034
|
+
import { TelephonyManager } from 'nexus-ai-pro/telephony';
|
|
1035
|
+
import { TwilioTelephonyProvider } from 'nexus-ai-pro/telephony/twilio';
|
|
1036
|
+
import { createTelephonyRealtimeBridge } from 'nexus-ai-pro/telephony/realtime-bridge';
|
|
897
1037
|
```
|
|
898
1038
|
|
|
899
|
-
Provider SDKs are optional peer dependencies. The package
|
|
1039
|
+
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.
|
|
900
1040
|
|
|
901
1041
|
## Examples
|
|
902
1042
|
|
|
@@ -946,10 +1086,10 @@ npm run test:conformance:real
|
|
|
946
1086
|
|
|
947
1087
|
## Roadmap
|
|
948
1088
|
|
|
949
|
-
The
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1089
|
+
The experimental image foundation now includes portable asset types, `ImageManager`, provider
|
|
1090
|
+
capability negotiation, local operation handles, visual-safety hooks, deterministic conformance, and an
|
|
1091
|
+
opt-in OpenAI adapter. Durable operations, production asset storage, additional providers, and
|
|
1092
|
+
media-specific evaluations remain planned in [ROADMAP.md](./ROADMAP.md).
|
|
953
1093
|
|
|
954
1094
|
## Production Notes
|
|
955
1095
|
|
package/ROADMAP.md
CHANGED
|
@@ -36,7 +36,23 @@ Current limitations are intentional and should remain visible:
|
|
|
36
36
|
- Realtime video tracks, SIP transports, durable cost accounting beyond the configurable local estimate,
|
|
37
37
|
and a published latency benchmark methodology remain follow-on work.
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Current next-release work: first-class image generation
|
|
40
|
+
|
|
41
|
+
The experimental foundation is now implemented in the current development line:
|
|
42
|
+
|
|
43
|
+
- portable byte, URL, and stored asset locations plus image request/result, usage, safety, provenance,
|
|
44
|
+
provider-call context, and operation-handle types;
|
|
45
|
+
- a provider-neutral `ImageManager` with generation, editing, provider registration, strict capability
|
|
46
|
+
negotiation, visual-safety hooks, and cancellable in-process submissions;
|
|
47
|
+
- a deterministic network-free mock and a parallel image-provider conformance harness;
|
|
48
|
+
- an opt-in OpenAI Image API adapter for one-shot generation and reference-based editing;
|
|
49
|
+
- a bounded tenant-aware in-memory asset store with retention, defensive byte copies, computed SHA-256
|
|
50
|
+
checksums, capacity rejection, and optional signed-URL integration.
|
|
51
|
+
|
|
52
|
+
This surface remains experimental. OpenAI masks are intentionally disabled until a transformer can
|
|
53
|
+
verify dimensions and convert neutral mask polarity into provider alpha semantics. Durable operations,
|
|
54
|
+
filesystem/S3-compatible asset stores, a second cloud provider, ComfyUI, and media evaluation are still
|
|
55
|
+
required before promotion.
|
|
40
56
|
|
|
41
57
|
Image generation should be a separate operation family rather than another variation of
|
|
42
58
|
`complete()`. Text completions and generated assets have different request shapes, response
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NexusAI } from './nexus.js';
|
|
2
2
|
import type { AnthropicProviderConfig, AuditLogConfig, AzureOpenAIProviderConfig, CacheConfig, CohereProviderConfig, CostBudgetConfig, CustomProviderConfig, DeepSeekProviderConfig, GoogleProviderConfig, GroqProviderConfig, LMStudioProviderConfig, LlamaCppProviderConfig, LoggerConfig, MistralProviderConfig, NexusAIConfig, OllamaProviderConfig, OpenAIProviderConfig, OpenRouterProviderConfig, ProvidersConfig, RateLimitConfig, ResponseFormatConfig, RetryConfig, RoutingConfig, RoutingStrategy } from '../types/config.js';
|
|
3
3
|
import type { ContextWindowConfig } from '../types/context-window.js';
|
|
4
|
+
import type { ImageConfig } from '../types/images.js';
|
|
4
5
|
import type { SecurityConfig, SecurityLevel } from '../types/security.js';
|
|
5
6
|
import type { TokenOptimizerConfig } from '../types/optimizer.js';
|
|
6
7
|
import type { PipelineConfig } from '../pipeline/types.js';
|
|
@@ -53,6 +54,8 @@ export declare class NexusConfigBuilder {
|
|
|
53
54
|
security(config: SecurityLevel | SecurityConfig): this;
|
|
54
55
|
/** Sets context-window compaction behavior. */
|
|
55
56
|
contextWindow(config: ContextWindowConfig): this;
|
|
57
|
+
/** Sets image-provider defaults and registrations. */
|
|
58
|
+
images(config: ImageConfig): this;
|
|
56
59
|
/** Sets token optimization behavior. */
|
|
57
60
|
tokenOptimizer(config: TokenOptimizerConfig): this;
|
|
58
61
|
/** Sets exact, semantic, or hybrid cache behavior. */
|
|
@@ -98,6 +98,11 @@ export class NexusConfigBuilder {
|
|
|
98
98
|
this.config.contextWindow = config;
|
|
99
99
|
return this;
|
|
100
100
|
}
|
|
101
|
+
/** Sets image-provider defaults and registrations. */
|
|
102
|
+
images(config) {
|
|
103
|
+
this.config.images = config;
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
101
106
|
/** Sets token optimization behavior. */
|
|
102
107
|
tokenOptimizer(config) {
|
|
103
108
|
this.config.tokenOptimizer = config;
|
package/dist/core/nexus.d.ts
CHANGED
|
@@ -4,10 +4,12 @@ import type { NexusPlan } from '../types/planning.js';
|
|
|
4
4
|
import type { NexusResponse, NexusStream } from '../types/response.js';
|
|
5
5
|
import type { AgentConfig, AgentResult } from '../types/agent.js';
|
|
6
6
|
import type { SpeechRequest, SpeechResponse, TranscriptionRequest, TranscriptionResponse, VoiceProvider, VoiceSessionConfig, VoiceTurnRequest, VoiceTurnResponse } from '../types/voice.js';
|
|
7
|
-
import type {
|
|
7
|
+
import type { ImageProvider } from '../types/images.js';
|
|
8
|
+
import type { CreateCallRequest, CreateCallResponse, EndCallRequest, GetCallRequest, ListPhoneNumbersRequest, TelephonyCallDetails, TelephonyMediaStreamEvent, TelephonyOutboundAudioMessage, TelephonyPhoneNumber, TelephonyProvider, TelephonyResponseRequest, TelephonyStatusCallback, TelephonyWebhookResponse, TelephonyWebhookValidationRequest, UpdatePhoneNumberRequest } from '../types/telephony.js';
|
|
8
9
|
import type { PipelineStep } from '../pipeline/types.js';
|
|
9
10
|
import type { BaseProvider } from '../providers/base.js';
|
|
10
11
|
import { type VoiceSession } from '../voice/index.js';
|
|
12
|
+
import { ImageManager } from '../images/manager.js';
|
|
11
13
|
import { type VerificationOptions } from '../hallucination/verification.js';
|
|
12
14
|
import { type SelfConsistencyOptions } from '../hallucination/consistency.js';
|
|
13
15
|
import { type BatchOptions, type BatchItemResult } from '../jobs/batch.js';
|
|
@@ -20,6 +22,8 @@ import { type SummarizeVerifyFormatOptions, type WorkflowResult } from '../workf
|
|
|
20
22
|
* Use `new NexusAI(config)` when you want full control, or `createNexus()` for the beginner shorthand.
|
|
21
23
|
*/
|
|
22
24
|
export declare class NexusAI {
|
|
25
|
+
/** Provider-neutral image generation and editing operations. */
|
|
26
|
+
readonly images: ImageManager;
|
|
23
27
|
private config;
|
|
24
28
|
private providers;
|
|
25
29
|
private router;
|
|
@@ -104,6 +108,27 @@ export declare class NexusAI {
|
|
|
104
108
|
event?: 'media' | 'mark' | 'clear';
|
|
105
109
|
markName?: string;
|
|
106
110
|
}): TelephonyOutboundAudioMessage;
|
|
111
|
+
/**
|
|
112
|
+
* Reads a call's current provider-side state, including the duration usage metering bills on.
|
|
113
|
+
*/
|
|
114
|
+
getCall(request: GetCallRequest): Promise<TelephonyCallDetails>;
|
|
115
|
+
/**
|
|
116
|
+
* Hangs up a live call through the provider's call-control API.
|
|
117
|
+
*/
|
|
118
|
+
endCall(request: EndCallRequest): Promise<TelephonyCallDetails>;
|
|
119
|
+
/**
|
|
120
|
+
* Parses a provider status webhook into a normalized record. Prefer this over media-stream
|
|
121
|
+
* lifecycle events when metering usage.
|
|
122
|
+
*/
|
|
123
|
+
parseTelephonyStatusCallback(providerName: string, body: string | URLSearchParams | Record<string, string | number | boolean | undefined>): TelephonyStatusCallback | undefined;
|
|
124
|
+
/**
|
|
125
|
+
* Lists phone numbers owned by the provider account.
|
|
126
|
+
*/
|
|
127
|
+
listPhoneNumbers(request?: ListPhoneNumbersRequest): Promise<TelephonyPhoneNumber[]>;
|
|
128
|
+
/**
|
|
129
|
+
* Points a phone number at a voice webhook and/or status callback.
|
|
130
|
+
*/
|
|
131
|
+
updatePhoneNumber(request: UpdatePhoneNumberRequest): Promise<TelephonyPhoneNumber>;
|
|
107
132
|
/**
|
|
108
133
|
* Registers a custom text provider at runtime.
|
|
109
134
|
*/
|
|
@@ -112,18 +137,24 @@ export declare class NexusAI {
|
|
|
112
137
|
* Registers a custom voice provider at runtime.
|
|
113
138
|
*/
|
|
114
139
|
registerVoiceProvider(name: string, provider: VoiceProvider): this;
|
|
140
|
+
/**
|
|
141
|
+
* Registers a custom image provider at runtime.
|
|
142
|
+
*/
|
|
143
|
+
registerImageProvider(name: string, provider: ImageProvider): this;
|
|
115
144
|
/**
|
|
116
145
|
* Registers a custom telephony provider at runtime.
|
|
117
146
|
*/
|
|
118
147
|
registerTelephonyProvider(name: string, provider: TelephonyProvider): this;
|
|
119
148
|
hasProvider(name: string): boolean;
|
|
120
149
|
hasVoiceProvider(name: string): boolean;
|
|
150
|
+
hasImageProvider(name: string): boolean;
|
|
121
151
|
hasTelephonyProvider(name: string): boolean;
|
|
122
152
|
/**
|
|
123
153
|
* Lists configured text providers.
|
|
124
154
|
*/
|
|
125
155
|
listProviders(): string[];
|
|
126
156
|
listVoiceProviders(): string[];
|
|
157
|
+
listImageProviders(): string[];
|
|
127
158
|
listTelephonyProviders(): string[];
|
|
128
159
|
/**
|
|
129
160
|
* Adds a custom pipeline step.
|
package/dist/core/nexus.js
CHANGED
|
@@ -15,6 +15,7 @@ import { Logger } from '../utils/logger.js';
|
|
|
15
15
|
import { SecurityPipeline } from '../security/index.js';
|
|
16
16
|
import { ContextWindowManager } from '../context/index.js';
|
|
17
17
|
import { VoiceManager } from '../voice/index.js';
|
|
18
|
+
import { ImageManager } from '../images/manager.js';
|
|
18
19
|
import { TelephonyManager } from '../telephony/index.js';
|
|
19
20
|
import { TokenOptimizer } from '../optimizer/index.js';
|
|
20
21
|
import { AgentLoop } from '../agent/loop.js';
|
|
@@ -41,6 +42,8 @@ import { summarizeVerifyFormat } from '../workflow/chains.js';
|
|
|
41
42
|
* Use `new NexusAI(config)` when you want full control, or `createNexus()` for the beginner shorthand.
|
|
42
43
|
*/
|
|
43
44
|
export class NexusAI {
|
|
45
|
+
/** Provider-neutral image generation and editing operations. */
|
|
46
|
+
images;
|
|
44
47
|
config;
|
|
45
48
|
providers = new Map();
|
|
46
49
|
router = new Router();
|
|
@@ -73,6 +76,7 @@ export class NexusAI {
|
|
|
73
76
|
this.security = new SecurityPipeline(this.config.security || 'standard');
|
|
74
77
|
this.contextWindow = new ContextWindowManager(this.config.contextWindow || {});
|
|
75
78
|
this.voiceManager = new VoiceManager(this.config.voice || {});
|
|
79
|
+
this.images = new ImageManager(this.config.images || {});
|
|
76
80
|
this.telephonyManager = new TelephonyManager(this.config.telephony || {});
|
|
77
81
|
this.optimizer = new TokenOptimizer(this.config.tokenOptimizer || {});
|
|
78
82
|
this.cache = new MemoryCache(this.config.cache?.maxEntries || 500);
|
|
@@ -439,6 +443,37 @@ export class NexusAI {
|
|
|
439
443
|
formatTelephonyAudioMessage(providerName, streamId, payload, options) {
|
|
440
444
|
return this.telephonyManager.formatAudioMessage(providerName, streamId, payload, options);
|
|
441
445
|
}
|
|
446
|
+
/**
|
|
447
|
+
* Reads a call's current provider-side state, including the duration usage metering bills on.
|
|
448
|
+
*/
|
|
449
|
+
async getCall(request) {
|
|
450
|
+
return this.telephonyManager.getCall(request);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Hangs up a live call through the provider's call-control API.
|
|
454
|
+
*/
|
|
455
|
+
async endCall(request) {
|
|
456
|
+
return this.telephonyManager.endCall(request);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Parses a provider status webhook into a normalized record. Prefer this over media-stream
|
|
460
|
+
* lifecycle events when metering usage.
|
|
461
|
+
*/
|
|
462
|
+
parseTelephonyStatusCallback(providerName, body) {
|
|
463
|
+
return this.telephonyManager.parseStatusCallback(providerName, body);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Lists phone numbers owned by the provider account.
|
|
467
|
+
*/
|
|
468
|
+
async listPhoneNumbers(request) {
|
|
469
|
+
return this.telephonyManager.listPhoneNumbers(request);
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Points a phone number at a voice webhook and/or status callback.
|
|
473
|
+
*/
|
|
474
|
+
async updatePhoneNumber(request) {
|
|
475
|
+
return this.telephonyManager.updatePhoneNumber(request);
|
|
476
|
+
}
|
|
442
477
|
/**
|
|
443
478
|
* Registers a custom text provider at runtime.
|
|
444
479
|
*/
|
|
@@ -453,6 +488,13 @@ export class NexusAI {
|
|
|
453
488
|
this.voiceManager.registerProvider(name, provider);
|
|
454
489
|
return this;
|
|
455
490
|
}
|
|
491
|
+
/**
|
|
492
|
+
* Registers a custom image provider at runtime.
|
|
493
|
+
*/
|
|
494
|
+
registerImageProvider(name, provider) {
|
|
495
|
+
this.images.registerImageProvider(name, provider);
|
|
496
|
+
return this;
|
|
497
|
+
}
|
|
456
498
|
/**
|
|
457
499
|
* Registers a custom telephony provider at runtime.
|
|
458
500
|
*/
|
|
@@ -466,6 +508,9 @@ export class NexusAI {
|
|
|
466
508
|
hasVoiceProvider(name) {
|
|
467
509
|
return this.voiceManager.hasProvider(name);
|
|
468
510
|
}
|
|
511
|
+
hasImageProvider(name) {
|
|
512
|
+
return this.images.hasImageProvider(name);
|
|
513
|
+
}
|
|
469
514
|
hasTelephonyProvider(name) {
|
|
470
515
|
return this.telephonyManager.hasProvider(name);
|
|
471
516
|
}
|
|
@@ -478,6 +523,9 @@ export class NexusAI {
|
|
|
478
523
|
listVoiceProviders() {
|
|
479
524
|
return this.voiceManager.listProviders();
|
|
480
525
|
}
|
|
526
|
+
listImageProviders() {
|
|
527
|
+
return this.images.listImageProviders();
|
|
528
|
+
}
|
|
481
529
|
listTelephonyProviders() {
|
|
482
530
|
return this.telephonyManager.listProviders();
|
|
483
531
|
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { AssetBytesLocation, AssetDescriptor, AssetInput, AssetProvenance } from '../types/images.js';
|
|
2
|
+
/** An asset input whose payload is already available locally as bytes. */
|
|
3
|
+
export interface ByteAssetInput extends Omit<AssetInput, 'location'> {
|
|
4
|
+
location: AssetBytesLocation;
|
|
5
|
+
}
|
|
6
|
+
/** A retrieved asset descriptor whose byte payload is available to the caller. */
|
|
7
|
+
export interface ByteAssetDescriptor extends Omit<AssetDescriptor, 'location'> {
|
|
8
|
+
location: AssetBytesLocation;
|
|
9
|
+
}
|
|
10
|
+
export interface AssetPutOptions {
|
|
11
|
+
/** Tenant that owns the asset. This value is required for every later access. */
|
|
12
|
+
tenantId: string;
|
|
13
|
+
provenance: AssetProvenance;
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
/** Relative retention period. Mutually exclusive with `expiresAt`. */
|
|
17
|
+
ttlSeconds?: number;
|
|
18
|
+
/** Absolute retention deadline. Mutually exclusive with `ttlSeconds`. */
|
|
19
|
+
expiresAt?: Date | string;
|
|
20
|
+
}
|
|
21
|
+
export interface AssetStat {
|
|
22
|
+
assetId: string;
|
|
23
|
+
tenantId: string;
|
|
24
|
+
/** Metadata-only descriptor. Its location points back to this store, not to the byte payload. */
|
|
25
|
+
descriptor: AssetDescriptor;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
expiresAt?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface AssetSignOptions {
|
|
30
|
+
/** Requested signed-URL lifetime. Enforcement is delegated to the configured signer. */
|
|
31
|
+
expiresInSeconds?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface AssetSignerContext extends AssetStat {
|
|
34
|
+
now: string;
|
|
35
|
+
expiresInSeconds?: number;
|
|
36
|
+
}
|
|
37
|
+
export type AssetSigner = (context: AssetSignerContext) => string | URL | Promise<string | URL>;
|
|
38
|
+
export type AssetStoreResult<T> = T | Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* Provider-neutral asset persistence contract.
|
|
41
|
+
*
|
|
42
|
+
* A store must treat a missing asset and an asset owned by another tenant identically. Implementations
|
|
43
|
+
* may complete synchronously or asynchronously so the same contract can cover memory and remote stores.
|
|
44
|
+
*/
|
|
45
|
+
export interface AssetStore {
|
|
46
|
+
put(input: ByteAssetInput, options: AssetPutOptions): AssetStoreResult<AssetStat>;
|
|
47
|
+
get(assetId: string, tenantId: string): AssetStoreResult<ByteAssetDescriptor | undefined>;
|
|
48
|
+
stat(assetId: string, tenantId: string): AssetStoreResult<AssetStat | undefined>;
|
|
49
|
+
delete(assetId: string, tenantId: string): AssetStoreResult<true | undefined>;
|
|
50
|
+
sign(assetId: string, tenantId: string, options?: AssetSignOptions): AssetStoreResult<string | undefined>;
|
|
51
|
+
purgeExpired(): AssetStoreResult<number>;
|
|
52
|
+
}
|
|
53
|
+
export interface MemoryAssetStoreOptions {
|
|
54
|
+
maxEntries?: number;
|
|
55
|
+
maxTotalBytes?: number;
|
|
56
|
+
maxAssetBytes?: number;
|
|
57
|
+
defaultTtlSeconds?: number;
|
|
58
|
+
createAssetId?: () => string;
|
|
59
|
+
now?: () => Date;
|
|
60
|
+
signer?: AssetSigner;
|
|
61
|
+
}
|
|
62
|
+
export interface MemoryAssetStoreSnapshot {
|
|
63
|
+
entries: number;
|
|
64
|
+
totalBytes: number;
|
|
65
|
+
maxEntries: number;
|
|
66
|
+
maxTotalBytes: number;
|
|
67
|
+
maxAssetBytes: number;
|
|
68
|
+
}
|
|
69
|
+
export declare class AssetStoreError extends Error {
|
|
70
|
+
readonly code: string;
|
|
71
|
+
readonly cause?: unknown | undefined;
|
|
72
|
+
constructor(message: string, code: string, cause?: unknown | undefined);
|
|
73
|
+
}
|
|
74
|
+
export declare class AssetStoreValidationError extends AssetStoreError {
|
|
75
|
+
constructor(message: string, cause?: unknown);
|
|
76
|
+
}
|
|
77
|
+
export type AssetCapacityConstraint = 'maxEntries' | 'maxTotalBytes' | 'maxAssetBytes';
|
|
78
|
+
export declare class AssetStoreCapacityError extends AssetStoreError {
|
|
79
|
+
readonly constraint: AssetCapacityConstraint;
|
|
80
|
+
readonly maximum: number;
|
|
81
|
+
readonly current: number;
|
|
82
|
+
readonly requested: number;
|
|
83
|
+
constructor(constraint: AssetCapacityConstraint, maximum: number, current: number, requested: number);
|
|
84
|
+
}
|
|
85
|
+
export declare class AssetStoreSigningError extends AssetStoreError {
|
|
86
|
+
constructor(message: string, cause?: unknown);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Process-local, bounded asset storage. Capacity exhaustion rejects the write; live entries are never
|
|
90
|
+
* silently evicted. Expired entries are purged before capacity and access decisions.
|
|
91
|
+
*/
|
|
92
|
+
export declare class MemoryAssetStore implements AssetStore {
|
|
93
|
+
private readonly entries;
|
|
94
|
+
private readonly maxEntries;
|
|
95
|
+
private readonly maxTotalBytes;
|
|
96
|
+
private readonly maxAssetBytes;
|
|
97
|
+
private readonly defaultTtlSeconds?;
|
|
98
|
+
private readonly createAssetId;
|
|
99
|
+
private readonly clock;
|
|
100
|
+
private readonly signer?;
|
|
101
|
+
private totalBytes;
|
|
102
|
+
constructor(options?: MemoryAssetStoreOptions);
|
|
103
|
+
put(input: ByteAssetInput, options: AssetPutOptions): AssetStat;
|
|
104
|
+
get(assetId: string, tenantId: string): ByteAssetDescriptor | undefined;
|
|
105
|
+
stat(assetId: string, tenantId: string): AssetStat | undefined;
|
|
106
|
+
delete(assetId: string, tenantId: string): true | undefined;
|
|
107
|
+
sign(assetId: string, tenantId: string, options?: AssetSignOptions): Promise<string | undefined>;
|
|
108
|
+
purgeExpired(): number;
|
|
109
|
+
snapshot(): MemoryAssetStoreSnapshot;
|
|
110
|
+
private assertCapacity;
|
|
111
|
+
private ownedEntry;
|
|
112
|
+
private purgeExpiredAt;
|
|
113
|
+
private removeEntry;
|
|
114
|
+
private nowMs;
|
|
115
|
+
}
|