dsh-realtime-agent 0.1.2 → 0.2.1

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
@@ -38,6 +38,22 @@ declare module '@deepseek-ai/cordis' {
38
38
  'realtime-agent/delegation'(request: DelegationRequest): DelegationAnswer | undefined | Promise<DelegationAnswer | undefined>;
39
39
  /** A session-scoped failure the adapter contained rather than throwing. */
40
40
  'realtime-agent/error'(error: Error): void;
41
+ /**
42
+ * Output audio: PCM16 in the session's declared output format.
43
+ *
44
+ * Emitted once per provider delta, in order, with no buffering. A consumer that cannot keep up is
45
+ * expected to drop frames rather than queue them — a queue that grows while nothing drains it
46
+ * presents first as latency and then as an unbounded allocation.
47
+ */
48
+ 'realtime-agent/audio'(pcm16: Uint8Array): void;
49
+ /**
50
+ * Input audio: capture frames to write to the open session.
51
+ *
52
+ * The host-side half of the microphone path. A capture device belongs in a client half, which
53
+ * cannot reach this context directly, so frames arrive here as an event and the agent keeps the
54
+ * only object that can write them. Emitted with no session open, this is dropped — not buffered.
55
+ */
56
+ 'realtime-agent/mic'(pcm16: Uint8Array): void;
41
57
  }
42
58
  }
43
59
  export * from './types.ts';
@@ -86,6 +102,8 @@ export interface HandlerDeps {
86
102
  readonly onClosed: () => void;
87
103
  /** Where a session-scoped failure is reported. */
88
104
  readonly onSessionError: (error: Error) => void;
105
+ /** Where output audio is delivered. Called once per provider delta. */
106
+ readonly onAudio: (pcm16: Uint8Array) => void;
89
107
  }
90
108
  /**
91
109
  * Build the session handlers.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAsB,eAAe,EAAE,uBAAuB,EAAsB,MAAM,cAAc,CAAA;AACpH,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAE1F,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;;;WAMG;QACH,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;QAC7H,2EAA2E;QAC3E,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;KAC3C;CACF;AAED,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAErE,wDAAwD;AACxD,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,sFAAsF;AACtF,eAAO,MAAM,MAAM,UAAwB,CAAA;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;aAQjB,CAAA;AAEF,yGAAyG;AACzG,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;IACrC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;IAC7B,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CAChD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,uBAAuB,CAkBzE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CA0DrE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,MAAM,MAAM,0BAA0B,CAAA;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAsB,eAAe,EAAE,uBAAuB,EAAsB,MAAM,cAAc,CAAA;AACpH,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AAEpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAE1F,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,MAAM;QACd;;;;;;WAMG;QACH,2BAA2B,CAAC,OAAO,EAAE,iBAAiB,GAAG,gBAAgB,GAAG,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAA;QAC7H,2EAA2E;QAC3E,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;QAC1C;;;;;;WAMG;QACH,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;QAC/C;;;;;;WAMG;QACH,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;KAC9C;CACF;AAED,cAAc,YAAY,CAAA;AAC1B,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAA;AACpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAErE,wDAAwD;AACxD,eAAO,MAAM,IAAI,mBAAmB,CAAA;AAEpC,sFAAsF;AACtF,eAAO,MAAM,MAAM,UAAwB,CAAA;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;aAQjB,CAAA;AAEF,yGAAyG;AACzG,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;IACrC,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,gCAAgC;IAChC,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAA;IAC7B,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAC/C,uEAAuE;IACvE,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CAC9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,uBAAuB,CAmBzE;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAgFrE"}
package/lib/index.js CHANGED
@@ -69,6 +69,7 @@ export function createHandlers(deps) {
69
69
  void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs)
70
70
  .catch(deps.onSessionError);
71
71
  },
72
+ onAudio: (pcm16) => { deps.onAudio(pcm16); },
72
73
  onClosed: () => { deps.onClosed(); },
73
74
  onError: (error) => { deps.onSessionError(error); },
74
75
  };
@@ -88,6 +89,7 @@ export function apply(ctx, config) {
88
89
  timeoutMs: config.delegationTimeoutMs,
89
90
  onClosed: () => { session = undefined; },
90
91
  onSessionError: (error) => { ctx.emit('realtime-agent/error', error); },
92
+ onAudio: (pcm16) => { ctx.emit('realtime-agent/audio', pcm16); },
91
93
  });
92
94
  /**
93
95
  * Open a session, or return the one already open.
@@ -128,6 +130,28 @@ export function apply(ctx, config) {
128
130
  yield () => { for (const dispose of disposers)
129
131
  dispose(); };
130
132
  }, 'realtime-agent.tools');
133
+ // The microphone seam. Output audio leaves through a handler the adapter already calls; input had no
134
+ // such route, because the object that captures it — a client half — cannot reach this context. So the
135
+ // frames arrive as an event, and the agent keeps the only object that can write them.
136
+ ctx.effect(function* () {
137
+ const dispose = ctx.on('realtime-agent/mic', (pcm16) => {
138
+ const current = session;
139
+ // No session: a capture device that starts before `voice_start` must not throw from inside a
140
+ // listener, and must not buffer either — see the event's own contract.
141
+ if (current === undefined)
142
+ return;
143
+ try {
144
+ current.sendAudio(pcm16);
145
+ }
146
+ catch (error) {
147
+ // A write into a session that closed a moment ago is a race, not a fault, and the adapter's own
148
+ // close handler decides what it means. Reporting beats throwing from a listener, which is the
149
+ // worst place to raise one.
150
+ ctx.emit('realtime-agent/error', error);
151
+ }
152
+ });
153
+ yield () => { dispose(); };
154
+ }, 'realtime-agent.mic');
131
155
  if (config.autoStart) {
132
156
  // `apply` is synchronous, so a failed open cannot be thrown from it — it is reported on the bus
133
157
  // instead. The plugin stays valid and a later start may succeed.
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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAwB,MAAM,wBAAwB,CAAA;AAC/G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAqBnD,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACnC;AAuBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,EAAE,CA6C1E"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAwB,MAAM,wBAAwB,CAAA;AAC/G,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAqBnD,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,eAAe,GAAG,SAAS,CAAA;IACnD,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,eAAe,CAAC,CAAA;IAC9C,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACnC;AAcD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,EAAE,CA2B1E"}
package/lib/tools.js CHANGED
@@ -24,14 +24,6 @@ const STOPPED_VALUE = {
24
24
  additionalProperties: false,
25
25
  properties: { closed: { type: 'boolean', required: true } },
26
26
  };
27
- const SAID_VALUE = {
28
- type: 'object',
29
- additionalProperties: false,
30
- properties: {
31
- spoken: { type: 'boolean', required: true },
32
- characters: { type: 'number', required: true },
33
- },
34
- };
35
27
  /**
36
28
  * The tools that let an agent drive a voice session.
37
29
  *
@@ -66,23 +58,6 @@ export function voiceToolDefinitions(deps) {
66
58
  return { closed: wasOpen };
67
59
  },
68
60
  }),
69
- defineTool({
70
- name: 'voice_say',
71
- description: 'Say something out loud in the live voice session, in your own voice.',
72
- parameters: { text: { type: 'string', required: true, description: 'What to say aloud.' } },
73
- output: jsonOutput(SAID_VALUE),
74
- async execute(args) {
75
- const session = deps.session();
76
- // Thrown, not returned as a value. A tool-thrown failure is the registry's own failure
77
- // channel, and reporting this as a successful result would leave the model believing it had
78
- // spoken when nothing was said.
79
- if (session === undefined) {
80
- throw new Error('no voice session is open — call voice_start first');
81
- }
82
- await session.appendCommentary(args.text);
83
- return { spoken: true, characters: args.text.length };
84
- },
85
- }),
86
61
  ];
87
62
  }
88
63
  //# sourceMappingURL=tools.js.map
package/lib/tools.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA8D,MAAM,wBAAwB,CAAA;AAG/G;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAkC,MAAS;IAI5D,OAAO;QACL,MAAM;QACN,MAAM,EAAE,CAAC,KAAc,EAAE,KAAoB,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;KAClG,CAAA;AACH,CAAC;AAYD,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;CACrD,CAAA;AAEV,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE;CACnD,CAAA;AAEV;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAmB;IACtD,OAAO;QACL,UAAU,CAAC;YACT,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,yFAAyF;YACtG,UAAU,EAAE,EAAE;YACd,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC;YACjC,KAAK,CAAC,OAAO;gBACX,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,CAAA;gBAClC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,CAAA;YAClC,CAAC;SACF,CAAC;QAEF,UAAU,CAAC;YACT,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,6DAA6D;YAC1E,UAAU,EAAE,EAAE;YACd,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC;YACjC,KAAK,CAAC,OAAO;gBACX,4FAA4F;gBAC5F,uEAAuE;gBACvE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,SAAS,CAAA;gBAC5C,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;gBACjB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;YAC5B,CAAC;SACF,CAAC;KACH,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-realtime-agent",
3
- "version": "0.1.2",
3
+ "version": "0.2.1",
4
4
  "description": "Delegation bridge for the dsh-realtime seam: answers what the voice model delegates, or says plainly that it cannot.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@deepseek-ai/dsh-tools": "^0.2.0-rc.2",
46
- "dsh-realtime": "^0.1.1"
46
+ "dsh-realtime": "^0.2.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@deepseek-ai/cordis": "^4.0.3",
package/src/index.ts CHANGED
@@ -41,6 +41,22 @@ declare module '@deepseek-ai/cordis' {
41
41
  'realtime-agent/delegation'(request: DelegationRequest): DelegationAnswer | undefined | Promise<DelegationAnswer | undefined>
42
42
  /** A session-scoped failure the adapter contained rather than throwing. */
43
43
  'realtime-agent/error'(error: Error): void
44
+ /**
45
+ * Output audio: PCM16 in the session's declared output format.
46
+ *
47
+ * Emitted once per provider delta, in order, with no buffering. A consumer that cannot keep up is
48
+ * expected to drop frames rather than queue them — a queue that grows while nothing drains it
49
+ * presents first as latency and then as an unbounded allocation.
50
+ */
51
+ 'realtime-agent/audio'(pcm16: Uint8Array): void
52
+ /**
53
+ * Input audio: capture frames to write to the open session.
54
+ *
55
+ * The host-side half of the microphone path. A capture device belongs in a client half, which
56
+ * cannot reach this context directly, so frames arrive here as an event and the agent keeps the
57
+ * only object that can write them. Emitted with no session open, this is dropped — not buffered.
58
+ */
59
+ 'realtime-agent/mic'(pcm16: Uint8Array): void
44
60
  }
45
61
  }
46
62
 
@@ -86,6 +102,8 @@ export interface HandlerDeps {
86
102
  readonly onClosed: () => void
87
103
  /** Where a session-scoped failure is reported. */
88
104
  readonly onSessionError: (error: Error) => void
105
+ /** Where output audio is delivered. Called once per provider delta. */
106
+ readonly onAudio: (pcm16: Uint8Array) => void
89
107
  }
90
108
 
91
109
  /**
@@ -108,6 +126,7 @@ export function createHandlers(deps: HandlerDeps): RealtimeSessionHandlers {
108
126
  void answerDelegation(session, delegation, deps.transcript.lines(), deps.ask, deps.timeoutMs)
109
127
  .catch(deps.onSessionError)
110
128
  },
129
+ onAudio: (pcm16: Uint8Array): void => { deps.onAudio(pcm16) },
111
130
  onClosed: (): void => { deps.onClosed() },
112
131
  onError: (error: Error): void => { deps.onSessionError(error) },
113
132
  }
@@ -129,6 +148,7 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
129
148
  timeoutMs: config.delegationTimeoutMs,
130
149
  onClosed: () => { session = undefined },
131
150
  onSessionError: (error) => { ctx.emit('realtime-agent/error', error) },
151
+ onAudio: (pcm16) => { ctx.emit('realtime-agent/audio', pcm16) },
132
152
  })
133
153
 
134
154
  /**
@@ -171,6 +191,27 @@ export function apply(ctx: Context, config: RealtimeAgentConfig): void {
171
191
  yield () => { for (const dispose of disposers) dispose() }
172
192
  }, 'realtime-agent.tools')
173
193
 
194
+ // The microphone seam. Output audio leaves through a handler the adapter already calls; input had no
195
+ // such route, because the object that captures it — a client half — cannot reach this context. So the
196
+ // frames arrive as an event, and the agent keeps the only object that can write them.
197
+ ctx.effect(function* () {
198
+ const dispose = ctx.on('realtime-agent/mic', (pcm16: Uint8Array) => {
199
+ const current = session
200
+ // No session: a capture device that starts before `voice_start` must not throw from inside a
201
+ // listener, and must not buffer either — see the event's own contract.
202
+ if (current === undefined) return
203
+ try {
204
+ current.sendAudio(pcm16)
205
+ } catch (error) {
206
+ // A write into a session that closed a moment ago is a race, not a fault, and the adapter's own
207
+ // close handler decides what it means. Reporting beats throwing from a listener, which is the
208
+ // worst place to raise one.
209
+ ctx.emit('realtime-agent/error', error as Error)
210
+ }
211
+ })
212
+ yield () => { dispose() }
213
+ }, 'realtime-agent.mic')
214
+
174
215
  if (config.autoStart) {
175
216
  // `apply` is synchronous, so a failed open cannot be thrown from it — it is reported on the bus
176
217
  // instead. The plugin stays valid and a later start may succeed.
package/src/tools.ts CHANGED
@@ -42,15 +42,6 @@ const STOPPED_VALUE = {
42
42
  properties: { closed: { type: 'boolean', required: true } },
43
43
  } as const
44
44
 
45
- const SAID_VALUE = {
46
- type: 'object',
47
- additionalProperties: false,
48
- properties: {
49
- spoken: { type: 'boolean', required: true },
50
- characters: { type: 'number', required: true },
51
- },
52
- } as const
53
-
54
45
  /**
55
46
  * The tools that let an agent drive a voice session.
56
47
  *
@@ -86,23 +77,5 @@ export function voiceToolDefinitions(deps: VoiceToolDeps): ToolDefinition[] {
86
77
  return { closed: wasOpen }
87
78
  },
88
79
  }),
89
-
90
- defineTool({
91
- name: 'voice_say',
92
- description: 'Say something out loud in the live voice session, in your own voice.',
93
- parameters: { text: { type: 'string', required: true, description: 'What to say aloud.' } },
94
- output: jsonOutput(SAID_VALUE),
95
- async execute(args) {
96
- const session = deps.session()
97
- // Thrown, not returned as a value. A tool-thrown failure is the registry's own failure
98
- // channel, and reporting this as a successful result would leave the model believing it had
99
- // spoken when nothing was said.
100
- if (session === undefined) {
101
- throw new Error('no voice session is open — call voice_start first')
102
- }
103
- await session.appendCommentary(args.text)
104
- return { spoken: true, characters: args.text.length }
105
- },
106
- }),
107
80
  ]
108
81
  }