Skip to content

Commit 9434df7

Browse files
Convert JS SDK streaming APIs from callbacks to async iterables (#545)
- [x] Convert JS SDK streaming APIs from callbacks to async iterables - [x] Add `return()` hook to async iterators to prevent unbounded buffering on early break - [x] Add guards in streaming callbacks to skip work after error or cancellation - [x] Fix test assertions to assert synchronous throws directly - [x] Replace O(n) `chunks.shift()` with O(1) head-index dequeue with compaction - [x] Guard against concurrent `next()` calls with `nextInFlight` flag - [x] Add comment explaining native stream cancellation limitation in `return()` - [x] Fix docs example for `completeStreamingChat(messages, tools)` overload to pass `tools` - [x] Regenerate TypeDoc API docs - [x] Type-check, code review, and security scan - [x] Add comments explaining why local variable captures are needed (closures lose `this`) - [x] Add comments clarifying promise-resolve wake-up pattern in `.then()` handler - [x] Add structural comments explaining the AsyncIterable/AsyncIterator factory pattern - [x] Apply same readability improvements to chatClient.ts <!-- START COPILOT CODING AGENT TIPS --> --- ⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with [Raycast](https://gh.io/cca-raycast-docs). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baijumeswani <12852605+baijumeswani@users.noreply.github.com>
1 parent 15cf28f commit 9434df7

19 files changed

Lines changed: 528 additions & 363 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,9 @@ const result = await audioClient.transcribe('recording.wav');
232232
console.log('Transcription:', result.text);
233233
234234
// Or stream in real-time
235-
await audioClient.transcribeStreaming('recording.wav', (chunk) => {
235+
for await (const chunk of audioClient.transcribeStreaming('recording.wav')) {
236236
process.stdout.write(chunk.text);
237-
});
237+
}
238238
239239
await whisperModel.unload();
240240
```

samples/js/audio-transcription-example/app.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ console.log('\nAudio transcription result:');
3939
console.log(transcription.text);
4040
console.log('✓ Audio transcription completed');
4141

42-
// Same example but with streaming transcription using callback
42+
// Same example but with streaming transcription using async iteration
4343
console.log('\nTesting streaming audio transcription...');
44-
await audioClient.transcribeStreaming('./Recording.mp3', (result) => {
44+
for await (const result of audioClient.transcribeStreaming('./Recording.mp3')) {
4545
// Output the intermediate transcription results as they are received without line ending
4646
process.stdout.write(result.text);
47-
});
47+
}
4848
console.log('\n✓ Streaming transcription completed');
4949

5050
// Unload the model

samples/js/chat-and-audio-foundry-local/src/app.js

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -76,22 +76,19 @@ async function main() {
7676

7777
// Summarize the transcription
7878
console.log("Generating summary...\n");
79-
await chatClient.completeStreamingChat(
80-
[
81-
{
82-
role: "system",
83-
content:
84-
"You are a helpful assistant. Summarize the following transcribed audio and extract key themes and action items.",
85-
},
86-
{ role: "user", content: transcription.text },
87-
],
88-
(chunk) => {
89-
const content = chunk.choices?.[0]?.message?.content;
90-
if (content) {
91-
process.stdout.write(content);
92-
}
79+
for await (const chunk of chatClient.completeStreamingChat([
80+
{
81+
role: "system",
82+
content:
83+
"You are a helpful assistant. Summarize the following transcribed audio and extract key themes and action items.",
84+
},
85+
{ role: "user", content: transcription.text },
86+
])) {
87+
const content = chunk.choices?.[0]?.message?.content;
88+
if (content) {
89+
process.stdout.write(content);
9390
}
94-
);
91+
}
9592
console.log("\n");
9693

9794
// --- Clean up ---

samples/js/native-chat-completions/app.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,14 @@ console.log(completion.choices[0]?.message?.content);
4141

4242
// Example streaming completion
4343
console.log('\nTesting streaming completion...');
44-
await chatClient.completeStreamingChat(
45-
[{ role: 'user', content: 'Write a short poem about programming.' }],
46-
(chunk) => {
47-
const content = chunk.choices?.[0]?.message?.content;
48-
if (content) {
49-
process.stdout.write(content);
50-
}
44+
for await (const chunk of chatClient.completeStreamingChat(
45+
[{ role: 'user', content: 'Write a short poem about programming.' }]
46+
)) {
47+
const content = chunk.choices?.[0]?.message?.content;
48+
if (content) {
49+
process.stdout.write(content);
5150
}
52-
);
51+
}
5352
console.log('\n');
5453

5554
// Unload the model

sdk/js/README.md

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,14 @@ console.log(completion.choices[0]?.message?.content);
6969

7070
// Example streaming completion
7171
console.log('\nTesting streaming completion...');
72-
await chatClient.completeStreamingChat(
73-
[{ role: 'user', content: 'Write a short poem about programming.' }],
74-
(chunk) => {
75-
const content = chunk.choices?.[0]?.message?.content;
76-
if (content) {
77-
process.stdout.write(content);
78-
}
72+
for await (const chunk of chatClient.completeStreamingChat(
73+
[{ role: 'user', content: 'Write a short poem about programming.' }]
74+
)) {
75+
const content = chunk.choices?.[0]?.message?.content;
76+
if (content) {
77+
process.stdout.write(content);
7978
}
80-
);
79+
}
8180
console.log('\n');
8281

8382
// Unload the model
@@ -157,15 +156,14 @@ console.log(response.choices[0].message.content);
157156
For real-time output, use streaming:
158157

159158
```typescript
160-
await chatClient.completeStreamingChat(
161-
[{ role: 'user', content: 'Write a short poem about programming.' }],
162-
(chunk) => {
163-
const content = chunk.choices?.[0]?.message?.content;
164-
if (content) {
165-
process.stdout.write(content);
166-
}
159+
for await (const chunk of chatClient.completeStreamingChat(
160+
[{ role: 'user', content: 'Write a short poem about programming.' }]
161+
)) {
162+
const content = chunk.choices?.[0]?.message?.content;
163+
if (content) {
164+
process.stdout.write(content);
167165
}
168-
);
166+
}
169167
```
170168

171169
### Audio Transcription
@@ -180,9 +178,9 @@ audioClient.settings.language = 'en';
180178
const result = await audioClient.transcribe('/path/to/audio.wav');
181179

182180
// Streaming transcription
183-
await audioClient.transcribeStreaming('/path/to/audio.wav', (chunk) => {
181+
for await (const chunk of audioClient.transcribeStreaming('/path/to/audio.wav')) {
184182
console.log(chunk);
185-
});
183+
}
186184
```
187185

188186
### Embedded Web Service

0 commit comments

Comments
 (0)