veryfront 0.1.293 → 0.1.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/esm/deno.d.ts CHANGED
@@ -48,6 +48,7 @@ declare namespace _default {
48
48
  "./chat/message-prep": string;
49
49
  "./chat/final-step-fallback": string;
50
50
  "./chat/provider-errors": string;
51
+ "./chat/stream-watchdog": string;
51
52
  };
52
53
  let imports: {
53
54
  "veryfront/head": string;
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.293",
3
+ "version": "0.1.294",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -67,7 +67,8 @@ export default {
67
67
  "./chat/conversation": "./src/chat/conversation.ts",
68
68
  "./chat/message-prep": "./src/chat/message-prep.ts",
69
69
  "./chat/final-step-fallback": "./src/chat/final-step-fallback.ts",
70
- "./chat/provider-errors": "./src/chat/provider-errors.ts"
70
+ "./chat/provider-errors": "./src/chat/provider-errors.ts",
71
+ "./chat/stream-watchdog": "./src/chat/stream-watchdog.ts"
71
72
  },
72
73
  "imports": {
73
74
  "veryfront/head": "./src/react/runtime/core.ts",
@@ -63,4 +63,5 @@ export { type HostedStreamPartForUiChunkMapping, type HostedUiChunkMappingOption
63
63
  export { useCompletion, type UseCompletionOptions, type UseCompletionResult, } from "../agent/react/use-completion.js";
64
64
  export { useStreaming, type UseStreamingOptions, type UseStreamingResult, } from "../agent/react/use-streaming.js";
65
65
  export { useVoiceInput, type UseVoiceInputOptions, type UseVoiceInputResult, } from "../agent/react/use-voice-input.js";
66
+ export { ChatStreamIdleTimeoutError, type ChatStreamWatchdogOptions, type ChatStreamWatchdogPhase, type ChatStreamWatchdogState, createChatStreamWatchdog, createChatStreamWatchdogState, DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS, DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS, getNextChatStreamWatchdogState, isHeartbeatOnlyMetadataChunk, isLongRunningToolRunning, } from "./stream-watchdog.js";
66
67
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/chat/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/src/chat/index.ts"],"names":[],"mappings":"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"}
@@ -61,3 +61,4 @@ export { mapHostedStreamPartToChatUiChunks, } from "./hosted-ui-chunk-mapping.js
61
61
  export { useCompletion, } from "../agent/react/use-completion.js";
62
62
  export { useStreaming, } from "../agent/react/use-streaming.js";
63
63
  export { useVoiceInput, } from "../agent/react/use-voice-input.js";
64
+ export { ChatStreamIdleTimeoutError, createChatStreamWatchdog, createChatStreamWatchdogState, DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS, DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS, getNextChatStreamWatchdogState, isHeartbeatOnlyMetadataChunk, isLongRunningToolRunning, } from "./stream-watchdog.js";
@@ -0,0 +1,34 @@
1
+ import "../../_dnt.polyfills.js";
2
+ import type { ChatUiMessageChunk, MessageMetadata } from "./types.js";
3
+ export declare const DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS = 120000;
4
+ export declare const DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS = 300000;
5
+ export type ChatStreamWatchdogPhase = "response_pending" | "tool_input_streaming" | "tool_running" | "post_tool_idle";
6
+ export type ChatStreamWatchdogState = {
7
+ phase: ChatStreamWatchdogPhase;
8
+ timeoutMs: number;
9
+ toolCallId?: string;
10
+ toolName?: string;
11
+ };
12
+ export type ChatStreamWatchdogOptions = {
13
+ idleTimeoutMs?: number;
14
+ toolRunningTimeoutMs?: number;
15
+ longRunningToolNames?: Iterable<string>;
16
+ };
17
+ export declare class ChatStreamIdleTimeoutError extends Error {
18
+ readonly state: ChatStreamWatchdogState;
19
+ constructor(state: ChatStreamWatchdogState);
20
+ }
21
+ export declare function createChatStreamWatchdogState(phase: ChatStreamWatchdogPhase, metadata?: {
22
+ toolCallId?: string;
23
+ toolName?: string;
24
+ }, options?: Pick<Required<ChatStreamWatchdogOptions>, "idleTimeoutMs" | "toolRunningTimeoutMs">): ChatStreamWatchdogState;
25
+ export declare function isLongRunningToolRunning(current: ChatStreamWatchdogState, longRunningToolNames: ReadonlySet<string>): boolean;
26
+ export declare function getNextChatStreamWatchdogState(currentState: ChatStreamWatchdogState, chunk: ChatUiMessageChunk<MessageMetadata>, options?: ChatStreamWatchdogOptions): ChatStreamWatchdogState;
27
+ export declare function isHeartbeatOnlyMetadataChunk(chunk: ChatUiMessageChunk<MessageMetadata>): boolean;
28
+ export declare function createChatStreamWatchdog(options?: ChatStreamWatchdogOptions): {
29
+ signal: AbortSignal;
30
+ readonly lastTimeoutState: ChatStreamWatchdogState | null;
31
+ observe(chunk: ChatUiMessageChunk<MessageMetadata>): void;
32
+ dispose(): void;
33
+ };
34
+ //# sourceMappingURL=stream-watchdog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-watchdog.d.ts","sourceRoot":"","sources":["../../../src/src/chat/stream-watchdog.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEtE,eAAO,MAAM,mCAAmC,SAAU,CAAC;AAC3D,eAAO,MAAM,2CAA2C,SAAU,CAAC;AAEnE,MAAM,MAAM,uBAAuB,GAC/B,kBAAkB,GAClB,sBAAsB,GACtB,cAAc,GACd,gBAAgB,CAAC;AAErB,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,uBAAuB,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;CACzC,CAAC;AAEF,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;gBAE5B,KAAK,EAAE,uBAAuB;CAU3C;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,uBAAuB,EAC9B,QAAQ,CAAC,EAAE;IACT,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,EACD,OAAO,GAAE,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,eAAe,GAAG,sBAAsB,CAG1F,GACA,uBAAuB,CAOzB;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,uBAAuB,EAChC,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAC,GACxC,OAAO,CAMT;AAED,wBAAgB,8BAA8B,CAC5C,YAAY,EAAE,uBAAuB,EACrC,KAAK,EAAE,kBAAkB,CAAC,eAAe,CAAC,EAC1C,OAAO,CAAC,EAAE,yBAAyB,GAClC,uBAAuB,CA+DzB;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,kBAAkB,CAAC,eAAe,CAAC,GAAG,OAAO,CAEhG;AAED,wBAAgB,wBAAwB,CAAC,OAAO,CAAC,EAAE,yBAAyB;;+BAsChD,uBAAuB,GAAG,IAAI;mBAGvC,kBAAkB,CAAC,eAAe,CAAC;;EAgBrD"}
@@ -0,0 +1,142 @@
1
+ import "../../_dnt.polyfills.js";
2
+ import * as dntShim from "../../_dnt.shims.js";
3
+ export const DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS = 120_000;
4
+ export const DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS = 300_000;
5
+ export class ChatStreamIdleTimeoutError extends Error {
6
+ state;
7
+ constructor(state) {
8
+ const toolLabel = typeof state.toolName === "string" && state.toolName.length > 0
9
+ ? ` for ${state.toolName}${state.toolCallId ? ` (${state.toolCallId})` : ""}`
10
+ : state.toolCallId
11
+ ? ` for ${state.toolCallId}`
12
+ : "";
13
+ super(`Chat stream idle timeout after ${state.timeoutMs}ms during ${state.phase}${toolLabel}`);
14
+ this.name = "ChatStreamIdleTimeoutError";
15
+ this.state = state;
16
+ }
17
+ }
18
+ export function createChatStreamWatchdogState(phase, metadata, options = {
19
+ idleTimeoutMs: DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS,
20
+ toolRunningTimeoutMs: DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS,
21
+ }) {
22
+ return {
23
+ phase,
24
+ timeoutMs: phase === "tool_running" ? options.toolRunningTimeoutMs : options.idleTimeoutMs,
25
+ ...(metadata?.toolCallId ? { toolCallId: metadata.toolCallId } : {}),
26
+ ...(metadata?.toolName ? { toolName: metadata.toolName } : {}),
27
+ };
28
+ }
29
+ export function isLongRunningToolRunning(current, longRunningToolNames) {
30
+ return (current.phase === "tool_running" &&
31
+ typeof current.toolName === "string" &&
32
+ longRunningToolNames.has(current.toolName));
33
+ }
34
+ export function getNextChatStreamWatchdogState(currentState, chunk, options) {
35
+ const resolvedOptions = resolveChatStreamWatchdogOptions(options);
36
+ switch (chunk.type) {
37
+ case "tool-input-start":
38
+ return createChatStreamWatchdogState("tool_input_streaming", {
39
+ toolCallId: chunk.toolCallId,
40
+ toolName: chunk.toolName,
41
+ }, resolvedOptions);
42
+ case "tool-input-delta":
43
+ return createChatStreamWatchdogState("tool_input_streaming", {
44
+ toolCallId: chunk.toolCallId,
45
+ toolName: currentState.toolCallId === chunk.toolCallId
46
+ ? currentState.toolName
47
+ : undefined,
48
+ }, resolvedOptions);
49
+ case "tool-input-available":
50
+ return createChatStreamWatchdogState("tool_running", {
51
+ toolCallId: chunk.toolCallId,
52
+ toolName: chunk.toolName,
53
+ }, resolvedOptions);
54
+ case "tool-output-available":
55
+ case "tool-output-error":
56
+ case "tool-output-denied":
57
+ return createChatStreamWatchdogState("post_tool_idle", {
58
+ toolCallId: chunk.toolCallId,
59
+ toolName: currentState.toolCallId === chunk.toolCallId
60
+ ? currentState.toolName
61
+ : undefined,
62
+ }, resolvedOptions);
63
+ case "message-metadata":
64
+ return isLongRunningToolRunning(currentState, resolvedOptions.longRunningToolNames)
65
+ ? currentState
66
+ : createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
67
+ case "finish":
68
+ return createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
69
+ default:
70
+ return isLongRunningToolRunning(currentState, resolvedOptions.longRunningToolNames)
71
+ ? currentState
72
+ : createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
73
+ }
74
+ }
75
+ export function isHeartbeatOnlyMetadataChunk(chunk) {
76
+ return chunk.type === "message-metadata" && Object.keys(chunk.messageMetadata ?? {}).length === 0;
77
+ }
78
+ export function createChatStreamWatchdog(options) {
79
+ const resolvedOptions = resolveChatStreamWatchdogOptions(options);
80
+ const controller = new AbortController();
81
+ let state = createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
82
+ let timer = null;
83
+ let lastTimeoutState = null;
84
+ const clearTimer = () => {
85
+ if (timer !== null) {
86
+ clearTimeout(timer);
87
+ timer = null;
88
+ }
89
+ };
90
+ const arm = () => {
91
+ if (controller.signal.aborted) {
92
+ return;
93
+ }
94
+ clearTimer();
95
+ if (isLongRunningToolRunning(state, resolvedOptions.longRunningToolNames)) {
96
+ return;
97
+ }
98
+ timer = dntShim.setTimeout(() => {
99
+ lastTimeoutState = state;
100
+ controller.abort(new DOMException(new ChatStreamIdleTimeoutError(state).message, "AbortError"));
101
+ }, state.timeoutMs);
102
+ maybeUnrefTimer(timer);
103
+ };
104
+ arm();
105
+ return {
106
+ signal: controller.signal,
107
+ get lastTimeoutState() {
108
+ return lastTimeoutState;
109
+ },
110
+ observe(chunk) {
111
+ if (isHeartbeatOnlyMetadataChunk(chunk)) {
112
+ return;
113
+ }
114
+ state = getNextChatStreamWatchdogState(state, chunk, resolvedOptions);
115
+ if (chunk.type === "finish") {
116
+ clearTimer();
117
+ return;
118
+ }
119
+ arm();
120
+ },
121
+ dispose() {
122
+ clearTimer();
123
+ },
124
+ };
125
+ }
126
+ function resolveChatStreamWatchdogOptions(options) {
127
+ return {
128
+ idleTimeoutMs: options?.idleTimeoutMs ?? DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS,
129
+ toolRunningTimeoutMs: options?.toolRunningTimeoutMs ??
130
+ DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS,
131
+ longRunningToolNames: new Set(options?.longRunningToolNames ?? ["invoke_agent"]),
132
+ };
133
+ }
134
+ function maybeUnrefTimer(timer) {
135
+ if (typeof timer !== "object" || timer === null || !("unref" in timer)) {
136
+ return;
137
+ }
138
+ const timerWithUnref = timer;
139
+ if (typeof timerWithUnref.unref === "function") {
140
+ timerWithUnref.unref();
141
+ }
142
+ }
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.1.293";
1
+ export declare const VERSION = "0.1.294";
2
2
  //# sourceMappingURL=version-constant.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.293";
3
+ export const VERSION = "0.1.294";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.1.293",
3
+ "version": "0.1.294",
4
4
  "description": "The simplest way to build AI-powered apps",
5
5
  "keywords": [
6
6
  "react",
@@ -193,6 +193,10 @@
193
193
  "import": "./esm/src/chat/provider-errors.js",
194
194
  "types": "./esm/src/chat/provider-errors.d.ts"
195
195
  },
196
+ "./chat/stream-watchdog": {
197
+ "import": "./esm/src/chat/stream-watchdog.js",
198
+ "types": "./esm/src/chat/stream-watchdog.d.ts"
199
+ },
196
200
  "./tsconfig.json": "./tsconfig.json"
197
201
  },
198
202
  "scripts": {},
package/src/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.293",
3
+ "version": "0.1.294",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "workspace": [
@@ -67,7 +67,8 @@ export default {
67
67
  "./chat/conversation": "./src/chat/conversation.ts",
68
68
  "./chat/message-prep": "./src/chat/message-prep.ts",
69
69
  "./chat/final-step-fallback": "./src/chat/final-step-fallback.ts",
70
- "./chat/provider-errors": "./src/chat/provider-errors.ts"
70
+ "./chat/provider-errors": "./src/chat/provider-errors.ts",
71
+ "./chat/stream-watchdog": "./src/chat/stream-watchdog.ts"
71
72
  },
72
73
  "imports": {
73
74
  "veryfront/head": "./src/react/runtime/core.ts",
@@ -259,3 +259,17 @@ export {
259
259
  type UseVoiceInputOptions,
260
260
  type UseVoiceInputResult,
261
261
  } from "../agent/react/use-voice-input.js";
262
+
263
+ export {
264
+ ChatStreamIdleTimeoutError,
265
+ type ChatStreamWatchdogOptions,
266
+ type ChatStreamWatchdogPhase,
267
+ type ChatStreamWatchdogState,
268
+ createChatStreamWatchdog,
269
+ createChatStreamWatchdogState,
270
+ DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS,
271
+ DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS,
272
+ getNextChatStreamWatchdogState,
273
+ isHeartbeatOnlyMetadataChunk,
274
+ isLongRunningToolRunning,
275
+ } from "./stream-watchdog.js";
@@ -0,0 +1,222 @@
1
+ import "../../_dnt.polyfills.js";
2
+ import * as dntShim from "../../_dnt.shims.js";
3
+ import type { ChatUiMessageChunk, MessageMetadata } from "./types.js";
4
+
5
+ export const DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS = 120_000;
6
+ export const DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS = 300_000;
7
+
8
+ export type ChatStreamWatchdogPhase =
9
+ | "response_pending"
10
+ | "tool_input_streaming"
11
+ | "tool_running"
12
+ | "post_tool_idle";
13
+
14
+ export type ChatStreamWatchdogState = {
15
+ phase: ChatStreamWatchdogPhase;
16
+ timeoutMs: number;
17
+ toolCallId?: string;
18
+ toolName?: string;
19
+ };
20
+
21
+ export type ChatStreamWatchdogOptions = {
22
+ idleTimeoutMs?: number;
23
+ toolRunningTimeoutMs?: number;
24
+ longRunningToolNames?: Iterable<string>;
25
+ };
26
+
27
+ export class ChatStreamIdleTimeoutError extends Error {
28
+ readonly state: ChatStreamWatchdogState;
29
+
30
+ constructor(state: ChatStreamWatchdogState) {
31
+ const toolLabel = typeof state.toolName === "string" && state.toolName.length > 0
32
+ ? ` for ${state.toolName}${state.toolCallId ? ` (${state.toolCallId})` : ""}`
33
+ : state.toolCallId
34
+ ? ` for ${state.toolCallId}`
35
+ : "";
36
+ super(`Chat stream idle timeout after ${state.timeoutMs}ms during ${state.phase}${toolLabel}`);
37
+ this.name = "ChatStreamIdleTimeoutError";
38
+ this.state = state;
39
+ }
40
+ }
41
+
42
+ export function createChatStreamWatchdogState(
43
+ phase: ChatStreamWatchdogPhase,
44
+ metadata?: {
45
+ toolCallId?: string;
46
+ toolName?: string;
47
+ },
48
+ options: Pick<Required<ChatStreamWatchdogOptions>, "idleTimeoutMs" | "toolRunningTimeoutMs"> = {
49
+ idleTimeoutMs: DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS,
50
+ toolRunningTimeoutMs: DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS,
51
+ },
52
+ ): ChatStreamWatchdogState {
53
+ return {
54
+ phase,
55
+ timeoutMs: phase === "tool_running" ? options.toolRunningTimeoutMs : options.idleTimeoutMs,
56
+ ...(metadata?.toolCallId ? { toolCallId: metadata.toolCallId } : {}),
57
+ ...(metadata?.toolName ? { toolName: metadata.toolName } : {}),
58
+ };
59
+ }
60
+
61
+ export function isLongRunningToolRunning(
62
+ current: ChatStreamWatchdogState,
63
+ longRunningToolNames: ReadonlySet<string>,
64
+ ): boolean {
65
+ return (
66
+ current.phase === "tool_running" &&
67
+ typeof current.toolName === "string" &&
68
+ longRunningToolNames.has(current.toolName)
69
+ );
70
+ }
71
+
72
+ export function getNextChatStreamWatchdogState(
73
+ currentState: ChatStreamWatchdogState,
74
+ chunk: ChatUiMessageChunk<MessageMetadata>,
75
+ options?: ChatStreamWatchdogOptions,
76
+ ): ChatStreamWatchdogState {
77
+ const resolvedOptions = resolveChatStreamWatchdogOptions(options);
78
+
79
+ switch (chunk.type) {
80
+ case "tool-input-start":
81
+ return createChatStreamWatchdogState(
82
+ "tool_input_streaming",
83
+ {
84
+ toolCallId: chunk.toolCallId,
85
+ toolName: chunk.toolName,
86
+ },
87
+ resolvedOptions,
88
+ );
89
+
90
+ case "tool-input-delta":
91
+ return createChatStreamWatchdogState(
92
+ "tool_input_streaming",
93
+ {
94
+ toolCallId: chunk.toolCallId,
95
+ toolName: currentState.toolCallId === chunk.toolCallId
96
+ ? currentState.toolName
97
+ : undefined,
98
+ },
99
+ resolvedOptions,
100
+ );
101
+
102
+ case "tool-input-available":
103
+ return createChatStreamWatchdogState(
104
+ "tool_running",
105
+ {
106
+ toolCallId: chunk.toolCallId,
107
+ toolName: chunk.toolName,
108
+ },
109
+ resolvedOptions,
110
+ );
111
+
112
+ case "tool-output-available":
113
+ case "tool-output-error":
114
+ case "tool-output-denied":
115
+ return createChatStreamWatchdogState(
116
+ "post_tool_idle",
117
+ {
118
+ toolCallId: chunk.toolCallId,
119
+ toolName: currentState.toolCallId === chunk.toolCallId
120
+ ? currentState.toolName
121
+ : undefined,
122
+ },
123
+ resolvedOptions,
124
+ );
125
+
126
+ case "message-metadata":
127
+ return isLongRunningToolRunning(currentState, resolvedOptions.longRunningToolNames)
128
+ ? currentState
129
+ : createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
130
+
131
+ case "finish":
132
+ return createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
133
+
134
+ default:
135
+ return isLongRunningToolRunning(currentState, resolvedOptions.longRunningToolNames)
136
+ ? currentState
137
+ : createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
138
+ }
139
+ }
140
+
141
+ export function isHeartbeatOnlyMetadataChunk(chunk: ChatUiMessageChunk<MessageMetadata>): boolean {
142
+ return chunk.type === "message-metadata" && Object.keys(chunk.messageMetadata ?? {}).length === 0;
143
+ }
144
+
145
+ export function createChatStreamWatchdog(options?: ChatStreamWatchdogOptions) {
146
+ const resolvedOptions = resolveChatStreamWatchdogOptions(options);
147
+ const controller = new AbortController();
148
+ let state = createChatStreamWatchdogState("response_pending", undefined, resolvedOptions);
149
+ let timer: ReturnType<typeof dntShim.setTimeout> | null = null;
150
+ let lastTimeoutState: ChatStreamWatchdogState | null = null;
151
+
152
+ const clearTimer = () => {
153
+ if (timer !== null) {
154
+ clearTimeout(timer);
155
+ timer = null;
156
+ }
157
+ };
158
+
159
+ const arm = () => {
160
+ if (controller.signal.aborted) {
161
+ return;
162
+ }
163
+
164
+ clearTimer();
165
+
166
+ if (isLongRunningToolRunning(state, resolvedOptions.longRunningToolNames)) {
167
+ return;
168
+ }
169
+
170
+ timer = dntShim.setTimeout(() => {
171
+ lastTimeoutState = state;
172
+ controller.abort(
173
+ new DOMException(new ChatStreamIdleTimeoutError(state).message, "AbortError"),
174
+ );
175
+ }, state.timeoutMs);
176
+ maybeUnrefTimer(timer);
177
+ };
178
+
179
+ arm();
180
+
181
+ return {
182
+ signal: controller.signal,
183
+ get lastTimeoutState(): ChatStreamWatchdogState | null {
184
+ return lastTimeoutState;
185
+ },
186
+ observe(chunk: ChatUiMessageChunk<MessageMetadata>) {
187
+ if (isHeartbeatOnlyMetadataChunk(chunk)) {
188
+ return;
189
+ }
190
+
191
+ state = getNextChatStreamWatchdogState(state, chunk, resolvedOptions);
192
+ if (chunk.type === "finish") {
193
+ clearTimer();
194
+ return;
195
+ }
196
+ arm();
197
+ },
198
+ dispose() {
199
+ clearTimer();
200
+ },
201
+ };
202
+ }
203
+
204
+ function resolveChatStreamWatchdogOptions(options?: ChatStreamWatchdogOptions) {
205
+ return {
206
+ idleTimeoutMs: options?.idleTimeoutMs ?? DEFAULT_CHAT_STREAM_IDLE_TIMEOUT_MS,
207
+ toolRunningTimeoutMs: options?.toolRunningTimeoutMs ??
208
+ DEFAULT_CHAT_STREAM_TOOL_RUNNING_TIMEOUT_MS,
209
+ longRunningToolNames: new Set(options?.longRunningToolNames ?? ["invoke_agent"]),
210
+ };
211
+ }
212
+
213
+ function maybeUnrefTimer(timer: ReturnType<typeof dntShim.setTimeout>): void {
214
+ if (typeof timer !== "object" || timer === null || !("unref" in timer)) {
215
+ return;
216
+ }
217
+
218
+ const timerWithUnref: { unref?: unknown } = timer;
219
+ if (typeof timerWithUnref.unref === "function") {
220
+ timerWithUnref.unref();
221
+ }
222
+ }
@@ -1,3 +1,3 @@
1
1
  // Keep in sync with deno.json version.
2
2
  // scripts/release.ts updates this constant during releases.
3
- export const VERSION = "0.1.293";
3
+ export const VERSION = "0.1.294";