veryfront 0.1.292 → 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.292",
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",
@@ -226,6 +226,10 @@ export declare function pushToolParts(parts: MessagePart[], toolName: string, to
226
226
  output?: unknown;
227
227
  errorText?: unknown;
228
228
  }): void;
229
+ export declare function toConversationPartsFromUiMessage(message: ChatUiMessage): MessagePart[];
230
+ export declare function hasIncompleteToolParts(message: ChatUiMessage): boolean;
231
+ export declare function markIncompleteToolPartsAsStopped(message: ChatUiMessage): ChatUiMessage;
232
+ export declare function markIncompleteToolPartsAsErrored(message: ChatUiMessage, errorText: string): ChatUiMessage;
229
233
  export declare function isToolCallPart(value: unknown): value is ToolCallLike;
230
234
  export declare function isToolResultPart(value: unknown): value is ToolResultLike;
231
235
  export declare function isTextPart(value: unknown): value is TextPartLike;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/src/chat/conversation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/src/chat/conversation.ts"],"names":[],"mappings":"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"}
@@ -214,6 +214,129 @@ export function pushToolParts(parts, toolName, toolCallId, state, part) {
214
214
  state: mapToolState(state),
215
215
  });
216
216
  }
217
+ function pushFileConversationPart(parts, part) {
218
+ const uploadId = part.uploadId ?? extractUploadId(part.url);
219
+ if (!uploadId)
220
+ return;
221
+ if (part.mediaType.startsWith("image/")) {
222
+ parts.push({
223
+ type: "image",
224
+ upload_id: uploadId,
225
+ media_type: part.mediaType,
226
+ ...(part.url ? { url: part.url } : {}),
227
+ });
228
+ return;
229
+ }
230
+ parts.push({
231
+ type: "file",
232
+ upload_id: uploadId,
233
+ media_type: part.mediaType,
234
+ ...(part.url ? { url: part.url } : {}),
235
+ });
236
+ }
237
+ export function toConversationPartsFromUiMessage(message) {
238
+ const parts = [];
239
+ for (const part of message.parts) {
240
+ if (part.type === "text") {
241
+ parts.push({ type: "text", text: part.text });
242
+ continue;
243
+ }
244
+ if (part.type === "reasoning") {
245
+ parts.push({ type: "reasoning", text: part.text });
246
+ continue;
247
+ }
248
+ if (part.type === "step-start") {
249
+ continue;
250
+ }
251
+ if (part.type === "source-url") {
252
+ parts.push({
253
+ type: "citation",
254
+ source_id: part.sourceId,
255
+ title: part.title,
256
+ url: part.url,
257
+ });
258
+ continue;
259
+ }
260
+ if (part.type === "source-document") {
261
+ parts.push({
262
+ type: "citation",
263
+ source_id: part.sourceId,
264
+ title: part.title,
265
+ });
266
+ continue;
267
+ }
268
+ if (part.type === "file") {
269
+ pushFileConversationPart(parts, part);
270
+ continue;
271
+ }
272
+ if (isDataUiPart(part)) {
273
+ const name = part.type.replace(/^data-/, "");
274
+ if (name.length > 0) {
275
+ parts.push({
276
+ type: "data",
277
+ name,
278
+ value: part.data,
279
+ });
280
+ }
281
+ continue;
282
+ }
283
+ if (isToolUiPart(part)) {
284
+ const toolName = getUiToolName(part);
285
+ if (!toolName) {
286
+ continue;
287
+ }
288
+ pushToolParts(parts, toolName, part.toolCallId, part.state, part);
289
+ }
290
+ }
291
+ return parts.filter((part) => messagePartSchema.safeParse(part).success);
292
+ }
293
+ function isToolComplete(part) {
294
+ return part.state === "output-available" || part.state === "output-error" ||
295
+ part.state === "output-denied";
296
+ }
297
+ export function hasIncompleteToolParts(message) {
298
+ return message.parts.some((part) => isToolUiPart(part) && !isToolComplete(part));
299
+ }
300
+ export function markIncompleteToolPartsAsStopped(message) {
301
+ return markIncompleteToolPartsAsErrored(message, "Stopped by user");
302
+ }
303
+ export function markIncompleteToolPartsAsErrored(message, errorText) {
304
+ let mutated = false;
305
+ const parts = message.parts.map((part) => {
306
+ if (!isToolUiPart(part) || isToolComplete(part)) {
307
+ return part;
308
+ }
309
+ mutated = true;
310
+ return markToolPartAsErrored(part, errorText);
311
+ });
312
+ return mutated ? { ...message, parts } : message;
313
+ }
314
+ function markToolPartAsErrored(part, errorText) {
315
+ if (part.type === "dynamic-tool") {
316
+ return {
317
+ type: "dynamic-tool",
318
+ toolName: part.toolName,
319
+ toolCallId: part.toolCallId,
320
+ ...(part.title ? { title: part.title } : {}),
321
+ ...(part.providerExecuted !== undefined ? { providerExecuted: part.providerExecuted } : {}),
322
+ ...(part.callProviderMetadata ? { callProviderMetadata: part.callProviderMetadata } : {}),
323
+ input: part.input,
324
+ state: "output-error",
325
+ errorText,
326
+ };
327
+ }
328
+ return {
329
+ type: part.type,
330
+ toolCallId: part.toolCallId,
331
+ ...(part.toolName ? { toolName: part.toolName } : {}),
332
+ ...(part.title ? { title: part.title } : {}),
333
+ ...(part.providerExecuted !== undefined ? { providerExecuted: part.providerExecuted } : {}),
334
+ ...(part.callProviderMetadata ? { callProviderMetadata: part.callProviderMetadata } : {}),
335
+ input: part.input,
336
+ state: "output-error",
337
+ errorText,
338
+ };
339
+ }
217
340
  export function isToolCallPart(value) {
218
341
  return (isRecord(value) &&
219
342
  value.type === "tool-call" &&
@@ -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.292";
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.292";
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.292",
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.292",
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",
@@ -293,6 +293,157 @@ export function pushToolParts(
293
293
  });
294
294
  }
295
295
 
296
+ function pushFileConversationPart(
297
+ parts: MessagePart[],
298
+ part: Extract<ChatUiMessagePart, { type: "file" }>,
299
+ ): void {
300
+ const uploadId = part.uploadId ?? extractUploadId(part.url);
301
+ if (!uploadId) return;
302
+
303
+ if (part.mediaType.startsWith("image/")) {
304
+ parts.push({
305
+ type: "image",
306
+ upload_id: uploadId,
307
+ media_type: part.mediaType,
308
+ ...(part.url ? { url: part.url } : {}),
309
+ });
310
+ return;
311
+ }
312
+
313
+ parts.push({
314
+ type: "file",
315
+ upload_id: uploadId,
316
+ media_type: part.mediaType,
317
+ ...(part.url ? { url: part.url } : {}),
318
+ });
319
+ }
320
+
321
+ export function toConversationPartsFromUiMessage(message: ChatUiMessage): MessagePart[] {
322
+ const parts: MessagePart[] = [];
323
+
324
+ for (const part of message.parts) {
325
+ if (part.type === "text") {
326
+ parts.push({ type: "text", text: part.text });
327
+ continue;
328
+ }
329
+
330
+ if (part.type === "reasoning") {
331
+ parts.push({ type: "reasoning", text: part.text });
332
+ continue;
333
+ }
334
+
335
+ if (part.type === "step-start") {
336
+ continue;
337
+ }
338
+
339
+ if (part.type === "source-url") {
340
+ parts.push({
341
+ type: "citation",
342
+ source_id: part.sourceId,
343
+ title: part.title,
344
+ url: part.url,
345
+ });
346
+ continue;
347
+ }
348
+
349
+ if (part.type === "source-document") {
350
+ parts.push({
351
+ type: "citation",
352
+ source_id: part.sourceId,
353
+ title: part.title,
354
+ });
355
+ continue;
356
+ }
357
+
358
+ if (part.type === "file") {
359
+ pushFileConversationPart(parts, part);
360
+ continue;
361
+ }
362
+
363
+ if (isDataUiPart(part)) {
364
+ const name = part.type.replace(/^data-/, "");
365
+ if (name.length > 0) {
366
+ parts.push({
367
+ type: "data",
368
+ name,
369
+ value: part.data,
370
+ });
371
+ }
372
+ continue;
373
+ }
374
+
375
+ if (isToolUiPart(part)) {
376
+ const toolName = getUiToolName(part);
377
+ if (!toolName) {
378
+ continue;
379
+ }
380
+
381
+ pushToolParts(parts, toolName, part.toolCallId, part.state, part);
382
+ }
383
+ }
384
+
385
+ return parts.filter((part) => messagePartSchema.safeParse(part).success);
386
+ }
387
+
388
+ function isToolComplete(part: ToolUiPart): boolean {
389
+ return part.state === "output-available" || part.state === "output-error" ||
390
+ part.state === "output-denied";
391
+ }
392
+
393
+ export function hasIncompleteToolParts(message: ChatUiMessage): boolean {
394
+ return message.parts.some((part) => isToolUiPart(part) && !isToolComplete(part));
395
+ }
396
+
397
+ export function markIncompleteToolPartsAsStopped(message: ChatUiMessage): ChatUiMessage {
398
+ return markIncompleteToolPartsAsErrored(message, "Stopped by user");
399
+ }
400
+
401
+ export function markIncompleteToolPartsAsErrored(
402
+ message: ChatUiMessage,
403
+ errorText: string,
404
+ ): ChatUiMessage {
405
+ let mutated = false;
406
+
407
+ const parts = message.parts.map((part) => {
408
+ if (!isToolUiPart(part) || isToolComplete(part)) {
409
+ return part;
410
+ }
411
+
412
+ mutated = true;
413
+ return markToolPartAsErrored(part, errorText);
414
+ });
415
+
416
+ return mutated ? { ...message, parts } : message;
417
+ }
418
+
419
+ function markToolPartAsErrored(part: ToolUiPart, errorText: string): ChatUiMessagePart {
420
+ if (part.type === "dynamic-tool") {
421
+ return {
422
+ type: "dynamic-tool",
423
+ toolName: part.toolName,
424
+ toolCallId: part.toolCallId,
425
+ ...(part.title ? { title: part.title } : {}),
426
+ ...(part.providerExecuted !== undefined ? { providerExecuted: part.providerExecuted } : {}),
427
+ ...(part.callProviderMetadata ? { callProviderMetadata: part.callProviderMetadata } : {}),
428
+ input: part.input,
429
+ state: "output-error",
430
+ errorText,
431
+ };
432
+ }
433
+
434
+ return {
435
+ type: part.type,
436
+ toolCallId: part.toolCallId,
437
+ ...(part.toolName ? { toolName: part.toolName } : {}),
438
+ ...(part.title ? { title: part.title } : {}),
439
+ ...(part.providerExecuted !== undefined ? { providerExecuted: part.providerExecuted } : {}),
440
+ ...(part.callProviderMetadata ? { callProviderMetadata: part.callProviderMetadata } : {}),
441
+ input: part.input,
442
+ state: "output-error",
443
+ errorText,
444
+ };
445
+ }
446
+
296
447
  export function isToolCallPart(value: unknown): value is ToolCallLike {
297
448
  return (
298
449
  isRecord(value) &&
@@ -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.292";
3
+ export const VERSION = "0.1.294";