@dudousxd/nestjs-agent-react 0.4.2 → 0.5.1
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/dist/index.cjs +71 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -1
- package/dist/index.d.ts +90 -1
- package/dist/index.js +70 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -43,6 +43,14 @@ interface AgentChatTransportOptions {
|
|
|
43
43
|
getResumeRunId?: () => string | undefined;
|
|
44
44
|
/** Fires whenever a stream emits its `meta` frame. */
|
|
45
45
|
onMeta?: (meta: AgentStreamMeta) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Fires synchronously at the very start of `sendMessages`/`reconnectToStream`, before any network
|
|
48
|
+
* call — i.e. strictly before that attempt's own `onMeta` (if any) can fire. Lets a caller reset
|
|
49
|
+
* "which run is THIS attempt settling" state without racing React's render/effect timing: a
|
|
50
|
+
* consumer that also read `onMeta` to learn the current run id would otherwise risk misattributing
|
|
51
|
+
* an early failure (no meta ever arrives) to a PRIOR attempt's id.
|
|
52
|
+
*/
|
|
53
|
+
onAttemptStart?: () => void;
|
|
46
54
|
/** Injectable for tests / non-browser runtimes. Defaults to global fetch. */
|
|
47
55
|
fetch?: typeof fetch;
|
|
48
56
|
}
|
|
@@ -190,6 +198,66 @@ declare class AgentClient {
|
|
|
190
198
|
*/
|
|
191
199
|
declare function storedMessageToUiMessage(message: StoredMessage): UIMessage;
|
|
192
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Summed usage/cost across the stored-message rows merged into one turn (see
|
|
203
|
+
* {@link storedThreadToUiMessages}). Mirrors `MessageUsage`, but `costUsd` is always present
|
|
204
|
+
* (never omitted) since it's a computed aggregate, not a single provider report.
|
|
205
|
+
*/
|
|
206
|
+
interface AggregatedTurnUsage {
|
|
207
|
+
inputTokens: number;
|
|
208
|
+
outputTokens: number;
|
|
209
|
+
/**
|
|
210
|
+
* `null` only when EVERY merged row reports a null/absent cost (no pricing store bound, or an
|
|
211
|
+
* unpriced model) — same "unknown, not a real $0" distinction `MessageUsage.costUsd` makes for a
|
|
212
|
+
* single row. A null cost on SOME rows (mixed with priced ones) contributes `0` to the sum
|
|
213
|
+
* instead of poisoning the whole turn's total to `null` — the tokens are still real and summed
|
|
214
|
+
* either way, so only the cost figure would be understated, never wrong in a "$0 turn" sense.
|
|
215
|
+
*/
|
|
216
|
+
costUsd: number | null;
|
|
217
|
+
}
|
|
218
|
+
/** Metadata the grouped `UIMessage` carries on `.metadata.usage` — see {@link AggregatedTurnUsage}. */
|
|
219
|
+
interface StoredTurnMetadata {
|
|
220
|
+
usage: AggregatedTurnUsage;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive
|
|
224
|
+
* assistant rows (no user message between them) into ONE `UIMessage` per turn.
|
|
225
|
+
*
|
|
226
|
+
* Why: the agent loop persists one row per model iteration (see `agent-loop.ts`'s per-step
|
|
227
|
+
* `persist:assistant:${i}`) — a turn with tool calls appends "I'll check that..." + tool calls,
|
|
228
|
+
* then a separate final-answer row. `storedMessageToUiMessage` maps 1:1, so a reloaded thread
|
|
229
|
+
* renders 2-3 assistant bubbles (each with its own cost/tokens footer) for what the LIVE stream
|
|
230
|
+
* renders as one continuous response (one `UIMessage`, stepped internally — see
|
|
231
|
+
* `AgentChatTransport.toChunkStream`'s `start-step`/`finish-step` bracketing). This closes that gap
|
|
232
|
+
* for replayed history.
|
|
233
|
+
*
|
|
234
|
+
* Merge shape: each row is mapped via `storedMessageToUiMessage` (unchanged — same text-then-tool
|
|
235
|
+
* part ordering per row) and the parts are concatenated in row order, so the grouped message's parts
|
|
236
|
+
* read as `[row1 text?, row1 tools?, row2 text?, row2 tools?, ...]` — exactly the sequence the live
|
|
237
|
+
* transport streams for the same turn. The group's `id` is the LAST row's id (the final-answer row —
|
|
238
|
+
* it's the one carrying `followUps`, and what a host keys turn-level actions like "fork" or
|
|
239
|
+
* "regenerate" on). Non-assistant rows (user/system) pass through `storedMessageToUiMessage`
|
|
240
|
+
* unchanged, one row → one message, same as today.
|
|
241
|
+
*
|
|
242
|
+
* A lone assistant row between two user rows (the common case: no tool calls, or already a single
|
|
243
|
+
* iteration) has nothing to merge with, so it comes back byte-for-byte identical to calling
|
|
244
|
+
* `storedMessageToUiMessage` directly — no `metadata` is added for that case either, preserving
|
|
245
|
+
* exact backward compatibility for hosts that read stored usage some other way.
|
|
246
|
+
*
|
|
247
|
+
* Only an ACTUAL merge (2+ rows) attaches `metadata.usage` — the {@link AggregatedTurnUsage} summed
|
|
248
|
+
* across the merged rows' `usage` (rows without a `usage` at all, e.g. an older/test fixture, are
|
|
249
|
+
* skipped rather than treated as zero-and-priced).
|
|
250
|
+
*
|
|
251
|
+
* Deliberately NOT reproduced: the live transport's `{type: 'step-start'}` UI parts (one per model
|
|
252
|
+
* call, emitted by the AI SDK for every `start-step` chunk — see `repro-real-frames.spec.ts` for a
|
|
253
|
+
* captured wire dump). Those are structural brackets `MessageItem`'s `renderParts` never renders
|
|
254
|
+
* (it only special-cases text and tool parts), and `storedMessageToUiMessage` has never emitted them
|
|
255
|
+
* for a single row either — inventing them here would make a merged turn diverge from a same-shaped
|
|
256
|
+
* unmerged one instead of converging on it. "Indistinguishable from the live stream" is scoped to
|
|
257
|
+
* what actually renders: the text/tool-call content in step order, not the step brackets around it.
|
|
258
|
+
*/
|
|
259
|
+
declare function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[];
|
|
260
|
+
|
|
193
261
|
interface UseAgentChatOptions {
|
|
194
262
|
/** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
|
|
195
263
|
baseUrl?: string;
|
|
@@ -237,6 +305,27 @@ interface UseAgentChatOptions {
|
|
|
237
305
|
* even before the consumer navigates.
|
|
238
306
|
*/
|
|
239
307
|
onThreadCreated?: (threadId: string) => void;
|
|
308
|
+
/**
|
|
309
|
+
* Fired exactly once per run when its stream settles — normally (`'completed'`) or via a thrown
|
|
310
|
+
* failure / the backend's `event: error` frame (`'failed'`) — including a RESUMED stream's own
|
|
311
|
+
* completion. By the time this fires, the server has already derived and persisted the thread's
|
|
312
|
+
* title (and the run's terminal state), so it's the signal `onFinish` doesn't give you: `onFinish`
|
|
313
|
+
* only says "a turn rendered," never "the server is done writing" — without this, a host has no
|
|
314
|
+
* reason to refetch the thread/list queries, and the header/sidebar title is stuck on "Untitled".
|
|
315
|
+
*
|
|
316
|
+
* Skipped when the attempt never got far enough to learn a run id (e.g. the initial POST itself
|
|
317
|
+
* failed before any response headers/meta frame arrived) — nothing was created server-side, so
|
|
318
|
+
* there's nothing to refetch.
|
|
319
|
+
*
|
|
320
|
+
* A user-initiated `cancel()`/`stop()` reports `'completed'` here (the AI SDK's own abort signal
|
|
321
|
+
* doesn't set its `isError` flag) — the server-side cancel already recorded its own terminal run
|
|
322
|
+
* state; this callback only reflects whether the CLIENT's stream loop exited with or without an
|
|
323
|
+
* error, not why it stopped.
|
|
324
|
+
*/
|
|
325
|
+
onRunSettled?: (outcome: {
|
|
326
|
+
runId: string;
|
|
327
|
+
status: 'completed' | 'failed';
|
|
328
|
+
}) => void;
|
|
240
329
|
}
|
|
241
330
|
interface AddToolResultArgs {
|
|
242
331
|
tool: string;
|
|
@@ -490,4 +579,4 @@ interface SpeechRecognitionHook {
|
|
|
490
579
|
*/
|
|
491
580
|
declare function useSpeechRecognition({ lang, onFinalTranscript, onInterimTranscript, }: UseSpeechRecognitionOptions): SpeechRecognitionHook;
|
|
492
581
|
|
|
493
|
-
export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AnyToolUIPart, type CancelResult, ChatInput, type ChatInputProps, type ChatStatus, DEFAULT_SPEECH_LANG, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, SPEECH_LANGUAGES, type SpeechLanguage, type SpeechRecognitionHook, type ThreadPatch, type UseAgentChatOptions, type UseSpeechRecognitionOptions, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, storedMessageToUiMessage, useAgentChat, useSpeechRecognition };
|
|
582
|
+
export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type CancelResult, ChatInput, type ChatInputProps, type ChatStatus, DEFAULT_SPEECH_LANG, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, SPEECH_LANGUAGES, type SpeechLanguage, type SpeechRecognitionHook, type StoredTurnMetadata, type ThreadPatch, type UseAgentChatOptions, type UseSpeechRecognitionOptions, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useSpeechRecognition };
|
package/dist/index.d.ts
CHANGED
|
@@ -43,6 +43,14 @@ interface AgentChatTransportOptions {
|
|
|
43
43
|
getResumeRunId?: () => string | undefined;
|
|
44
44
|
/** Fires whenever a stream emits its `meta` frame. */
|
|
45
45
|
onMeta?: (meta: AgentStreamMeta) => void;
|
|
46
|
+
/**
|
|
47
|
+
* Fires synchronously at the very start of `sendMessages`/`reconnectToStream`, before any network
|
|
48
|
+
* call — i.e. strictly before that attempt's own `onMeta` (if any) can fire. Lets a caller reset
|
|
49
|
+
* "which run is THIS attempt settling" state without racing React's render/effect timing: a
|
|
50
|
+
* consumer that also read `onMeta` to learn the current run id would otherwise risk misattributing
|
|
51
|
+
* an early failure (no meta ever arrives) to a PRIOR attempt's id.
|
|
52
|
+
*/
|
|
53
|
+
onAttemptStart?: () => void;
|
|
46
54
|
/** Injectable for tests / non-browser runtimes. Defaults to global fetch. */
|
|
47
55
|
fetch?: typeof fetch;
|
|
48
56
|
}
|
|
@@ -190,6 +198,66 @@ declare class AgentClient {
|
|
|
190
198
|
*/
|
|
191
199
|
declare function storedMessageToUiMessage(message: StoredMessage): UIMessage;
|
|
192
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Summed usage/cost across the stored-message rows merged into one turn (see
|
|
203
|
+
* {@link storedThreadToUiMessages}). Mirrors `MessageUsage`, but `costUsd` is always present
|
|
204
|
+
* (never omitted) since it's a computed aggregate, not a single provider report.
|
|
205
|
+
*/
|
|
206
|
+
interface AggregatedTurnUsage {
|
|
207
|
+
inputTokens: number;
|
|
208
|
+
outputTokens: number;
|
|
209
|
+
/**
|
|
210
|
+
* `null` only when EVERY merged row reports a null/absent cost (no pricing store bound, or an
|
|
211
|
+
* unpriced model) — same "unknown, not a real $0" distinction `MessageUsage.costUsd` makes for a
|
|
212
|
+
* single row. A null cost on SOME rows (mixed with priced ones) contributes `0` to the sum
|
|
213
|
+
* instead of poisoning the whole turn's total to `null` — the tokens are still real and summed
|
|
214
|
+
* either way, so only the cost figure would be understated, never wrong in a "$0 turn" sense.
|
|
215
|
+
*/
|
|
216
|
+
costUsd: number | null;
|
|
217
|
+
}
|
|
218
|
+
/** Metadata the grouped `UIMessage` carries on `.metadata.usage` — see {@link AggregatedTurnUsage}. */
|
|
219
|
+
interface StoredTurnMetadata {
|
|
220
|
+
usage: AggregatedTurnUsage;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Convert a thread's full `StoredMessage[]` history into `UIMessage[]`, merging consecutive
|
|
224
|
+
* assistant rows (no user message between them) into ONE `UIMessage` per turn.
|
|
225
|
+
*
|
|
226
|
+
* Why: the agent loop persists one row per model iteration (see `agent-loop.ts`'s per-step
|
|
227
|
+
* `persist:assistant:${i}`) — a turn with tool calls appends "I'll check that..." + tool calls,
|
|
228
|
+
* then a separate final-answer row. `storedMessageToUiMessage` maps 1:1, so a reloaded thread
|
|
229
|
+
* renders 2-3 assistant bubbles (each with its own cost/tokens footer) for what the LIVE stream
|
|
230
|
+
* renders as one continuous response (one `UIMessage`, stepped internally — see
|
|
231
|
+
* `AgentChatTransport.toChunkStream`'s `start-step`/`finish-step` bracketing). This closes that gap
|
|
232
|
+
* for replayed history.
|
|
233
|
+
*
|
|
234
|
+
* Merge shape: each row is mapped via `storedMessageToUiMessage` (unchanged — same text-then-tool
|
|
235
|
+
* part ordering per row) and the parts are concatenated in row order, so the grouped message's parts
|
|
236
|
+
* read as `[row1 text?, row1 tools?, row2 text?, row2 tools?, ...]` — exactly the sequence the live
|
|
237
|
+
* transport streams for the same turn. The group's `id` is the LAST row's id (the final-answer row —
|
|
238
|
+
* it's the one carrying `followUps`, and what a host keys turn-level actions like "fork" or
|
|
239
|
+
* "regenerate" on). Non-assistant rows (user/system) pass through `storedMessageToUiMessage`
|
|
240
|
+
* unchanged, one row → one message, same as today.
|
|
241
|
+
*
|
|
242
|
+
* A lone assistant row between two user rows (the common case: no tool calls, or already a single
|
|
243
|
+
* iteration) has nothing to merge with, so it comes back byte-for-byte identical to calling
|
|
244
|
+
* `storedMessageToUiMessage` directly — no `metadata` is added for that case either, preserving
|
|
245
|
+
* exact backward compatibility for hosts that read stored usage some other way.
|
|
246
|
+
*
|
|
247
|
+
* Only an ACTUAL merge (2+ rows) attaches `metadata.usage` — the {@link AggregatedTurnUsage} summed
|
|
248
|
+
* across the merged rows' `usage` (rows without a `usage` at all, e.g. an older/test fixture, are
|
|
249
|
+
* skipped rather than treated as zero-and-priced).
|
|
250
|
+
*
|
|
251
|
+
* Deliberately NOT reproduced: the live transport's `{type: 'step-start'}` UI parts (one per model
|
|
252
|
+
* call, emitted by the AI SDK for every `start-step` chunk — see `repro-real-frames.spec.ts` for a
|
|
253
|
+
* captured wire dump). Those are structural brackets `MessageItem`'s `renderParts` never renders
|
|
254
|
+
* (it only special-cases text and tool parts), and `storedMessageToUiMessage` has never emitted them
|
|
255
|
+
* for a single row either — inventing them here would make a merged turn diverge from a same-shaped
|
|
256
|
+
* unmerged one instead of converging on it. "Indistinguishable from the live stream" is scoped to
|
|
257
|
+
* what actually renders: the text/tool-call content in step order, not the step brackets around it.
|
|
258
|
+
*/
|
|
259
|
+
declare function storedThreadToUiMessages(messages: StoredMessage[]): UIMessage[];
|
|
260
|
+
|
|
193
261
|
interface UseAgentChatOptions {
|
|
194
262
|
/** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
|
|
195
263
|
baseUrl?: string;
|
|
@@ -237,6 +305,27 @@ interface UseAgentChatOptions {
|
|
|
237
305
|
* even before the consumer navigates.
|
|
238
306
|
*/
|
|
239
307
|
onThreadCreated?: (threadId: string) => void;
|
|
308
|
+
/**
|
|
309
|
+
* Fired exactly once per run when its stream settles — normally (`'completed'`) or via a thrown
|
|
310
|
+
* failure / the backend's `event: error` frame (`'failed'`) — including a RESUMED stream's own
|
|
311
|
+
* completion. By the time this fires, the server has already derived and persisted the thread's
|
|
312
|
+
* title (and the run's terminal state), so it's the signal `onFinish` doesn't give you: `onFinish`
|
|
313
|
+
* only says "a turn rendered," never "the server is done writing" — without this, a host has no
|
|
314
|
+
* reason to refetch the thread/list queries, and the header/sidebar title is stuck on "Untitled".
|
|
315
|
+
*
|
|
316
|
+
* Skipped when the attempt never got far enough to learn a run id (e.g. the initial POST itself
|
|
317
|
+
* failed before any response headers/meta frame arrived) — nothing was created server-side, so
|
|
318
|
+
* there's nothing to refetch.
|
|
319
|
+
*
|
|
320
|
+
* A user-initiated `cancel()`/`stop()` reports `'completed'` here (the AI SDK's own abort signal
|
|
321
|
+
* doesn't set its `isError` flag) — the server-side cancel already recorded its own terminal run
|
|
322
|
+
* state; this callback only reflects whether the CLIENT's stream loop exited with or without an
|
|
323
|
+
* error, not why it stopped.
|
|
324
|
+
*/
|
|
325
|
+
onRunSettled?: (outcome: {
|
|
326
|
+
runId: string;
|
|
327
|
+
status: 'completed' | 'failed';
|
|
328
|
+
}) => void;
|
|
240
329
|
}
|
|
241
330
|
interface AddToolResultArgs {
|
|
242
331
|
tool: string;
|
|
@@ -490,4 +579,4 @@ interface SpeechRecognitionHook {
|
|
|
490
579
|
*/
|
|
491
580
|
declare function useSpeechRecognition({ lang, onFinalTranscript, onInterimTranscript, }: UseSpeechRecognitionOptions): SpeechRecognitionHook;
|
|
492
581
|
|
|
493
|
-
export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AnyToolUIPart, type CancelResult, ChatInput, type ChatInputProps, type ChatStatus, DEFAULT_SPEECH_LANG, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, SPEECH_LANGUAGES, type SpeechLanguage, type SpeechRecognitionHook, type ThreadPatch, type UseAgentChatOptions, type UseSpeechRecognitionOptions, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, storedMessageToUiMessage, useAgentChat, useSpeechRecognition };
|
|
582
|
+
export { AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentStreamMeta, type AggregatedTurnUsage, type AnyToolUIPart, type CancelResult, ChatInput, type ChatInputProps, type ChatStatus, DEFAULT_SPEECH_LANG, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageList, type MessageListClassNames, type MessageListProps, type MessageUsageInfo, type QuotaToday, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, SPEECH_LANGUAGES, type SpeechLanguage, type SpeechRecognitionHook, type StoredTurnMetadata, type ThreadPatch, type UseAgentChatOptions, type UseSpeechRecognitionOptions, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useSpeechRecognition };
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ var AgentChatTransport = class {
|
|
|
23
23
|
return this.currentThreadId;
|
|
24
24
|
}
|
|
25
25
|
async sendMessages(options) {
|
|
26
|
+
this.options.onAttemptStart?.();
|
|
26
27
|
const lastMessage = options.messages.at(-1);
|
|
27
28
|
const message = lastMessage ? extractText(lastMessage) : "";
|
|
28
29
|
const body = {
|
|
@@ -55,6 +56,7 @@ var AgentChatTransport = class {
|
|
|
55
56
|
return this.toChunkStream(response.body);
|
|
56
57
|
}
|
|
57
58
|
async reconnectToStream(options) {
|
|
59
|
+
this.options.onAttemptStart?.();
|
|
58
60
|
const runId = this.options.getResumeRunId?.();
|
|
59
61
|
if (runId === void 0) return null;
|
|
60
62
|
const response = await this.fetchImpl()(`${this.baseUrl()}/agent/chat/${encodeURIComponent(runId)}/stream`, {
|
|
@@ -564,6 +566,59 @@ function storedMessageToUiMessage(message) {
|
|
|
564
566
|
}
|
|
565
567
|
__name(storedMessageToUiMessage, "storedMessageToUiMessage");
|
|
566
568
|
|
|
569
|
+
// src/stored-thread-to-ui-messages.ts
|
|
570
|
+
function storedThreadToUiMessages(messages) {
|
|
571
|
+
const turns = [];
|
|
572
|
+
for (const message of messages) {
|
|
573
|
+
const currentTurn = turns.at(-1);
|
|
574
|
+
const previousRow = currentTurn?.at(-1);
|
|
575
|
+
if (message.role === "assistant" && previousRow?.role === "assistant" && currentTurn) {
|
|
576
|
+
currentTurn.push(message);
|
|
577
|
+
} else {
|
|
578
|
+
turns.push([
|
|
579
|
+
message
|
|
580
|
+
]);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
return turns.map(mergeTurn);
|
|
584
|
+
}
|
|
585
|
+
__name(storedThreadToUiMessages, "storedThreadToUiMessages");
|
|
586
|
+
function mergeTurn(rows) {
|
|
587
|
+
const lastRow = rows.at(-1);
|
|
588
|
+
if (lastRow === void 0) {
|
|
589
|
+
throw new Error("storedThreadToUiMessages: encountered an empty turn");
|
|
590
|
+
}
|
|
591
|
+
if (rows.length === 1) {
|
|
592
|
+
return storedMessageToUiMessage(lastRow);
|
|
593
|
+
}
|
|
594
|
+
const parts = rows.flatMap((row) => storedMessageToUiMessage(row).parts);
|
|
595
|
+
const usage = sumUsage(rows);
|
|
596
|
+
return {
|
|
597
|
+
id: lastRow.id,
|
|
598
|
+
role: lastRow.role,
|
|
599
|
+
parts,
|
|
600
|
+
...usage !== void 0 ? {
|
|
601
|
+
metadata: {
|
|
602
|
+
usage
|
|
603
|
+
}
|
|
604
|
+
} : {}
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
__name(mergeTurn, "mergeTurn");
|
|
608
|
+
function sumUsage(rows) {
|
|
609
|
+
const usages = rows.map((row) => row.usage).filter((usage) => usage !== void 0);
|
|
610
|
+
if (usages.length === 0) {
|
|
611
|
+
return void 0;
|
|
612
|
+
}
|
|
613
|
+
const allCostsUnknown = usages.every((usage) => usage.costUsd === null || usage.costUsd === void 0);
|
|
614
|
+
return {
|
|
615
|
+
inputTokens: usages.reduce((sum, usage) => sum + usage.inputTokens, 0),
|
|
616
|
+
outputTokens: usages.reduce((sum, usage) => sum + usage.outputTokens, 0),
|
|
617
|
+
costUsd: allCostsUnknown ? null : usages.reduce((sum, usage) => sum + (usage.costUsd ?? 0), 0)
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
__name(sumUsage, "sumUsage");
|
|
621
|
+
|
|
567
622
|
// src/use-agent-chat.ts
|
|
568
623
|
import { useChat } from "@ai-sdk/react";
|
|
569
624
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -573,6 +628,7 @@ function useAgentChat(options) {
|
|
|
573
628
|
const [runId, setRunId] = useState(options.resumeRunId);
|
|
574
629
|
const runIdRef = useRef(runId);
|
|
575
630
|
runIdRef.current = runId;
|
|
631
|
+
const settlingRunIdRef = useRef(void 0);
|
|
576
632
|
const autoResumeRunIdRef = useRef(void 0);
|
|
577
633
|
const [autoResume, setAutoResume] = useState(false);
|
|
578
634
|
const [activeRunId, setActiveRunId] = useState(null);
|
|
@@ -615,6 +671,7 @@ function useAgentChat(options) {
|
|
|
615
671
|
]);
|
|
616
672
|
const transport = useMemo(() => {
|
|
617
673
|
function onMeta(meta) {
|
|
674
|
+
settlingRunIdRef.current = meta.runId;
|
|
618
675
|
setRunId(meta.runId);
|
|
619
676
|
if (latest.current.threadId === void 0 && meta.threadId && createdThreadId.current !== meta.threadId) {
|
|
620
677
|
createdThreadId.current = meta.threadId;
|
|
@@ -655,7 +712,10 @@ function useAgentChat(options) {
|
|
|
655
712
|
};
|
|
656
713
|
}, "getBody"),
|
|
657
714
|
getResumeRunId: /* @__PURE__ */ __name(() => latest.current.resumeRunId ?? autoResumeRunIdRef.current, "getResumeRunId"),
|
|
658
|
-
onMeta
|
|
715
|
+
onMeta,
|
|
716
|
+
onAttemptStart: /* @__PURE__ */ __name(() => {
|
|
717
|
+
settlingRunIdRef.current = void 0;
|
|
718
|
+
}, "onAttemptStart")
|
|
659
719
|
});
|
|
660
720
|
}, []);
|
|
661
721
|
const chat = useChat({
|
|
@@ -667,8 +727,15 @@ function useAgentChat(options) {
|
|
|
667
727
|
...options.initialMessages !== void 0 ? {
|
|
668
728
|
messages: options.initialMessages
|
|
669
729
|
} : {},
|
|
670
|
-
onFinish: /* @__PURE__ */ __name(() => {
|
|
730
|
+
onFinish: /* @__PURE__ */ __name(({ isError }) => {
|
|
671
731
|
latest.current.onFinish?.();
|
|
732
|
+
const settledRunId = settlingRunIdRef.current;
|
|
733
|
+
if (settledRunId !== void 0) {
|
|
734
|
+
latest.current.onRunSettled?.({
|
|
735
|
+
runId: settledRunId,
|
|
736
|
+
status: isError ? "failed" : "completed"
|
|
737
|
+
});
|
|
738
|
+
}
|
|
672
739
|
}, "onFinish")
|
|
673
740
|
});
|
|
674
741
|
const chatRef = useRef(chat);
|
|
@@ -1373,6 +1440,7 @@ export {
|
|
|
1373
1440
|
loadStoredSpeechLang,
|
|
1374
1441
|
persistSpeechLang,
|
|
1375
1442
|
storedMessageToUiMessage,
|
|
1443
|
+
storedThreadToUiMessages,
|
|
1376
1444
|
useAgentChat,
|
|
1377
1445
|
useSpeechRecognition
|
|
1378
1446
|
};
|