@dudousxd/nestjs-agent-react 0.3.2 → 0.4.0

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.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, ToolUIPart, DynamicToolUIPart } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { ThreadSummary, ThreadDetail, QuotaView } from '@dudousxd/nestjs-agent-core';
4
+ import { ThreadSummary, ThreadDetail, MessageAttachment, QuotaView, StoredMessage } from '@dudousxd/nestjs-agent-core';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import React from 'react';
7
7
 
@@ -55,6 +55,13 @@ interface AgentChatTransportOptions {
55
55
  * The backend hydrates prior history from its store, so only the latest
56
56
  * user message text is sent each turn — keeping payloads tiny and
57
57
  * preventing the client from corrupting replayed history.
58
+ *
59
+ * Attachments (image/PDF for a vision-capable model) ride the per-send body:
60
+ * `sendMessage({ text }, { body: { attachments: MessageAttachment[] } })`. They
61
+ * flow to the backend as the turn's `attachments`, get persisted on the user
62
+ * message, and are rendered as native model content parts. Optimistic display of
63
+ * the user's own attachment thumbnails is the consumer's concern (it stages the
64
+ * upload), the same way history rendering reads `StoredMessage.attachments`.
58
65
  */
59
66
  declare class AgentChatTransport implements ChatTransport<UIMessage> {
60
67
  private readonly options;
@@ -73,11 +80,16 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
73
80
  private captureHeaderMeta;
74
81
  private recordMeta;
75
82
  /**
76
- * Parse the backend's SSE byte stream and synthesize a valid v7
77
- * UI-message chunk stream. Recognized backend frames:
78
- * - `event: meta` `data: {"runId","threadId"}` → records identity
79
- * - `data: {"delta":"..."}` → `text-delta`
80
- * - `event: done` `data: {}` → terminates
83
+ * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
84
+ * Recognized frames:
85
+ * - `event: meta` `data: {"runId","threadId"}` → records identity
86
+ * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool)
87
+ * - `event: done` `data: {}` → terminates
88
+ * - `event: error` `data: {code,message}` → error chunk
89
+ *
90
+ * A run is ONE UI message with N steps. Each `step-start`/`step-finish` pair brackets a model
91
+ * call plus its tool execution; text and reasoning open lazily and close at the step boundary, so
92
+ * tool-call cards (input streaming → output) render live between the prose.
81
93
  */
82
94
  private toChunkStream;
83
95
  }
@@ -100,6 +112,15 @@ interface CancelResult {
100
112
  interface OkResult {
101
113
  ok: boolean;
102
114
  }
115
+ /**
116
+ * Partial update accepted by `PATCH /agent/threads/:threadId`. `defaultAgent: null` clears a
117
+ * previously-set default back to the module's own default; omitting it leaves the thread's
118
+ * current default untouched.
119
+ */
120
+ interface ThreadPatch {
121
+ title?: string;
122
+ defaultAgent?: string | null;
123
+ }
103
124
  interface AgentClientOptions {
104
125
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
105
126
  baseUrl?: string;
@@ -124,6 +145,14 @@ declare class AgentClient {
124
145
  deleteThread(id: string): Promise<void>;
125
146
  forkFromMessage(threadId: string, messageId: string): Promise<ThreadSummary>;
126
147
  renameThread(id: string, title: string): Promise<OkResult>;
148
+ /** General `PATCH /agent/threads/:threadId` — title and/or the thread's pinned default agent. */
149
+ updateThread(id: string, patch: ThreadPatch): Promise<OkResult>;
150
+ /**
151
+ * Uploads a file (image/PDF) for a vision-capable model turn. Multipart, field name `file` —
152
+ * mirrors the backend's `POST /agent/attachments`. The returned {@link MessageAttachment} is
153
+ * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
154
+ */
155
+ uploadAttachment(file: File): Promise<MessageAttachment>;
127
156
  promoteThread(id: string): Promise<OkResult>;
128
157
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
129
158
  getQuotaToday(): Promise<QuotaToday>;
@@ -136,8 +165,31 @@ declare class AgentClient {
136
165
  reason?: string;
137
166
  }): Promise<void>;
138
167
  private request;
168
+ private handleResponse;
139
169
  }
140
170
 
171
+ /**
172
+ * Convert a persisted `StoredMessage` (the agent-lib's on-disk shape) into an AI SDK v7
173
+ * `UIMessage` so a loaded thread can seed `useChat`'s `initialMessages` / `messages`.
174
+ *
175
+ * The lib stores a message as flat `content` text plus `toolCalls`/`toolResults` arrays; the SDK
176
+ * renders from `parts`. This maps:
177
+ * - `content` → a single `text` part (skipped when empty).
178
+ * - each `attachment` → a `file` part (image/PDF) so the user bubble re-renders its
179
+ * thumbnails on a reloaded thread.
180
+ * - each `toolCall` → a `tool-<name>` part, pairing its `toolResult` (matched by id):
181
+ * - a result found → `output-available` state, carrying `output`.
182
+ * - no result found → `input-available` state (the call never finished, e.g. the run was
183
+ * interrupted) — `output` is omitted, never a fabricated value.
184
+ * When the store reports the tool's kind (`'read' | 'action'`), it rides along as
185
+ * `toolMetadata.toolKind` so a UI can render an approval affordance for `action` tools
186
+ * without hardcoding tool-name sets, matching how live-streamed tool parts carry it.
187
+ *
188
+ * Live streaming still arrives as fully-typed SDK tool parts (see `AgentChatTransport`); this
189
+ * converter only feeds replayed history, so the tool cards render the same either way.
190
+ */
191
+ declare function storedMessageToUiMessage(message: StoredMessage): UIMessage;
192
+
141
193
  interface UseAgentChatOptions {
142
194
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
143
195
  baseUrl?: string;
@@ -161,12 +213,30 @@ interface UseAgentChatOptions {
161
213
  * Run id of a buffered stream to reconnect to on mount — wire this to the thread's
162
214
  * `activeStreamId`. Its presence both gates the SDK's `resume` and names the run, so a normal
163
215
  * mount (no id) never fires a doomed resume GET. Omitted → no resume.
216
+ *
217
+ * For the common case (no id in hand yet), prefer {@link UseAgentChatOptions.resume} — it does
218
+ * this fetch-and-wire for you.
164
219
  */
165
220
  resumeRunId?: string;
221
+ /**
222
+ * When `true` and the hook (re)mounts with a `threadId`, the hook fetches the thread and, if its
223
+ * `activeRunId` is non-null (a turn was still streaming when the page loaded/reloaded), attaches
224
+ * to that run's `GET /agent/chat/:runId/stream` automatically — the in-flight turn streams into
225
+ * this session's message state exactly as if the send had happened here. A no-op when `threadId`
226
+ * is omitted (nothing to resume) or the fetched thread has no active run. Default `false`.
227
+ */
228
+ resume?: boolean;
166
229
  /** Read at every send to capture a page snapshot for the page-assistant. */
167
230
  getPageContext?: () => Record<string, unknown> | null;
168
231
  /** Fired after each streamed turn finishes (e.g. to refetch the sidebar). */
169
232
  onFinish?: () => void;
233
+ /**
234
+ * Fired once when a threadless chat's first send makes the backend create a thread — carries the
235
+ * new id so the consumer can sync its URL/router. Not fired when `threadId` was supplied. The hook
236
+ * ALSO remembers the id internally, so every subsequent send reuses it (no new thread per message)
237
+ * even before the consumer navigates.
238
+ */
239
+ onThreadCreated?: (threadId: string) => void;
170
240
  }
171
241
  interface AddToolResultArgs {
172
242
  tool: string;
@@ -182,6 +252,8 @@ interface AddToolResultArgs {
182
252
  declare function useAgentChat(options: UseAgentChatOptions): {
183
253
  addToolResult: ({ tool, toolCallId, output }: AddToolResultArgs) => void | PromiseLike<void>;
184
254
  runId: string | undefined;
255
+ /** The `resume`-fetched thread's active run id, or `null` once resolved with none. */
256
+ activeRunId: string | null;
185
257
  client: AgentClient;
186
258
  threads: ThreadSummary[];
187
259
  loadThreads: () => Promise<ThreadSummary[]>;
@@ -210,7 +282,7 @@ declare function useAgentChat(options: UseAgentChatOptions): {
210
282
  status: ai.ChatStatus;
211
283
  sendMessage: (message?: (Omit<UIMessage<unknown, ai.UIDataTypes, ai.UITools>, "id" | "role"> & {
212
284
  id?: string;
213
- role?: "system" | "user" | "assistant";
285
+ role?: "user" | "assistant" | "system";
214
286
  } & {
215
287
  text?: never;
216
288
  files?: never;
@@ -418,4 +490,4 @@ interface SpeechRecognitionHook {
418
490
  */
419
491
  declare function useSpeechRecognition({ lang, onFinalTranscript, onInterimTranscript, }: UseSpeechRecognitionOptions): SpeechRecognitionHook;
420
492
 
421
- 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 UseAgentChatOptions, type UseSpeechRecognitionOptions, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, useAgentChat, useSpeechRecognition };
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 };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, ToolUIPart, DynamicToolUIPart } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { ThreadSummary, ThreadDetail, QuotaView } from '@dudousxd/nestjs-agent-core';
4
+ import { ThreadSummary, ThreadDetail, MessageAttachment, QuotaView, StoredMessage } from '@dudousxd/nestjs-agent-core';
5
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
6
6
  import React from 'react';
7
7
 
@@ -55,6 +55,13 @@ interface AgentChatTransportOptions {
55
55
  * The backend hydrates prior history from its store, so only the latest
56
56
  * user message text is sent each turn — keeping payloads tiny and
57
57
  * preventing the client from corrupting replayed history.
58
+ *
59
+ * Attachments (image/PDF for a vision-capable model) ride the per-send body:
60
+ * `sendMessage({ text }, { body: { attachments: MessageAttachment[] } })`. They
61
+ * flow to the backend as the turn's `attachments`, get persisted on the user
62
+ * message, and are rendered as native model content parts. Optimistic display of
63
+ * the user's own attachment thumbnails is the consumer's concern (it stages the
64
+ * upload), the same way history rendering reads `StoredMessage.attachments`.
58
65
  */
59
66
  declare class AgentChatTransport implements ChatTransport<UIMessage> {
60
67
  private readonly options;
@@ -73,11 +80,16 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
73
80
  private captureHeaderMeta;
74
81
  private recordMeta;
75
82
  /**
76
- * Parse the backend's SSE byte stream and synthesize a valid v7
77
- * UI-message chunk stream. Recognized backend frames:
78
- * - `event: meta` `data: {"runId","threadId"}` → records identity
79
- * - `data: {"delta":"..."}` → `text-delta`
80
- * - `event: done` `data: {}` → terminates
83
+ * Parse the backend's SSE byte stream and re-emit it as a valid v7 UI-message chunk stream.
84
+ * Recognized frames:
85
+ * - `event: meta` `data: {"runId","threadId"}` → records identity
86
+ * - `data: <AgentStreamEvent JSON>` → mapped to UI chunks (text / reasoning / tool)
87
+ * - `event: done` `data: {}` → terminates
88
+ * - `event: error` `data: {code,message}` → error chunk
89
+ *
90
+ * A run is ONE UI message with N steps. Each `step-start`/`step-finish` pair brackets a model
91
+ * call plus its tool execution; text and reasoning open lazily and close at the step boundary, so
92
+ * tool-call cards (input streaming → output) render live between the prose.
81
93
  */
82
94
  private toChunkStream;
83
95
  }
@@ -100,6 +112,15 @@ interface CancelResult {
100
112
  interface OkResult {
101
113
  ok: boolean;
102
114
  }
115
+ /**
116
+ * Partial update accepted by `PATCH /agent/threads/:threadId`. `defaultAgent: null` clears a
117
+ * previously-set default back to the module's own default; omitting it leaves the thread's
118
+ * current default untouched.
119
+ */
120
+ interface ThreadPatch {
121
+ title?: string;
122
+ defaultAgent?: string | null;
123
+ }
103
124
  interface AgentClientOptions {
104
125
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
105
126
  baseUrl?: string;
@@ -124,6 +145,14 @@ declare class AgentClient {
124
145
  deleteThread(id: string): Promise<void>;
125
146
  forkFromMessage(threadId: string, messageId: string): Promise<ThreadSummary>;
126
147
  renameThread(id: string, title: string): Promise<OkResult>;
148
+ /** General `PATCH /agent/threads/:threadId` — title and/or the thread's pinned default agent. */
149
+ updateThread(id: string, patch: ThreadPatch): Promise<OkResult>;
150
+ /**
151
+ * Uploads a file (image/PDF) for a vision-capable model turn. Multipart, field name `file` —
152
+ * mirrors the backend's `POST /agent/attachments`. The returned {@link MessageAttachment} is
153
+ * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
154
+ */
155
+ uploadAttachment(file: File): Promise<MessageAttachment>;
127
156
  promoteThread(id: string): Promise<OkResult>;
128
157
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
129
158
  getQuotaToday(): Promise<QuotaToday>;
@@ -136,8 +165,31 @@ declare class AgentClient {
136
165
  reason?: string;
137
166
  }): Promise<void>;
138
167
  private request;
168
+ private handleResponse;
139
169
  }
140
170
 
171
+ /**
172
+ * Convert a persisted `StoredMessage` (the agent-lib's on-disk shape) into an AI SDK v7
173
+ * `UIMessage` so a loaded thread can seed `useChat`'s `initialMessages` / `messages`.
174
+ *
175
+ * The lib stores a message as flat `content` text plus `toolCalls`/`toolResults` arrays; the SDK
176
+ * renders from `parts`. This maps:
177
+ * - `content` → a single `text` part (skipped when empty).
178
+ * - each `attachment` → a `file` part (image/PDF) so the user bubble re-renders its
179
+ * thumbnails on a reloaded thread.
180
+ * - each `toolCall` → a `tool-<name>` part, pairing its `toolResult` (matched by id):
181
+ * - a result found → `output-available` state, carrying `output`.
182
+ * - no result found → `input-available` state (the call never finished, e.g. the run was
183
+ * interrupted) — `output` is omitted, never a fabricated value.
184
+ * When the store reports the tool's kind (`'read' | 'action'`), it rides along as
185
+ * `toolMetadata.toolKind` so a UI can render an approval affordance for `action` tools
186
+ * without hardcoding tool-name sets, matching how live-streamed tool parts carry it.
187
+ *
188
+ * Live streaming still arrives as fully-typed SDK tool parts (see `AgentChatTransport`); this
189
+ * converter only feeds replayed history, so the tool cards render the same either way.
190
+ */
191
+ declare function storedMessageToUiMessage(message: StoredMessage): UIMessage;
192
+
141
193
  interface UseAgentChatOptions {
142
194
  /** Origin + base path, e.g. `https://api.example.com`. Defaults to `''`. */
143
195
  baseUrl?: string;
@@ -161,12 +213,30 @@ interface UseAgentChatOptions {
161
213
  * Run id of a buffered stream to reconnect to on mount — wire this to the thread's
162
214
  * `activeStreamId`. Its presence both gates the SDK's `resume` and names the run, so a normal
163
215
  * mount (no id) never fires a doomed resume GET. Omitted → no resume.
216
+ *
217
+ * For the common case (no id in hand yet), prefer {@link UseAgentChatOptions.resume} — it does
218
+ * this fetch-and-wire for you.
164
219
  */
165
220
  resumeRunId?: string;
221
+ /**
222
+ * When `true` and the hook (re)mounts with a `threadId`, the hook fetches the thread and, if its
223
+ * `activeRunId` is non-null (a turn was still streaming when the page loaded/reloaded), attaches
224
+ * to that run's `GET /agent/chat/:runId/stream` automatically — the in-flight turn streams into
225
+ * this session's message state exactly as if the send had happened here. A no-op when `threadId`
226
+ * is omitted (nothing to resume) or the fetched thread has no active run. Default `false`.
227
+ */
228
+ resume?: boolean;
166
229
  /** Read at every send to capture a page snapshot for the page-assistant. */
167
230
  getPageContext?: () => Record<string, unknown> | null;
168
231
  /** Fired after each streamed turn finishes (e.g. to refetch the sidebar). */
169
232
  onFinish?: () => void;
233
+ /**
234
+ * Fired once when a threadless chat's first send makes the backend create a thread — carries the
235
+ * new id so the consumer can sync its URL/router. Not fired when `threadId` was supplied. The hook
236
+ * ALSO remembers the id internally, so every subsequent send reuses it (no new thread per message)
237
+ * even before the consumer navigates.
238
+ */
239
+ onThreadCreated?: (threadId: string) => void;
170
240
  }
171
241
  interface AddToolResultArgs {
172
242
  tool: string;
@@ -182,6 +252,8 @@ interface AddToolResultArgs {
182
252
  declare function useAgentChat(options: UseAgentChatOptions): {
183
253
  addToolResult: ({ tool, toolCallId, output }: AddToolResultArgs) => void | PromiseLike<void>;
184
254
  runId: string | undefined;
255
+ /** The `resume`-fetched thread's active run id, or `null` once resolved with none. */
256
+ activeRunId: string | null;
185
257
  client: AgentClient;
186
258
  threads: ThreadSummary[];
187
259
  loadThreads: () => Promise<ThreadSummary[]>;
@@ -210,7 +282,7 @@ declare function useAgentChat(options: UseAgentChatOptions): {
210
282
  status: ai.ChatStatus;
211
283
  sendMessage: (message?: (Omit<UIMessage<unknown, ai.UIDataTypes, ai.UITools>, "id" | "role"> & {
212
284
  id?: string;
213
- role?: "system" | "user" | "assistant";
285
+ role?: "user" | "assistant" | "system";
214
286
  } & {
215
287
  text?: never;
216
288
  files?: never;
@@ -418,4 +490,4 @@ interface SpeechRecognitionHook {
418
490
  */
419
491
  declare function useSpeechRecognition({ lang, onFinalTranscript, onInterimTranscript, }: UseSpeechRecognitionOptions): SpeechRecognitionHook;
420
492
 
421
- 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 UseAgentChatOptions, type UseSpeechRecognitionOptions, formatRelativeTime, loadStoredSpeechLang, persistSpeechLang, useAgentChat, useSpeechRecognition };
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 };