dsh-realtime-audio-ws 0.1.1 → 0.1.2

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/lib/index.d.ts CHANGED
@@ -22,10 +22,12 @@ export declare const Config: Schema<Schemastery.ObjectS<NoInfer<{
22
22
  path: Schema<string, string, "defined">;
23
23
  maxFrameBytes: Schema<number, number, "defined">;
24
24
  maxConnections: Schema<number, number, "defined">;
25
+ openSessionOnConnect: Schema<boolean, boolean, "defined">;
25
26
  }>>, Schemastery.ObjectT<NoInfer<{
26
27
  path: Schema<string, string, "defined">;
27
28
  maxFrameBytes: Schema<number, number, "defined">;
28
29
  maxConnections: Schema<number, number, "defined">;
30
+ openSessionOnConnect: Schema<boolean, boolean, "defined">;
29
31
  }>>, "plain">;
30
32
  export declare function apply(ctx: Context, config: RealtimeAudioWsConfig): void;
31
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AAEzF,mBAAmB;AACnB,eAAO,MAAM,IAAI,sBAAsB,CAAA;AAEvC,eAAO,MAAM,MAAM;;;;;;;;aAIjB,CAAA;AAqBF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,CA4CvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAOlD,OAAO,EAML,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAA;AAEnB,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAA;AAEzF,mBAAmB;AACnB,eAAO,MAAM,IAAI,sBAAsB,CAAA;AAEvC,eAAO,MAAM,MAAM;;;;;;;;;;aAQjB,CAAA;AAqBF,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,qBAAqB,GAAG,IAAI,CAoDvE"}
package/lib/index.js CHANGED
@@ -13,7 +13,7 @@
13
13
  import Schema from '@deepseek-ai/schemastery';
14
14
  import { attachAudioSocket } from './bridge.js';
15
15
  import { createUpgradeAcceptor, rejectUpgrade } from './upgrade.js';
16
- import { DEFAULT_MAX_CONNECTIONS, DEFAULT_MAX_FRAME_BYTES, DEFAULT_PATH, } from './types.js';
16
+ import { DEFAULT_MAX_CONNECTIONS, DEFAULT_MAX_FRAME_BYTES, DEFAULT_OPEN_SESSION_ON_CONNECT, DEFAULT_PATH, } from './types.js';
17
17
  export * from './types.js';
18
18
  export { attachAudioSocket, toBytes } from './bridge.js';
19
19
  export { createUpgradeAcceptor, rejectUpgrade } from './upgrade.js';
@@ -23,6 +23,10 @@ export const Config = Schema.object({
23
23
  path: Schema.string().default(DEFAULT_PATH),
24
24
  maxFrameBytes: Schema.natural().default(DEFAULT_MAX_FRAME_BYTES),
25
25
  maxConnections: Schema.natural().default(DEFAULT_MAX_CONNECTIONS),
26
+ // True, and deliberately not the same decision as the agent's `autoStart`. That one opens a session at
27
+ // boot with nobody asking, which is why it is false. This one opens a session because someone connected a
28
+ // microphone: a connection takes an explicit action, an authenticated one, and its absence is silence.
29
+ openSessionOnConnect: Schema.boolean().default(DEFAULT_OPEN_SESSION_ON_CONNECT),
26
30
  });
27
31
  export function apply(ctx, config) {
28
32
  ctx.inject(['connection', 'webServer'], (injected) => {
@@ -50,11 +54,21 @@ export function apply(ctx, config) {
50
54
  return;
51
55
  }
52
56
  clients.add(client);
57
+ // Ask for the session before the bridge goes in, so the first frames are written into a session
58
+ // that is being opened rather than dropped by the mic seam's no-session rule.
59
+ if (config.openSessionOnConnect)
60
+ ctx.emit('realtime-agent/start');
53
61
  attachAudioSocket(client, {
54
62
  emitMic: (pcm16) => { ctx.emit('realtime-agent/mic', pcm16); },
55
63
  subscribeAudio: (listener) => ctx.on('realtime-agent/audio', listener),
56
64
  maxFrameBytes: config.maxFrameBytes,
57
- onDetach: () => { clients.delete(client); },
65
+ onDetach: () => {
66
+ clients.delete(client);
67
+ // The last client leaving ends the session. This also covers the transport's own disposal,
68
+ // which terminates its clients — so a profile reload does not leave a session nobody holds.
69
+ if (config.openSessionOnConnect && clients.size === 0)
70
+ ctx.emit('realtime-agent/stop');
71
+ },
58
72
  });
59
73
  });
60
74
  },
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/lib/types.d.ts CHANGED
@@ -17,6 +17,8 @@ export declare const DEFAULT_PATH = "/dsh-realtime/audio";
17
17
  export declare const DEFAULT_MAX_FRAME_BYTES = 480000;
18
18
  /** How many sockets may be attached at once. One microphone is the honest default. */
19
19
  export declare const DEFAULT_MAX_CONNECTIONS = 1;
20
+ /** Whether an authenticated connection asks the agent to open the voice session. See the config field. */
21
+ export declare const DEFAULT_OPEN_SESSION_ON_CONNECT = true;
20
22
  export interface RealtimeAudioWsConfig {
21
23
  /**
22
24
  * Absolute pathname to claim. Registered exactly, so it must be distinct from every other route in the
@@ -33,6 +35,16 @@ export interface RealtimeAudioWsConfig {
33
35
  * two microphones on one session is a fault, not a feature.
34
36
  */
35
37
  readonly maxConnections: number;
38
+ /**
39
+ * Ask the agent to open the voice session when an authenticated client connects, and to close it when the
40
+ * last one leaves. Default true.
41
+ *
42
+ * This is not the agent's `autoStart`, and the two defaults differ for a reason. `autoStart` opens a
43
+ * session at boot with nobody asking, which is why it ships false. This one responds to a connection,
44
+ * which takes an explicit authenticated action — and with it false, a working microphone produces silence
45
+ * that looks like a fault anywhere but in this file.
46
+ */
47
+ readonly openSessionOnConnect: boolean;
36
48
  }
37
49
  /**
38
50
  * The slice of a WebSocket this package uses, described structurally.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,0GAA0G;AAC1G,eAAO,MAAM,YAAY,wBAAwB,CAAA;AAEjD,6FAA6F;AAC7F,eAAO,MAAM,uBAAuB,SAAU,CAAA;AAE9C,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C,SAAS,IAAI,IAAI,CAAA;IACjB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAA;IACnF,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAA;CAC9E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,0GAA0G;AAC1G,eAAO,MAAM,YAAY,wBAAwB,CAAA;AAEjD,6FAA6F;AAC7F,eAAO,MAAM,uBAAuB,SAAU,CAAA;AAE9C,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,IAAI,CAAA;AAExC,0GAA0G;AAC1G,eAAO,MAAM,+BAA+B,OAAO,CAAA;AAEnD,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAA;CACvC;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAA;IAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C,SAAS,IAAI,IAAI,CAAA;IACjB,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAA;IACnF,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAA;CAC9E"}
package/lib/types.js CHANGED
@@ -17,4 +17,6 @@ export const DEFAULT_PATH = '/dsh-realtime/audio';
17
17
  export const DEFAULT_MAX_FRAME_BYTES = 480_000;
18
18
  /** How many sockets may be attached at once. One microphone is the honest default. */
19
19
  export const DEFAULT_MAX_CONNECTIONS = 1;
20
+ /** Whether an authenticated connection asks the agent to open the voice session. See the config field. */
21
+ export const DEFAULT_OPEN_SESSION_ON_CONNECT = true;
20
22
  //# sourceMappingURL=types.js.map
package/lib/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,0GAA0G;AAC1G,MAAM,CAAC,MAAM,YAAY,GAAG,qBAAqB,CAAA;AAEjD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAA;AAE9C,sFAAsF;AACtF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAA"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,0GAA0G;AAC1G,MAAM,CAAC,MAAM,YAAY,GAAG,qBAAqB,CAAA;AAEjD,6FAA6F;AAC7F,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAO,CAAA;AAE9C,sFAAsF;AACtF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAA;AAExC,0GAA0G;AAC1G,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-realtime-audio-ws",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "The host end of the client half's transport: a WebSocket upgrade route that bridges microphone audio in and agent speech out.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "ws": "^8.22.0",
55
- "dsh-realtime-agent": "^0.2.1"
55
+ "dsh-realtime-agent": "^0.2.2"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "@deepseek-ai/cordis": "^4.0.3",
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import { createUpgradeAcceptor, rejectUpgrade } from './upgrade.ts'
22
22
  import {
23
23
  DEFAULT_MAX_CONNECTIONS,
24
24
  DEFAULT_MAX_FRAME_BYTES,
25
+ DEFAULT_OPEN_SESSION_ON_CONNECT,
25
26
  DEFAULT_PATH,
26
27
  type AudioSocket,
27
28
  type RealtimeAudioWsConfig,
@@ -38,6 +39,10 @@ export const Config = Schema.object({
38
39
  path: Schema.string().default(DEFAULT_PATH),
39
40
  maxFrameBytes: Schema.natural().default(DEFAULT_MAX_FRAME_BYTES),
40
41
  maxConnections: Schema.natural().default(DEFAULT_MAX_CONNECTIONS),
42
+ // True, and deliberately not the same decision as the agent's `autoStart`. That one opens a session at
43
+ // boot with nobody asking, which is why it is false. This one opens a session because someone connected a
44
+ // microphone: a connection takes an explicit action, an authenticated one, and its absence is silence.
45
+ openSessionOnConnect: Schema.boolean().default(DEFAULT_OPEN_SESSION_ON_CONNECT),
41
46
  })
42
47
 
43
48
  /**
@@ -86,11 +91,19 @@ export function apply(ctx: Context, config: RealtimeAudioWsConfig): void {
86
91
  return
87
92
  }
88
93
  clients.add(client)
94
+ // Ask for the session before the bridge goes in, so the first frames are written into a session
95
+ // that is being opened rather than dropped by the mic seam's no-session rule.
96
+ if (config.openSessionOnConnect) ctx.emit('realtime-agent/start')
89
97
  attachAudioSocket(client, {
90
98
  emitMic: (pcm16) => { ctx.emit('realtime-agent/mic', pcm16) },
91
99
  subscribeAudio: (listener) => ctx.on('realtime-agent/audio', listener),
92
100
  maxFrameBytes: config.maxFrameBytes,
93
- onDetach: () => { clients.delete(client) },
101
+ onDetach: () => {
102
+ clients.delete(client)
103
+ // The last client leaving ends the session. This also covers the transport's own disposal,
104
+ // which terminates its clients — so a profile reload does not leave a session nobody holds.
105
+ if (config.openSessionOnConnect && clients.size === 0) ctx.emit('realtime-agent/stop')
106
+ },
94
107
  })
95
108
  })
96
109
  },
package/src/types.ts CHANGED
@@ -21,6 +21,9 @@ export const DEFAULT_MAX_FRAME_BYTES = 480_000
21
21
  /** How many sockets may be attached at once. One microphone is the honest default. */
22
22
  export const DEFAULT_MAX_CONNECTIONS = 1
23
23
 
24
+ /** Whether an authenticated connection asks the agent to open the voice session. See the config field. */
25
+ export const DEFAULT_OPEN_SESSION_ON_CONNECT = true
26
+
24
27
  export interface RealtimeAudioWsConfig {
25
28
  /**
26
29
  * Absolute pathname to claim. Registered exactly, so it must be distinct from every other route in the
@@ -37,6 +40,16 @@ export interface RealtimeAudioWsConfig {
37
40
  * two microphones on one session is a fault, not a feature.
38
41
  */
39
42
  readonly maxConnections: number
43
+ /**
44
+ * Ask the agent to open the voice session when an authenticated client connects, and to close it when the
45
+ * last one leaves. Default true.
46
+ *
47
+ * This is not the agent's `autoStart`, and the two defaults differ for a reason. `autoStart` opens a
48
+ * session at boot with nobody asking, which is why it ships false. This one responds to a connection,
49
+ * which takes an explicit authenticated action — and with it false, a working microphone produces silence
50
+ * that looks like a fault anywhere but in this file.
51
+ */
52
+ readonly openSessionOnConnect: boolean
40
53
  }
41
54
 
42
55
  /**