@ariaflowagents/livekit-plugin-transport-ws 0.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.
@@ -0,0 +1,34 @@
1
+ import { TransportAdapter, type TransportAdapterConfig, type AudioEncoding } from '@ariaflow/livekit-plugin';
2
+ import type { WebSocket } from 'ws';
3
+ import { WebSocketAudioInput } from './audio_input.js';
4
+ import { WebSocketAudioOutput } from './audio_output.js';
5
+ import { WebSocketTextOutput } from './text_output.js';
6
+ /**
7
+ * Bundles WebSocket I/O implementations into a single TransportAdapter.
8
+ */
9
+ export declare class WebSocketTransportAdapter extends TransportAdapter {
10
+ private ws;
11
+ readonly id: string;
12
+ readonly audioInput: WebSocketAudioInput;
13
+ readonly audioOutput: WebSocketAudioOutput;
14
+ readonly textOutput: WebSocketTextOutput;
15
+ readonly config: TransportAdapterConfig;
16
+ private _isOpen;
17
+ /**
18
+ * Access the underlying WebSocket for raw I/O operations.
19
+ *
20
+ * Used by the realtime bridge (realtime_bridge.ts) and
21
+ * startNativeSession() to attach binary audio listeners
22
+ * directly on the socket without going through AudioInput/AudioOutput.
23
+ */
24
+ get rawSocket(): WebSocket;
25
+ constructor(ws: WebSocket, options?: {
26
+ id?: string;
27
+ sampleRate?: number;
28
+ numChannels?: number;
29
+ encoding?: AudioEncoding;
30
+ });
31
+ get isOpen(): boolean;
32
+ close(): Promise<void>;
33
+ }
34
+ //# sourceMappingURL=transport_adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport_adapter.d.ts","sourceRoot":"","sources":["../src/transport_adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,KAAK,sBAAsB,EAC3B,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,gBAAgB;IAqB3D,OAAO,CAAC,EAAE;IApBZ,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAC;IAExC,OAAO,CAAC,OAAO,CAAiB;IAEhC;;;;;;OAMG;IACH,IAAI,SAAS,IAAI,SAAS,CAEzB;gBAGS,EAAE,EAAE,SAAS,EACrB,OAAO,GAAE;QACP,EAAE,CAAC,EAAE,MAAM,CAAC;QACZ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,aAAa,CAAC;KACrB;IAoCR,IAAI,MAAM,IAAI,OAAO,CAEpB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAY7B"}
@@ -0,0 +1,72 @@
1
+ import { TransportAdapter, } from '@ariaflow/livekit-plugin';
2
+ import { WebSocketAudioInput } from './audio_input.js';
3
+ import { WebSocketAudioOutput } from './audio_output.js';
4
+ import { WebSocketTextOutput } from './text_output.js';
5
+ import { randomUUID } from 'node:crypto';
6
+ /**
7
+ * Bundles WebSocket I/O implementations into a single TransportAdapter.
8
+ */
9
+ export class WebSocketTransportAdapter extends TransportAdapter {
10
+ ws;
11
+ id;
12
+ audioInput;
13
+ audioOutput;
14
+ textOutput;
15
+ config;
16
+ _isOpen = true;
17
+ /**
18
+ * Access the underlying WebSocket for raw I/O operations.
19
+ *
20
+ * Used by the realtime bridge (realtime_bridge.ts) and
21
+ * startNativeSession() to attach binary audio listeners
22
+ * directly on the socket without going through AudioInput/AudioOutput.
23
+ */
24
+ get rawSocket() {
25
+ return this.ws;
26
+ }
27
+ constructor(ws, options = {}) {
28
+ super();
29
+ this.ws = ws;
30
+ this.id = options.id ?? randomUUID();
31
+ const sampleRate = options.sampleRate ?? 24000;
32
+ const numChannels = options.numChannels ?? 1;
33
+ const encoding = options.encoding ?? 'pcm_s16le';
34
+ this.config = {
35
+ sampleRate,
36
+ numChannels,
37
+ encoding,
38
+ samplesPerChannel: null,
39
+ };
40
+ this.audioInput = new WebSocketAudioInput(ws, sampleRate, numChannels);
41
+ this.audioOutput = new WebSocketAudioOutput(ws, this.id, sampleRate);
42
+ this.textOutput = new WebSocketTextOutput(ws, this.id);
43
+ ws.on('close', () => {
44
+ if (this._isOpen) {
45
+ this._isOpen = false;
46
+ void this.close();
47
+ }
48
+ });
49
+ ws.on('error', (err) => {
50
+ console.error('[WebSocketTransport] WebSocket error:', err.message);
51
+ if (this._isOpen) {
52
+ this._isOpen = false;
53
+ void this.close();
54
+ }
55
+ });
56
+ }
57
+ get isOpen() {
58
+ return this._isOpen;
59
+ }
60
+ async close() {
61
+ if (!this._isOpen)
62
+ return;
63
+ this._isOpen = false;
64
+ await this.audioInput.close();
65
+ await this.audioOutput.close();
66
+ await this.textOutput.close();
67
+ if (this.ws.readyState === this.ws.OPEN) {
68
+ this.ws.close(1000, 'Session ended');
69
+ }
70
+ }
71
+ }
72
+ //# sourceMappingURL=transport_adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport_adapter.js","sourceRoot":"","sources":["../src/transport_adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,GAGjB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;GAEG;AACH,MAAM,OAAO,yBAA0B,SAAQ,gBAAgB;IAqBnD;IApBD,EAAE,CAAS;IACX,UAAU,CAAsB;IAChC,WAAW,CAAuB;IAClC,UAAU,CAAsB;IAChC,MAAM,CAAyB;IAEhC,OAAO,GAAY,IAAI,CAAC;IAEhC;;;;;;OAMG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,YACU,EAAa,EACrB,UAKI,EAAE;QAEN,KAAK,EAAE,CAAC;QARA,OAAE,GAAF,EAAE,CAAW;QAUrB,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,UAAU,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,KAAK,CAAC;QAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,WAAW,CAAC;QAEjD,IAAI,CAAC,MAAM,GAAG;YACZ,UAAU;YACV,WAAW;YACX,QAAQ;YACR,iBAAiB,EAAE,IAAI;SACxB,CAAC;QAEF,IAAI,CAAC,UAAU,GAAG,IAAI,mBAAmB,CAAC,EAAE,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,GAAG,IAAI,oBAAoB,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACrE,IAAI,CAAC,UAAU,GAAG,IAAI,mBAAmB,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QAEvD,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAClB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;gBACrB,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACrB,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;YACpE,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;gBACjB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;gBACrB,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QAErB,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC/B,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QAE9B,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;YACxC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ import type { IncomingMessage } from 'node:http';
2
+ export interface WebSocketServerOptions {
3
+ /** Port to listen on. Default: 8080. */
4
+ port?: number;
5
+ /** Host to bind to. Default: '0.0.0.0'. */
6
+ host?: string;
7
+ /** Default audio sample rate. Default: 24000. */
8
+ defaultSampleRate?: number;
9
+ /** Default number of audio channels. Default: 1 (mono). */
10
+ defaultNumChannels?: number;
11
+ /** Optional authentication function. Return true to accept, false to reject. */
12
+ authenticate?: (req: IncomingMessage) => boolean | Promise<boolean>;
13
+ }
14
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,MAAM,WAAW,sBAAsB;IACrC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2DAA2D;IAC3D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrE"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@ariaflowagents/livekit-plugin-transport-ws",
3
+ "version": "0.9.0",
4
+ "description": "WebSocket transport adapter for LiveKit Agents. Run voice and text agents over plain WebSocket without a LiveKit server.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": ["dist"],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "clean": "rm -rf dist",
18
+ "typecheck": "tsc --noEmit",
19
+ "preexample": "tsc",
20
+ "example:basic": "tsx examples/basic_ws_agent.ts",
21
+ "example:text": "tsx examples/text_only_ws_agent.ts",
22
+ "test": "bun test test",
23
+ "test:e2e:ws-native": "npx tsx test/e2e/ws-native-e2e.ts",
24
+ "test:e2e:ws-cascaded": "npx tsx test/e2e/ws-cascaded-e2e.ts",
25
+ "test:e2e:ws-native:debug": "NODE_DEBUG=* npx tsx test/e2e/ws-native-e2e.ts",
26
+ "test:e2e:ws-cascaded:debug": "NODE_DEBUG=* npx tsx test/e2e/ws-cascaded-e2e.ts"
27
+ },
28
+ "dependencies": {
29
+ "ws": "^8.18.0"
30
+ },
31
+ "peerDependencies": {
32
+ "@ariaflowagents/livekit-plugin": "workspace:*",
33
+ "@ariaflowagents/core": "workspace:*",
34
+ "@livekit/agents": ">=1.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "typescript": "^5.5.0",
38
+ "@types/ws": "^8.5.0",
39
+ "tsx": "^4.19.0",
40
+ "ai": "^6.0.0",
41
+ "zod": "^3.23.0",
42
+ "@google/genai": "1.43.0",
43
+ "@ariaflowagents/gemini-native-audio": "workspace:*",
44
+ "@livekit/agents-plugin-silero": "^1.0.48"
45
+ },
46
+ "license": "Apache-2.0"
47
+ }