ai 6.0.292 → 6.0.294
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/CHANGELOG.md +19 -0
- package/dist/index.js +28 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -4
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.js +3 -2
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +3 -2
- package/dist/internal/index.mjs.map +1 -1
- package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +5 -2
- package/docs/03-ai-sdk-core/36-transcription.mdx +1 -0
- package/package.json +5 -5
- package/src/prompt/content-part.ts +1 -0
- package/src/prompt/convert-to-language-model-prompt.ts +3 -1
- package/src/util/write-to-server-response.ts +41 -2
|
@@ -2,6 +2,10 @@ import type { ServerResponse } from 'node:http';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Writes the content of a stream to a server response.
|
|
5
|
+
*
|
|
6
|
+
* When the client disconnects before the stream has been fully written
|
|
7
|
+
* (premature `close`), the stream is cancelled so that upstream resources
|
|
8
|
+
* can be released, and no further chunks are written.
|
|
5
9
|
*/
|
|
6
10
|
export function writeToServerResponse({
|
|
7
11
|
response,
|
|
@@ -24,22 +28,57 @@ export function writeToServerResponse({
|
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
const reader = stream.getReader();
|
|
31
|
+
|
|
32
|
+
// Detect client disconnects. `close` also fires after a regular `end()`;
|
|
33
|
+
// `writableFinished` distinguishes the two cases.
|
|
34
|
+
let clientDisconnected = false;
|
|
35
|
+
let onDisconnect: (() => void) | undefined;
|
|
36
|
+
const handleClose = () => {
|
|
37
|
+
if (response.writableFinished) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
clientDisconnected = true;
|
|
42
|
+
onDisconnect?.();
|
|
43
|
+
|
|
44
|
+
// cancelling the reader resolves a pending read with `done: true`:
|
|
45
|
+
reader.cancel(new Error('Client disconnected.')).catch(() => {});
|
|
46
|
+
};
|
|
47
|
+
response.once('close', handleClose);
|
|
48
|
+
|
|
49
|
+
// The response may have been destroyed before the close listener was
|
|
50
|
+
// registered. Cancel immediately instead of waiting indefinitely for the
|
|
51
|
+
// next stream chunk.
|
|
52
|
+
if (response.destroyed) {
|
|
53
|
+
handleClose();
|
|
54
|
+
}
|
|
55
|
+
|
|
27
56
|
const read = async () => {
|
|
28
57
|
try {
|
|
29
58
|
while (true) {
|
|
30
59
|
const { done, value } = await reader.read();
|
|
31
|
-
if (done) break;
|
|
60
|
+
if (done || clientDisconnected || response.destroyed) break;
|
|
32
61
|
|
|
33
62
|
// Respect backpressure: if write() returns false, wait for 'drain' event
|
|
34
63
|
const canContinue = response.write(value);
|
|
35
64
|
if (!canContinue) {
|
|
36
65
|
await new Promise<void>(resolve => {
|
|
66
|
+
// don't wait for `drain` on a disconnected response:
|
|
67
|
+
onDisconnect = resolve;
|
|
37
68
|
response.once('drain', resolve);
|
|
38
69
|
});
|
|
70
|
+
onDisconnect = undefined;
|
|
39
71
|
}
|
|
40
72
|
}
|
|
41
73
|
} finally {
|
|
42
|
-
response.
|
|
74
|
+
response.off('close', handleClose);
|
|
75
|
+
|
|
76
|
+
if (clientDisconnected || response.destroyed) {
|
|
77
|
+
// release the stream; ending a destroyed response is not possible:
|
|
78
|
+
reader.cancel().catch(() => {});
|
|
79
|
+
} else {
|
|
80
|
+
response.end();
|
|
81
|
+
}
|
|
43
82
|
}
|
|
44
83
|
};
|
|
45
84
|
|