Skip to content

Commit 58726f4

Browse files
committed
Support reusable rt session & phonic say
1 parent b8c3546 commit 58726f4

11 files changed

Lines changed: 994 additions & 140 deletions

File tree

agents/src/llm/realtime.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ export interface RealtimeCapabilities {
4949
autoToolReplyGeneration: boolean;
5050
audioOutput: boolean;
5151
manualFunctionCalls: boolean;
52+
midSessionContextUpdate?: boolean;
53+
midSessionInstructionsUpdate?: boolean;
54+
midSessionToolsUpdate?: boolean;
5255
}
5356

5457
export interface InputTranscriptionCompleted {
@@ -155,6 +158,13 @@ export abstract class RealtimeSession extends EventEmitter {
155158
return;
156159
}
157160

161+
say(
162+
_text: string | ReadableStream<string>,
163+
_options?: { allowInterruptions?: boolean },
164+
): Promise<GenerationCreatedEvent> {
165+
throw new Error(`${this.constructor.name} does not implement say(). use a TTS model instead`);
166+
}
167+
158168
private async _mainTaskImpl(signal: AbortSignal): Promise<void> {
159169
const reader = this.deferredInputStream.stream.getReader();
160170
while (true) {
@@ -167,6 +177,14 @@ export abstract class RealtimeSession extends EventEmitter {
167177
}
168178

169179
setInputAudioStream(audioStream: ReadableStream<AudioFrame>): void {
170-
this.deferredInputStream.setSource(audioStream);
180+
if (this.deferredInputStream.isSourceSet) {
181+
// Reused sessions must detach the previous audio source before rebinding.
182+
void this.deferredInputStream.detachSource();
183+
}
184+
try {
185+
this.deferredInputStream.setSource(audioStream);
186+
} catch (error) {
187+
throw error;
188+
}
171189
}
172190
}

agents/src/stream/deferred_stream.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export class DeferredReadableStream<T> {
4141
private transform: IdentityTransform<T>;
4242
private writer: WritableStreamDefaultWriter<T>;
4343
private sourceReader?: ReadableStreamDefaultReader<T>;
44+
private detachRequested = false;
4445

4546
constructor() {
4647
this.transform = new IdentityTransform<T>();
@@ -83,6 +84,11 @@ export class DeferredReadableStream<T> {
8384

8485
sourceError = e;
8586
} finally {
87+
if (this.detachRequested) {
88+
this.detachRequested = false;
89+
return;
90+
}
91+
8692
// any other error from source will be propagated to the consumer
8793
if (sourceError) {
8894
try {
@@ -124,6 +130,7 @@ export class DeferredReadableStream<T> {
124130
}
125131

126132
const sourceReader = this.sourceReader!;
133+
this.detachRequested = true;
127134
// Clear source first so future setSource() calls can reattach cleanly.
128135
this.sourceReader = undefined;
129136

0 commit comments

Comments
 (0)