nexus-ai-pro 0.8.1 → 1.0.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 +55 -0
- package/CHANGELOG.md +59 -0
- package/README.md +245 -8
- package/ROADMAP.md +221 -0
- package/SECURITY.md +46 -0
- package/dist/agent/tool.js +3 -1
- package/dist/cache/adapters.js +3 -1
- package/dist/cli.js +29 -13
- package/dist/connectors/web.d.ts +12 -0
- package/dist/connectors/web.js +359 -22
- package/dist/context/window.js +10 -15
- package/dist/core/nexus.d.ts +2 -2
- package/dist/core/nexus.js +61 -20
- package/dist/core/response-format.js +32 -53
- package/dist/core/secure-stream.d.ts +1 -1
- package/dist/core/secure-stream.js +135 -26
- package/dist/embeddings/providers.js +3 -3
- package/dist/evals/judge.js +1 -3
- package/dist/evals/metrics.js +2 -4
- package/dist/evals/runner.js +2 -6
- package/dist/hallucination/consistency.js +1 -3
- package/dist/hallucination/factual.js +4 -6
- package/dist/hallucination/knowledge-graph.js +7 -9
- package/dist/hallucination/rag.js +4 -2
- package/dist/hallucination/verification.js +32 -9
- package/dist/next/route-handler.js +1 -1
- package/dist/ops/audit-logger.js +29 -1
- package/dist/ops/health.js +1 -3
- package/dist/ops/metrics.js +5 -2
- package/dist/optimizer/cost.js +2 -2
- package/dist/optimizer/densifier.js +7 -4
- package/dist/optimizer/index.js +2 -3
- package/dist/pipeline/types.d.ts +1 -1
- package/dist/providers/anthropic.js +4 -2
- package/dist/providers/base.js +76 -18
- package/dist/providers/cohere.js +2 -2
- package/dist/providers/errors.js +8 -10
- package/dist/providers/google.js +6 -4
- package/dist/providers/groq.js +1 -1
- package/dist/providers/mistral.js +1 -1
- package/dist/providers/openai.js +22 -12
- package/dist/rag/file-ingestion.js +1 -1
- package/dist/rag/ingestion.js +5 -4
- package/dist/realtime/conversation.d.ts +19 -0
- package/dist/realtime/conversation.js +406 -0
- package/dist/realtime/errors.d.ts +25 -0
- package/dist/realtime/errors.js +74 -0
- package/dist/realtime/events.d.ts +10 -0
- package/dist/realtime/events.js +39 -0
- package/dist/realtime/id.d.ts +2 -0
- package/dist/realtime/id.js +8 -0
- package/dist/realtime/index.d.ts +22 -0
- package/dist/realtime/index.js +12 -0
- package/dist/realtime/mock.transport.d.ts +55 -0
- package/dist/realtime/mock.transport.js +169 -0
- package/dist/realtime/openai-events.d.ts +5 -0
- package/dist/realtime/openai-events.js +404 -0
- package/dist/realtime/openai-server.d.ts +33 -0
- package/dist/realtime/openai-server.js +138 -0
- package/dist/realtime/openai-webrtc.transport.d.ts +153 -0
- package/dist/realtime/openai-webrtc.transport.js +871 -0
- package/dist/realtime/openai-websocket.transport.d.ts +65 -0
- package/dist/realtime/openai-websocket.transport.js +420 -0
- package/dist/realtime/provider.d.ts +37 -0
- package/dist/realtime/provider.js +59 -0
- package/dist/realtime/session.d.ts +110 -0
- package/dist/realtime/session.js +962 -0
- package/dist/realtime/tools.d.ts +47 -0
- package/dist/realtime/tools.js +358 -0
- package/dist/realtime/transport-utils.d.ts +55 -0
- package/dist/realtime/transport-utils.js +240 -0
- package/dist/realtime/types.d.ts +544 -0
- package/dist/realtime/types.js +1 -0
- package/dist/router/auto-router.js +13 -9
- package/dist/router/failover.d.ts +10 -3
- package/dist/router/failover.js +250 -50
- package/dist/security/index.d.ts +3 -2
- package/dist/security/index.js +45 -6
- package/dist/security/injection-calibration.js +6 -2
- package/dist/security/injection-detector.js +21 -7
- package/dist/security/input-guard.js +28 -14
- package/dist/security/output-guard.d.ts +8 -0
- package/dist/security/output-guard.js +146 -57
- package/dist/security/prompt-hardening.js +2 -1
- package/dist/security/schema-validator.js +5 -8
- package/dist/security/upload-scanner.js +3 -1
- package/dist/telephony/providers/twilio.js +14 -10
- package/dist/testing/provider-conformance.js +4 -4
- package/dist/types/config.d.ts +6 -0
- package/dist/types/providers.js +22 -10
- package/dist/utils/ids.js +1 -1
- package/dist/utils/tokenizer.js +17 -14
- package/dist/voice/manager.js +1 -3
- package/dist/voice/providers/openai.js +4 -2
- package/dist/voice/session.js +6 -14
- package/dist/workflow/chains.js +19 -8
- package/dist/workflow/domain.js +28 -12
- package/package.json +163 -45
- package/EXPLANATION.md +0 -434
- package/assets/nexus-ai-pro-presentation.jpg +0 -0
- package/examples/agent.ts +0 -69
- package/examples/basic.ts +0 -37
- package/examples/bullmq-worker.ts +0 -36
- package/examples/classifier-calibration.ts +0 -7
- package/examples/cli-eval.json +0 -16
- package/examples/config-builder.ts +0 -18
- package/examples/create-nexus.ts +0 -15
- package/examples/custom-provider.ts +0 -16
- package/examples/domain-workflows.ts +0 -38
- package/examples/exports/README.md +0 -10
- package/examples/exports/config.ts +0 -18
- package/examples/exports/providers.ts +0 -33
- package/examples/exports/root.ts +0 -54
- package/examples/exports/runtime-modules.ts +0 -40
- package/examples/feature-flags.ts +0 -65
- package/examples/minimal.ts +0 -45
- package/examples/ocr-pdf-ingestion.ts +0 -42
- package/examples/optimizer.ts +0 -43
- package/examples/otel-express.ts +0 -47
- package/examples/otel-node-http.ts +0 -46
- package/examples/persisted-vector-store.ts +0 -42
- package/examples/security.ts +0 -69
package/API_STABILITY.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# API Stability Policy
|
|
2
|
+
|
|
3
|
+
This policy describes compatibility guarantees for `nexus-ai-pro` beginning with version 0.9.0.
|
|
4
|
+
|
|
5
|
+
## Release stages
|
|
6
|
+
|
|
7
|
+
The package is pre-1.0. Minor releases may contain breaking changes when they are necessary, but those changes will be called out in the changelog with migration guidance. Patch releases are intended to remain backward compatible.
|
|
8
|
+
|
|
9
|
+
The following surfaces are public and covered by this policy:
|
|
10
|
+
|
|
11
|
+
- exports documented in the root package or an explicit `package.json` subpath;
|
|
12
|
+
- exported TypeScript types and runtime symbols;
|
|
13
|
+
- documented configuration keys, response shapes, and CLI commands.
|
|
14
|
+
|
|
15
|
+
Source files, `dist` file paths, examples, test helpers that are not exported, and undocumented implementation details are not public API. Import only from `nexus-ai-pro` or one of its explicit subpaths.
|
|
16
|
+
|
|
17
|
+
## Compatibility rules
|
|
18
|
+
|
|
19
|
+
- A public symbol will not be removed or incompatibly changed in a patch release.
|
|
20
|
+
- Deprecations will be documented before removal whenever practical.
|
|
21
|
+
- New optional fields, providers, exports, error subclasses, and enum-like union members may be added in a minor release.
|
|
22
|
+
- TypeScript improvements that expose previously invalid usage may arrive in a patch release.
|
|
23
|
+
- Security fixes may tighten validation or blocking behavior in a patch release when preserving the old behavior would leave users exposed.
|
|
24
|
+
- Provider behavior can change when an upstream API changes; Nexus will preserve its normalized request and response contracts where possible.
|
|
25
|
+
|
|
26
|
+
The package is ESM-only and supports Node.js 22 or newer. CommonJS `require()` and deep imports into `dist` or `src` are not supported.
|
|
27
|
+
|
|
28
|
+
## Realtime API stage
|
|
29
|
+
|
|
30
|
+
The opt-in `nexus-ai-pro/realtime` family is public in the current development line. This includes the
|
|
31
|
+
explicit `realtime/session`, `realtime/tools`, `realtime/conversation`, `realtime/openai-webrtc`,
|
|
32
|
+
`realtime/openai-websocket`, `realtime/openai-server`, and `realtime/mock` subpaths. Its exported symbols,
|
|
33
|
+
normalized event names, configuration fields, and conversation/export shapes follow the same patch
|
|
34
|
+
compatibility rules as the rest of the package.
|
|
35
|
+
|
|
36
|
+
The realtime surface is still pre-1.0. Provider-specific wire events returned by `openai-events`, values
|
|
37
|
+
under `raw`, SDP/ICE behavior, and upstream model or voice availability are controlled by the provider
|
|
38
|
+
and are not normalized compatibility guarantees. New normalized event variants or optional metrics may
|
|
39
|
+
be added in a minor release. A necessary incompatible change during 0.x will be documented in a minor
|
|
40
|
+
release with migration guidance.
|
|
41
|
+
|
|
42
|
+
Platform interfaces for WebRTC and WebSocket are structural so applications can inject browser, server,
|
|
43
|
+
mobile, or test adapters without a framework dependency. A documented structural member is public;
|
|
44
|
+
private transport internals and unexported protocol helpers are not.
|
|
45
|
+
|
|
46
|
+
`VoiceSession` and `RealtimeSession` are independent public APIs. `VoiceSession` remains a batch,
|
|
47
|
+
turn-oriented transcription/completion/speech workflow. `RealtimeSession` owns a persistent transport,
|
|
48
|
+
live events, interruption, and normalized realtime conversation state. Neither is a compatibility alias
|
|
49
|
+
for the other.
|
|
50
|
+
|
|
51
|
+
## Deprecation process
|
|
52
|
+
|
|
53
|
+
Deprecated APIs are marked with `@deprecated` in declarations and described in the changelog. During the 0.x series, removal will not normally occur earlier than the next minor release. After 1.0, removals will be reserved for major releases, except when an urgent security issue requires otherwise.
|
|
54
|
+
|
|
55
|
+
Report accidental compatibility regressions through the project issue tracker. Security issues should follow [SECURITY.md](./SECURITY.md).
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Changelog
|
|
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 while accounting for the pre-1.0 stability policy.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- An opt-in realtime package family with `realtime`, `realtime/session`, `realtime/tools`,
|
|
10
|
+
`realtime/conversation`, provider transport, server-helper, and deterministic mock subpaths. Realtime
|
|
11
|
+
code is not added to the root or batch voice import graph.
|
|
12
|
+
- Framework-independent OpenAI WebRTC and WebSocket transports with injectable platform interfaces,
|
|
13
|
+
secure server-owned WebRTC negotiation, microphone and remote-audio handling, cancellation, and
|
|
14
|
+
reconnect support.
|
|
15
|
+
- A persistent `RealtimeSession` and higher-level `createRealtimeAgent()` API with normalized and raw
|
|
16
|
+
events, barge-in, response cancellation, unheard-audio truncation, typed tools, confirmations,
|
|
17
|
+
idempotency keys, bounded execution, and transcript/usage state.
|
|
18
|
+
- Immutable normalized conversations with JSON, OpenAI-event, text, and analytics exports, plus
|
|
19
|
+
connection, first-audio, turn, tool, interruption, reconnect, token, audio-duration, and cost metrics.
|
|
20
|
+
- Realtime security controls for tool allowlists, transcript retention, PII hooks, and maximum session
|
|
21
|
+
and audio duration, with structural OpenTelemetry-compatible tracing and metrics hooks.
|
|
22
|
+
- Opt-in safe-tool result caching, active-connection/audio-duration metrics, and an application-owned
|
|
23
|
+
realtime cost estimator hook without bundled pricing tables.
|
|
24
|
+
- A network-free realtime scheduling example using the deterministic mock transport.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Realtime connections are documented as a separate opt-in operation family. Existing `VoiceSession`
|
|
29
|
+
behavior remains the batch transcription -> completion/tools -> speech workflow.
|
|
30
|
+
|
|
31
|
+
## [0.9.0] - 2026-07-15
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Full JSON Schema validation through Ajv and standard format validation through `ajv-formats`.
|
|
36
|
+
- Node.js 22 and 24 CI gates for linting, builds, tests, consumer type checks, and packed-package installation.
|
|
37
|
+
- OIDC trusted publishing with npm provenance for tagged releases.
|
|
38
|
+
- API stability, security, and contribution policies.
|
|
39
|
+
- Biome formatting/lint gates, test/example type checks, and built-in Node.js coverage thresholds.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- The supported runtime is now Node.js 22 or newer and the package is explicitly ESM-only.
|
|
44
|
+
- Provider, cache, and job entry points now use an explicit export map instead of wildcard exports.
|
|
45
|
+
- Published tarballs contain the runtime and essential package documentation, excluding repository examples and marketing assets.
|
|
46
|
+
- Provider peer dependency ranges are bounded to tested SDK lines.
|
|
47
|
+
- Build and publish scripts always clean and rebuild `dist` before packing.
|
|
48
|
+
- Security-enabled output streams validate the complete bounded response before yielding chunks.
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- Blocking output policies now stop unsafe completions instead of returning blocked content as successful output.
|
|
53
|
+
- Streaming redaction protects values that cross provider chunk boundaries.
|
|
54
|
+
- Provider timeouts abort in-flight completion and streaming requests.
|
|
55
|
+
- URL fetching rejects unsafe private-network targets and limits response reads.
|
|
56
|
+
- CLI and audit findings no longer disclose detected secret values.
|
|
57
|
+
|
|
58
|
+
[Unreleased]: https://github.com/mkhitar-abrahamyan/nexus-ai/compare/v0.9.0...HEAD
|
|
59
|
+
[0.9.0]: https://github.com/mkhitar-abrahamyan/nexus-ai/releases/tag/v0.9.0
|
package/README.md
CHANGED
|
@@ -7,6 +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
|
+
- Planned image generation and infrastructure work: [ROADMAP.md](./ROADMAP.md)
|
|
10
11
|
|
|
11
12
|
## Install
|
|
12
13
|
|
|
@@ -14,6 +15,10 @@ Use the whole pipeline for production AI features, or turn pieces off when you o
|
|
|
14
15
|
npm install nexus-ai-pro
|
|
15
16
|
```
|
|
16
17
|
|
|
18
|
+
Requires Node.js 22 or newer. `nexus-ai-pro` is ESM-only: use `import` from an ES module rather than CommonJS `require()`.
|
|
19
|
+
The main Nexus pipeline is Node-oriented; the isolated realtime subpaths use portable structural
|
|
20
|
+
interfaces and can be bundled for modern browsers.
|
|
21
|
+
|
|
17
22
|
Install only the provider SDKs your app uses. The OpenAI SDK also powers OpenAI-compatible adapters such as OpenRouter, Groq, Mistral, DeepSeek, Azure OpenAI, LM Studio, and llama.cpp.
|
|
18
23
|
|
|
19
24
|
```bash
|
|
@@ -21,6 +26,8 @@ npm install openai @anthropic-ai/sdk ollama
|
|
|
21
26
|
```
|
|
22
27
|
|
|
23
28
|
The Google Gemini provider uses Node.js `fetch`, so it does not need an extra SDK.
|
|
29
|
+
Realtime transports use injected or platform WebRTC, WebSocket, and `fetch` interfaces and do not
|
|
30
|
+
require the OpenAI SDK.
|
|
24
31
|
|
|
25
32
|
## Quick Start
|
|
26
33
|
|
|
@@ -74,6 +81,7 @@ You can still pass a plain `NexusAIConfig` to `new NexusAI(...)` when you want f
|
|
|
74
81
|
- estimate tokens and cost before provider calls
|
|
75
82
|
- cache exact or semantically similar prompts
|
|
76
83
|
- add tools, agents, RAG context, evals, batch jobs, and queues
|
|
84
|
+
- build persistent realtime voice agents with interruption, live tools, and normalized conversation state
|
|
77
85
|
- keep TypeScript types around every request and response
|
|
78
86
|
|
|
79
87
|
## CLI
|
|
@@ -246,6 +254,12 @@ for await (const chunk of stream) {
|
|
|
246
254
|
|
|
247
255
|
All providers normalize streaming chunks to `text`, `tool_call`, `done`, or `error`.
|
|
248
256
|
|
|
257
|
+
When security is enabled, output streams are correctness-first: Nexus buffers and validates the
|
|
258
|
+
complete output before yielding any chunk, up to 1 MiB or 100,000 chunks. This prevents secrets,
|
|
259
|
+
PII, and blocked phrases split across provider chunks from leaking partially, at the cost of
|
|
260
|
+
token-by-token latency. `security: 'off'` preserves immediate streaming when that trade-off is
|
|
261
|
+
explicitly acceptable for the application.
|
|
262
|
+
|
|
249
263
|
### Tools and Agents
|
|
250
264
|
|
|
251
265
|
```ts
|
|
@@ -460,7 +474,210 @@ ai.registerVoiceProvider('private-voice', {
|
|
|
460
474
|
});
|
|
461
475
|
```
|
|
462
476
|
|
|
463
|
-
|
|
477
|
+
`VoiceSession` remains the batch-oriented path: each turn is transcription -> completion/tools -> optional
|
|
478
|
+
speech. For a persistent connection with live microphone audio, streamed remote audio, barge-in, and
|
|
479
|
+
provider events, use the separate realtime entry points below. Neither API replaces the other.
|
|
480
|
+
|
|
481
|
+
## Realtime Voice Agents
|
|
482
|
+
|
|
483
|
+
Realtime is opt-in and is not re-exported from the package root or from `nexus-ai-pro/voice`:
|
|
484
|
+
|
|
485
|
+
```ts
|
|
486
|
+
import {
|
|
487
|
+
createRealtimeAgent,
|
|
488
|
+
defineTool,
|
|
489
|
+
OpenAIRealtimeProvider,
|
|
490
|
+
} from 'nexus-ai-pro/realtime';
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
The framework-independent session normalizes connection, speech, transcript, response, tool,
|
|
494
|
+
interruption, error, conversation, and metrics events while retaining provider events when configured.
|
|
495
|
+
The browser and server transports use structural platform interfaces, so the realtime core does not
|
|
496
|
+
require React, a DOM shim, or an OpenAI SDK.
|
|
497
|
+
|
|
498
|
+
### Browser WebRTC
|
|
499
|
+
|
|
500
|
+
Give the browser a same-origin `sessionEndpoint`; never put a permanent provider API key in browser
|
|
501
|
+
code. The endpoint receives the SDP offer and returns the SDP answer while your server owns the
|
|
502
|
+
provider key and authoritative session configuration.
|
|
503
|
+
|
|
504
|
+
```ts
|
|
505
|
+
type BookingInput = { startTime: string; endTime: string; timezone: string };
|
|
506
|
+
|
|
507
|
+
const createBooking = defineTool({
|
|
508
|
+
name: 'create_calendar_booking',
|
|
509
|
+
description: 'Create a calendar booking after the user confirms it.',
|
|
510
|
+
parameters: {
|
|
511
|
+
type: 'object',
|
|
512
|
+
properties: {
|
|
513
|
+
startTime: { type: 'string', format: 'date-time' },
|
|
514
|
+
endTime: { type: 'string', format: 'date-time' },
|
|
515
|
+
timezone: { type: 'string' },
|
|
516
|
+
},
|
|
517
|
+
required: ['startTime', 'endTime', 'timezone'],
|
|
518
|
+
additionalProperties: false,
|
|
519
|
+
},
|
|
520
|
+
requiresConfirmation: true,
|
|
521
|
+
execute: async (input: BookingInput, context) =>
|
|
522
|
+
calendar.create(input, { idempotencyKey: context.idempotencyKey, signal: context.signal }),
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
const provider = new OpenAIRealtimeProvider({
|
|
526
|
+
sessionEndpoint: '/api/realtime/session',
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
const agent = createRealtimeAgent({
|
|
530
|
+
provider,
|
|
531
|
+
model: 'gpt-realtime',
|
|
532
|
+
modalities: ['audio', 'text'],
|
|
533
|
+
instructions: 'Check availability before booking. Never write without confirmation.',
|
|
534
|
+
tools: [createBooking],
|
|
535
|
+
voice: {
|
|
536
|
+
transport: 'webrtc',
|
|
537
|
+
voice: 'alloy',
|
|
538
|
+
turnDetection: { type: 'server_vad', silenceDurationMs: 450 },
|
|
539
|
+
interruption: {
|
|
540
|
+
enabled: true,
|
|
541
|
+
cancelResponse: true,
|
|
542
|
+
truncateUnheardAudio: true,
|
|
543
|
+
},
|
|
544
|
+
},
|
|
545
|
+
toolExecution: { mode: 'automatic', timeoutMs: 8_000, maxParallelCalls: 3 },
|
|
546
|
+
reconnect: { enabled: true, maxAttempts: 3, initialDelayMs: 500 },
|
|
547
|
+
conversation: { captureTranscripts: true, captureToolCalls: true, maxRawEvents: 2_000 },
|
|
548
|
+
security: {
|
|
549
|
+
maxSessionDurationMs: 30 * 60_000,
|
|
550
|
+
maxAudioDurationMs: 20 * 60_000,
|
|
551
|
+
toolAllowlist: ['create_calendar_booking'],
|
|
552
|
+
},
|
|
553
|
+
telemetry: {
|
|
554
|
+
includeTranscripts: false,
|
|
555
|
+
estimateCost: (usage) => pricing.estimateRealtime(usage),
|
|
556
|
+
},
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
agent.on('tool.confirmation.required', ({ call }) => {
|
|
560
|
+
const approved = window.confirm(`Create booking requested by ${call.name}?`);
|
|
561
|
+
agent.confirmTool(call.callId, approved);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
agent.on('metrics', (metrics) => {
|
|
565
|
+
console.log('speech end -> first audio', metrics.speechEndToFirstAudioMs);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
const audioElement = document.querySelector<HTMLAudioElement>('#assistant-audio')!;
|
|
569
|
+
await agent.connect({ microphone: true, audioElement });
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
WebRTC attaches the selected microphone track directly to the peer connection and assigns the remote
|
|
573
|
+
media stream to `audioElement`. Browsers still require HTTPS (or localhost), user permission, and often
|
|
574
|
+
a user gesture before audio playback. `sendAudio()` is intended for transports that accept binary
|
|
575
|
+
chunks; normal WebRTC microphone use should stay on the media track.
|
|
576
|
+
|
|
577
|
+
WebRTC first-audio timing uses the provider's `output_audio_buffer.started` event. WebSocket playback
|
|
578
|
+
remains application-owned, so its player must call `markAudioPlayed()` as described below.
|
|
579
|
+
|
|
580
|
+
A minimal server endpoint can use the focused server helper:
|
|
581
|
+
|
|
582
|
+
```ts
|
|
583
|
+
import { createOpenAIRealtimeCall } from 'nexus-ai-pro/realtime/openai-server';
|
|
584
|
+
|
|
585
|
+
export async function POST(request: Request) {
|
|
586
|
+
const answerSdp = await createOpenAIRealtimeCall(await request.text(), {
|
|
587
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
588
|
+
model: 'gpt-realtime',
|
|
589
|
+
session: {
|
|
590
|
+
instructions: 'You are a concise scheduling assistant.',
|
|
591
|
+
max_output_tokens: 1_024,
|
|
592
|
+
},
|
|
593
|
+
}, request.signal);
|
|
594
|
+
|
|
595
|
+
return new Response(answerSdp, { headers: { 'content-type': 'application/sdp' } });
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Authenticate that endpoint, authorize the tenant and requested tools, apply origin/CSRF and rate-limit
|
|
600
|
+
controls, and keep its accepted session options allowlisted. The client must not choose arbitrary tools,
|
|
601
|
+
instructions, limits, or credentials.
|
|
602
|
+
|
|
603
|
+
### Server WebSocket
|
|
604
|
+
|
|
605
|
+
Server-to-server agents can inject their WebSocket implementation and keep provider authorization in
|
|
606
|
+
request headers. The package deliberately does not force a WebSocket dependency:
|
|
607
|
+
|
|
608
|
+
```ts
|
|
609
|
+
import {
|
|
610
|
+
OpenAIWebSocketTransport,
|
|
611
|
+
type OpenAIWebSocketFactory,
|
|
612
|
+
} from 'nexus-ai-pro/realtime/openai-websocket';
|
|
613
|
+
import { createRealtimeSession } from 'nexus-ai-pro/realtime/session';
|
|
614
|
+
|
|
615
|
+
const webSocketFactory: OpenAIWebSocketFactory = (url, { headers, protocols }) =>
|
|
616
|
+
serverWebSocketClient.connect(url, { headers, protocols });
|
|
617
|
+
|
|
618
|
+
const session = createRealtimeSession({
|
|
619
|
+
provider: 'openai',
|
|
620
|
+
model: 'gpt-realtime',
|
|
621
|
+
transport: new OpenAIWebSocketTransport({
|
|
622
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
623
|
+
webSocketFactory,
|
|
624
|
+
}),
|
|
625
|
+
modalities: ['audio', 'text'],
|
|
626
|
+
reconnect: { enabled: true, maxAttempts: 3 },
|
|
627
|
+
connection: {
|
|
628
|
+
remoteAudioSink: (audio) => audioPlayer.enqueue(audio.data),
|
|
629
|
+
},
|
|
630
|
+
});
|
|
631
|
+
|
|
632
|
+
await session.connect();
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
When an application plays WebSocket audio itself, call `session.markAudioPlayed()` when the first bytes
|
|
636
|
+
actually reach playback. That makes the primary latency metric—user speech ended to first assistant
|
|
637
|
+
audio played—represent user experience rather than network receipt.
|
|
638
|
+
|
|
639
|
+
The global browser WebSocket path accepts only an ephemeral token. Supplying a permanent API key to a
|
|
640
|
+
browser adapter is rejected; use an injected server factory or an ephemeral-token provider instead.
|
|
641
|
+
|
|
642
|
+
### Interruption, tools, state, and exports
|
|
643
|
+
|
|
644
|
+
With interruption enabled, a `speech.started` event can stop local playback, cancel the active response,
|
|
645
|
+
and, for WebSocket playback with a known position, truncate unheard assistant audio. Applications can
|
|
646
|
+
also call `session.interrupt('manual')`.
|
|
647
|
+
|
|
648
|
+
Realtime tools support structural `parse`, `safeParse`, or `validate` schemas, execution timeouts,
|
|
649
|
+
bounded parallelism, safe-tool retries, duplicate call suppression, idempotency keys, allowlists, and
|
|
650
|
+
write confirmation. A tool marked `safe: true` can also opt into cross-call caching with `cache: true`
|
|
651
|
+
or `{ ttlMs, key }` when `toolExecution.cache` supplies a structural cache adapter; cache failures are
|
|
652
|
+
ignored unless `cacheFailureMode: 'fail'` is configured. `requiresConfirmation` does not replace server
|
|
653
|
+
authorization: re-check identity, permissions, business invariants, and idempotency in the tool
|
|
654
|
+
implementation.
|
|
655
|
+
|
|
656
|
+
Session state is available as immutable snapshots and four export formats:
|
|
657
|
+
|
|
658
|
+
```ts
|
|
659
|
+
const json = session.export('json');
|
|
660
|
+
const providerEvents = session.export('openai-events');
|
|
661
|
+
const transcript = session.export('text');
|
|
662
|
+
const analytics = session.export('analytics');
|
|
663
|
+
|
|
664
|
+
session.on('conversation.updated', (snapshot) => conversationStore.save(snapshot));
|
|
665
|
+
session.on('error', (error) => telemetry.recordException(error));
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
`json` contains normalized user/assistant speech, text messages, tool calls/results, interruptions,
|
|
669
|
+
errors, and latency/usage metrics. `openai-events` returns retained raw provider events; it is useful for
|
|
670
|
+
diagnostics and replay but follows the upstream provider schema. Disable transcript/raw-event retention
|
|
671
|
+
for sensitive workloads. `piiHook` redacts normalized conversation/event text, but deliberately does not
|
|
672
|
+
rewrite raw provider exports. Telemetry transcript fields are redacted by default; `includeTranscripts`
|
|
673
|
+
must be explicitly enabled. `estimateCost` accepts an application-owned pricing callback so model price
|
|
674
|
+
changes are not hard-coded into the package. The built-in limits and telemetry hooks are local controls,
|
|
675
|
+
not a durable session store, distributed rate limiter, or authorization system.
|
|
676
|
+
|
|
677
|
+
Focused public imports are available for `realtime`, `realtime/session`, `realtime/tools`,
|
|
678
|
+
`realtime/conversation`, `realtime/openai-webrtc`, `realtime/openai-websocket`,
|
|
679
|
+
`realtime/openai-server`, and `realtime/mock`. The deterministic mock is suitable for tests and demos;
|
|
680
|
+
see [`examples/realtime-scheduling.ts`](./examples/realtime-scheduling.ts).
|
|
464
681
|
|
|
465
682
|
## Phone Number Telephony
|
|
466
683
|
|
|
@@ -559,6 +776,12 @@ Useful helpers:
|
|
|
559
776
|
- URL and tool allowlist checks
|
|
560
777
|
- reusable policies through `guardrailPolicy(...)`
|
|
561
778
|
- `hardenPrompt(...)` for clearly delimiting untrusted input
|
|
779
|
+
- `createFetchUrlTool(...)` with DNS pinning, redirect validation, private-network blocking, and
|
|
780
|
+
bounded response reads
|
|
781
|
+
|
|
782
|
+
CLI scans and audit records redact detected values by default. `nexus scan --reveal-values` is
|
|
783
|
+
restricted to an interactive terminal; raw audit data requires both `includeSensitiveData: true`
|
|
784
|
+
and an explicit custom sink.
|
|
562
785
|
|
|
563
786
|
## Caching, Jobs, and Evals
|
|
564
787
|
|
|
@@ -583,6 +806,7 @@ Available runtime helpers:
|
|
|
583
806
|
- Redis and BullMQ queue adapters
|
|
584
807
|
- eval runner with quality, operations, RAG, safety metrics, and optional LLM-as-judge scoring
|
|
585
808
|
- voice sessions for multi-turn calls with conditional task prompts and app tools
|
|
809
|
+
- realtime sessions with WebRTC/WebSocket transports, interruption, tools, metrics, and conversation exports
|
|
586
810
|
- workflow templates for RAG answers, extraction, classification, comparison, support, sales, legal review, and code review
|
|
587
811
|
|
|
588
812
|
Use a plain assertion for small evals, or add an LLM judge when a rubric is more useful than exact matching:
|
|
@@ -668,9 +892,11 @@ import { ContextWindowManager } from 'nexus-ai-pro/context';
|
|
|
668
892
|
import { guardrailPolicy } from 'nexus-ai-pro/security';
|
|
669
893
|
import { RedisCacheAdapter } from 'nexus-ai-pro/cache';
|
|
670
894
|
import { DeepSeekProvider } from 'nexus-ai-pro/providers/deepseek';
|
|
895
|
+
import { createRealtimeSession } from 'nexus-ai-pro/realtime/session';
|
|
896
|
+
import { OpenAIWebRTCTransport } from 'nexus-ai-pro/realtime/openai-webrtc';
|
|
671
897
|
```
|
|
672
898
|
|
|
673
|
-
Provider SDKs are optional peer dependencies. The package is ESM-
|
|
899
|
+
Provider SDKs are optional peer dependencies. The package is ESM-only, 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` or `src` are unsupported.
|
|
674
900
|
|
|
675
901
|
## Examples
|
|
676
902
|
|
|
@@ -684,9 +910,11 @@ npm run example:basic
|
|
|
684
910
|
npm run example:security
|
|
685
911
|
npm run example:optimizer
|
|
686
912
|
npm run example:agent
|
|
913
|
+
npm run build && npx tsx examples/realtime-scheduling.ts
|
|
914
|
+
npx tsc -p tsconfig.examples.browser.json
|
|
687
915
|
```
|
|
688
916
|
|
|
689
|
-
|
|
917
|
+
Repository example files cover:
|
|
690
918
|
|
|
691
919
|
- OpenTelemetry with Node HTTP and Express
|
|
692
920
|
- BullMQ workers
|
|
@@ -695,25 +923,34 @@ Included example files cover:
|
|
|
695
923
|
- classifier calibration
|
|
696
924
|
- domain workflows
|
|
697
925
|
- custom providers
|
|
926
|
+
- deterministic realtime scheduling with tools, confirmation, metrics, and conversation exports
|
|
698
927
|
- import examples under `examples/exports`
|
|
699
928
|
|
|
700
929
|
## Test Commands
|
|
701
930
|
|
|
702
931
|
```bash
|
|
703
932
|
npm install
|
|
704
|
-
npm run
|
|
705
|
-
npm
|
|
706
|
-
npm run test:types
|
|
707
|
-
npm run test:clean-install
|
|
708
|
-
npm run test:conformance:mock
|
|
933
|
+
npm run check
|
|
934
|
+
npm run check:release
|
|
709
935
|
```
|
|
710
936
|
|
|
937
|
+
`check` runs formatting and lint gates, source/test/example type checks, the build, unit and mock
|
|
938
|
+
conformance tests, coverage thresholds, package import checks, and an external type-consumer test.
|
|
939
|
+
`check:release` additionally verifies the dry-run tarball and a clean packed-package install.
|
|
940
|
+
|
|
711
941
|
Real provider conformance is opt-in:
|
|
712
942
|
|
|
713
943
|
```bash
|
|
714
944
|
npm run test:conformance:real
|
|
715
945
|
```
|
|
716
946
|
|
|
947
|
+
## Roadmap
|
|
948
|
+
|
|
949
|
+
The next recommended feature family is first-class image generation and editing through a
|
|
950
|
+
provider-neutral `ImageManager`, portable asset types, durable operation handles, visual safety,
|
|
951
|
+
asset storage, and media-specific evaluations. The design and prioritized infrastructure backlog
|
|
952
|
+
are in [ROADMAP.md](./ROADMAP.md).
|
|
953
|
+
|
|
717
954
|
## Production Notes
|
|
718
955
|
|
|
719
956
|
- Use direct or rules-based routing when model choice is already known.
|