@dudousxd/nestjs-agent-react 0.27.0 → 0.29.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/README.md +55 -2
- package/dist/{client-DNM5Qm5N.d.cts → client-DhHEJi7c.d.cts} +19 -1
- package/dist/{client-DNM5Qm5N.d.ts → client-DhHEJi7c.d.ts} +19 -1
- package/dist/{generative-ui-jT9TYfCi.d.cts → generative-ui-VTZ1EADD.d.cts} +12 -0
- package/dist/{generative-ui-jT9TYfCi.d.ts → generative-ui-VTZ1EADD.d.ts} +12 -0
- package/dist/genui-json-render.cjs +202 -370
- package/dist/genui-json-render.cjs.map +1 -1
- package/dist/genui-json-render.d.cts +1 -1
- package/dist/genui-json-render.d.ts +1 -1
- package/dist/genui-json-render.js +209 -373
- package/dist/genui-json-render.js.map +1 -1
- package/dist/genui.cjs +178 -320
- package/dist/genui.cjs.map +1 -1
- package/dist/genui.d.cts +2 -2
- package/dist/genui.d.ts +2 -2
- package/dist/genui.js +185 -323
- package/dist/genui.js.map +1 -1
- package/dist/index.cjs +2044 -2729
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +123 -12
- package/dist/index.d.ts +123 -12
- package/dist/index.js +2067 -2737
- package/dist/index.js.map +1 -1
- package/dist/markdown.cjs +23 -36
- package/dist/markdown.cjs.map +1 -1
- package/dist/markdown.js +23 -28
- package/dist/markdown.js.map +1 -1
- package/dist/media.cjs +46 -79
- package/dist/media.cjs.map +1 -1
- package/dist/media.d.cts +1 -1
- package/dist/media.d.ts +1 -1
- package/dist/media.js +46 -81
- package/dist/media.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -37,8 +37,8 @@ handlers passed. On top of the AI SDK chat it returns:
|
|
|
37
37
|
| On `chat` | What it is |
|
|
38
38
|
|---|---|
|
|
39
39
|
| `transcript` | `useChatTranscript` already bound to the chat — approve/reject/answer/skip, stop, fork, regenerate, the tool catalog, and timestamps/usage read from message metadata. Override any of it with `useAgentChat({ transcript: { … } })`. |
|
|
40
|
-
| `composer` | `{ text, setText, files, canSend, blockedBy, submit() }` — `files` is `useAttachments` on the chat's backend; `submit()` sends the draft with the ready files attached and clears both — while a turn runs it QUEUES it (see *Typing ahead*); `blockedBy` is `'empty' \| 'busy' \| 'uploading' \| 'quota'` (`'busy'` only with `whileRunning: 'block'`). |
|
|
41
|
-
| `queue` | `{ items, paused, isSupported, add(text, { attachments?, mode? }), remove(id), edit(id, text), move(id, index), clear(), resume(), error }` — messages sent mid-turn, waiting server-side for the running turn to settle. |
|
|
40
|
+
| `composer` | `{ text, setText, files, canSend, blockedBy, submit() }` — `files` is `useAttachments` on the chat's backend; `submit()` sends the draft with the ready files attached and clears both — while a turn runs it QUEUES it (see *Typing ahead*), and `submit({ mode: 'interrupt' \| 'queue' })` picks what happens mid-turn for that one send; `blockedBy` is `'empty' \| 'busy' \| 'uploading' \| 'quota'` (`'busy'` only with `whileRunning: 'block'`). |
|
|
41
|
+
| `queue` | `{ items, paused, isSupported, add(text, { attachments?, mode? }), remove(id), interrupt(id), edit(id, text), move(id, index), clear(), resume(), error }` — messages sent mid-turn, waiting server-side for the running turn to settle. |
|
|
42
42
|
| `models` | `{ list, providers, selected, pinned, locked, select(id), pinToThread(id) }` — loaded the first time `list` is read. |
|
|
43
43
|
| `quota` / `blocked` | `useQuota`'s state, and the window blocking sends (the `blocked` option overrides it). |
|
|
44
44
|
| `approve` / `reject` / `answer` / `skip` | `({ toolCallId, … })` — the same object shape the transcript's handlers take. |
|
|
@@ -305,6 +305,46 @@ A refused settlement (403 "not your thread" or "not your approval", 410 "expired
|
|
|
305
305
|
`call.error` with the affordance still live, rather than escaping as an unhandled rejection. Render
|
|
306
306
|
it — a button that silently does nothing is indistinguishable from a broken one.
|
|
307
307
|
|
|
308
|
+
### When a run fails
|
|
309
|
+
|
|
310
|
+
The server closes a failed run's stream with `event: error` + `{ code, message }`. `chat.error`
|
|
311
|
+
carries the message; `chat.runError` carries the whole frame — `{ code, message, runId? }`, `null`
|
|
312
|
+
again once the next attempt starts — so the app words each failure itself. The library renders
|
|
313
|
+
nothing for it:
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
import { isRunNotActiveError } from '@dudousxd/nestjs-agent-react';
|
|
317
|
+
|
|
318
|
+
const FRIENDLY: Record<string, string> = {
|
|
319
|
+
replay_diverged: 'This answer was interrupted by an update. Send your message again.',
|
|
320
|
+
model_no_output: 'The model returned nothing. Try again.',
|
|
321
|
+
run_failed: 'Something went wrong on our side. Try again.',
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
{chat.runError && <p role="alert">{FRIENDLY[chat.runError.code ?? ''] ?? chat.runError.message}</p>}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
`AGENT_RUN_ERROR_CODES` lists the codes this library's loop sends (`quota_exceeded`,
|
|
328
|
+
`output_rejected`, `structured_output_invalid`, `replay_diverged`, `model_no_output`, `run_failed`).
|
|
329
|
+
In production the `message` of the last three is one generic sentence — the error itself stays in
|
|
330
|
+
the server's log.
|
|
331
|
+
|
|
332
|
+
A failed turn leaves its thread usable: the next send starts a new turn. What it cannot do is
|
|
333
|
+
answer a card the dead turn left on screen. `approve` / `reject` / `answer` / `skip` on one reject
|
|
334
|
+
with an `AgentHttpError` whose `status` is `409` and `code` is `run_not_active`:
|
|
335
|
+
|
|
336
|
+
```tsx
|
|
337
|
+
try {
|
|
338
|
+
await chat.approve({ toolCallId });
|
|
339
|
+
} catch (error) {
|
|
340
|
+
if (isRunNotActiveError(error)) showStale('This request expired with its turn — send it again.');
|
|
341
|
+
else throw error;
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
On the transcript model the same refusal is `call.errorCode === 'run_not_active'` (and
|
|
346
|
+
`elicitation.errorCode`) next to `call.error`, the server's message.
|
|
347
|
+
|
|
308
348
|
### Completing as you type
|
|
309
349
|
|
|
310
350
|
`useComposerAutocomplete` is the state machine behind a `/`-style menu in the composer. It is
|
|
@@ -607,8 +647,21 @@ const chat = useAgentChat({ threadId });
|
|
|
607
647
|
- `useAgentChat({ whileRunning })`: `'queue'` (default), `'interrupt'` (cancel the running turn and
|
|
608
648
|
run this next), or `'block'` (refuse, `composer.blockedBy === 'busy'` — the old behaviour, also
|
|
609
649
|
what a backend without `enqueueMessage` gets).
|
|
650
|
+
- One send can answer differently from the chat's `whileRunning`: `composer.submit({ mode })` and
|
|
651
|
+
`sendMessage(message, { mode })` take `'queue'` or `'interrupt'` — a "send now" button next to a
|
|
652
|
+
plain send that queues. The composer clears its own draft and files either way; with nothing
|
|
653
|
+
running, `mode` means nothing and the message is simply sent. It also lifts `'block'` for that
|
|
654
|
+
send.
|
|
610
655
|
- `chat.queue.edit(id, text)`, `move(id, index)`, `remove(id)`, `clear()` change what is waiting;
|
|
611
656
|
`add(text, { attachments, mode })` queues from your own code.
|
|
657
|
+
- `chat.queue.interrupt(id)` runs a message that is already waiting NOW: it moves to the head as an
|
|
658
|
+
interrupt and the running turn is cancelled for it, in one server call (the message keeps its id
|
|
659
|
+
and never leaves the queue — do not `remove` and `add` it again). With nothing running it starts
|
|
660
|
+
at once.
|
|
661
|
+
- A waiting message's files have the shape a sent message's do: `chat.queue.items[n].files` is
|
|
662
|
+
`MessageFile[]` — what `messageFiles(message)` gives — and `chat.transcript.queued[n].files` is the
|
|
663
|
+
same plus `isImage`, so one file renderer draws both. `attachmentFile(attachment)` makes one from
|
|
664
|
+
an uploaded `MessageAttachment`.
|
|
612
665
|
- The queue pauses behind a failed turn (`run_failed`), a Stop (`cancelled`) or an exhausted quota
|
|
613
666
|
(`quota_exceeded`); `chat.queue.paused` says which, `resume()` lifts it. A queue left waiting with
|
|
614
667
|
nothing running is started when the thread loads.
|
|
@@ -168,6 +168,16 @@ interface AgentBackend {
|
|
|
168
168
|
updateQueuedMessage?(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState>;
|
|
169
169
|
/** `DELETE <base>/queue/:messageId`. */
|
|
170
170
|
removeQueuedMessage?(messageId: string): Promise<ChatQueueState>;
|
|
171
|
+
/**
|
|
172
|
+
* `POST <base>/queue/:messageId/interrupt` — run a waiting message now: it moves to the head as an
|
|
173
|
+
* interrupt and the running turn is cancelled for it. `interrupting` is the run that was
|
|
174
|
+
* cancelled; `runId` is set instead when nothing was running and the message started at once.
|
|
175
|
+
* What `chat.queue.interrupt(id)` calls.
|
|
176
|
+
*/
|
|
177
|
+
interruptQueuedMessage?(messageId: string): Promise<ChatQueueState & {
|
|
178
|
+
runId?: string;
|
|
179
|
+
interrupting?: string;
|
|
180
|
+
}>;
|
|
171
181
|
/** `DELETE <base>/threads/:id/queue`. */
|
|
172
182
|
clearQueue?(threadId: string): Promise<ChatQueueState>;
|
|
173
183
|
/** `POST <base>/threads/:id/queue/resume` — `runId` when the head started. */
|
|
@@ -313,6 +323,14 @@ declare class AgentClient implements AgentBackend {
|
|
|
313
323
|
updateQueuedMessage(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState>;
|
|
314
324
|
/** `DELETE <path>/queue/:messageId`. */
|
|
315
325
|
removeQueuedMessage(messageId: string): Promise<ChatQueueState>;
|
|
326
|
+
/**
|
|
327
|
+
* `POST <path>/queue/:messageId/interrupt` — run a waiting message now, cancelling the running
|
|
328
|
+
* turn for it. `runId` when nothing was running and it started; else `interrupting`.
|
|
329
|
+
*/
|
|
330
|
+
interruptQueuedMessage(messageId: string): Promise<ChatQueueState & {
|
|
331
|
+
runId?: string;
|
|
332
|
+
interrupting?: string;
|
|
333
|
+
}>;
|
|
316
334
|
/** `DELETE <path>/threads/:id/queue` — drop every waiting message. */
|
|
317
335
|
clearQueue(threadId: string): Promise<ChatQueueState>;
|
|
318
336
|
/** `POST <path>/threads/:id/queue/resume` — lift a pause; `runId` when the head started. */
|
|
@@ -418,4 +436,4 @@ declare class AgentClient implements AgentBackend {
|
|
|
418
436
|
private handleResponse;
|
|
419
437
|
}
|
|
420
438
|
|
|
421
|
-
export { type
|
|
439
|
+
export { type AgentRequestError as A, type CancelResult as C, type ErrorAnswer as E, type HttpErrorListener as H, type MessageFeedbackInput as M, type QueuedMessageUpdate as Q, type ResumeStreamRequest as R, type ThreadPatch as T, type UploadAttachmentOptions as U, type AgentBackend as a, type AttachmentUploadStrategy as b, AgentBackendUnsupportedError as c, AgentClient as d, type AgentClientOptions as e, type AgentConnection as f, AgentHttpError as g, type ChatStreamRequest as h, type ChatStreamResponse as i, type QueuedSendResult as j, requireBackendMethod as r };
|
|
@@ -168,6 +168,16 @@ interface AgentBackend {
|
|
|
168
168
|
updateQueuedMessage?(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState>;
|
|
169
169
|
/** `DELETE <base>/queue/:messageId`. */
|
|
170
170
|
removeQueuedMessage?(messageId: string): Promise<ChatQueueState>;
|
|
171
|
+
/**
|
|
172
|
+
* `POST <base>/queue/:messageId/interrupt` — run a waiting message now: it moves to the head as an
|
|
173
|
+
* interrupt and the running turn is cancelled for it. `interrupting` is the run that was
|
|
174
|
+
* cancelled; `runId` is set instead when nothing was running and the message started at once.
|
|
175
|
+
* What `chat.queue.interrupt(id)` calls.
|
|
176
|
+
*/
|
|
177
|
+
interruptQueuedMessage?(messageId: string): Promise<ChatQueueState & {
|
|
178
|
+
runId?: string;
|
|
179
|
+
interrupting?: string;
|
|
180
|
+
}>;
|
|
171
181
|
/** `DELETE <base>/threads/:id/queue`. */
|
|
172
182
|
clearQueue?(threadId: string): Promise<ChatQueueState>;
|
|
173
183
|
/** `POST <base>/threads/:id/queue/resume` — `runId` when the head started. */
|
|
@@ -313,6 +323,14 @@ declare class AgentClient implements AgentBackend {
|
|
|
313
323
|
updateQueuedMessage(messageId: string, update: QueuedMessageUpdate): Promise<ChatQueueState>;
|
|
314
324
|
/** `DELETE <path>/queue/:messageId`. */
|
|
315
325
|
removeQueuedMessage(messageId: string): Promise<ChatQueueState>;
|
|
326
|
+
/**
|
|
327
|
+
* `POST <path>/queue/:messageId/interrupt` — run a waiting message now, cancelling the running
|
|
328
|
+
* turn for it. `runId` when nothing was running and it started; else `interrupting`.
|
|
329
|
+
*/
|
|
330
|
+
interruptQueuedMessage(messageId: string): Promise<ChatQueueState & {
|
|
331
|
+
runId?: string;
|
|
332
|
+
interrupting?: string;
|
|
333
|
+
}>;
|
|
316
334
|
/** `DELETE <path>/threads/:id/queue` — drop every waiting message. */
|
|
317
335
|
clearQueue(threadId: string): Promise<ChatQueueState>;
|
|
318
336
|
/** `POST <path>/threads/:id/queue/resume` — lift a pause; `runId` when the head started. */
|
|
@@ -418,4 +436,4 @@ declare class AgentClient implements AgentBackend {
|
|
|
418
436
|
private handleResponse;
|
|
419
437
|
}
|
|
420
438
|
|
|
421
|
-
export { type
|
|
439
|
+
export { type AgentRequestError as A, type CancelResult as C, type ErrorAnswer as E, type HttpErrorListener as H, type MessageFeedbackInput as M, type QueuedMessageUpdate as Q, type ResumeStreamRequest as R, type ThreadPatch as T, type UploadAttachmentOptions as U, type AgentBackend as a, type AttachmentUploadStrategy as b, AgentBackendUnsupportedError as c, AgentClient as d, type AgentClientOptions as e, type AgentConnection as f, AgentHttpError as g, type ChatStreamRequest as h, type ChatStreamResponse as i, type QueuedSendResult as j, requireBackendMethod as r };
|
|
@@ -329,6 +329,12 @@ interface TranscriptToolCall {
|
|
|
329
329
|
reject: TranscriptSettleState;
|
|
330
330
|
/** A failed decision — the call is still parked, so the affordance stays live. */
|
|
331
331
|
error: string | null;
|
|
332
|
+
/**
|
|
333
|
+
* The server's machine-readable reason for {@link error}, when it gave one. `run_not_active`
|
|
334
|
+
* means the turn that asked has ended: nothing is waiting for the decision, and pressing again
|
|
335
|
+
* will be refused again — word it yourself and let the person send the message again.
|
|
336
|
+
*/
|
|
337
|
+
errorCode: string | null;
|
|
332
338
|
}
|
|
333
339
|
/**
|
|
334
340
|
* A run of CONSECUTIVE tool parts, grouped so a UI can collapse "5 tools ran" into one affordance.
|
|
@@ -452,6 +458,8 @@ interface TranscriptElicitationBlock {
|
|
|
452
458
|
outcome: TranscriptElicitationOutcome | null;
|
|
453
459
|
/** A failed submission — the run is still parked, so the form stays live. */
|
|
454
460
|
error: string | null;
|
|
461
|
+
/** The server's machine-readable reason for {@link error} (`run_not_active`, …), when it gave one. */
|
|
462
|
+
errorCode: string | null;
|
|
455
463
|
answer: TranscriptSettleState;
|
|
456
464
|
skip: TranscriptSettleState;
|
|
457
465
|
}
|
|
@@ -501,6 +509,8 @@ interface ElicitationBlockOptions {
|
|
|
501
509
|
/** Which decision this call is sending, or `null` for none. */
|
|
502
510
|
submitting: (toolCallId: string) => SettleAction | null;
|
|
503
511
|
errorOf: (toolCallId: string) => string | null;
|
|
512
|
+
/** The `code` of the error `errorOf` reports, when the server sent one. */
|
|
513
|
+
errorCodeOf?: (toolCallId: string) => string | null;
|
|
504
514
|
}
|
|
505
515
|
/** Where an approval decision is sent, and what the last one did. */
|
|
506
516
|
interface ApprovalBlockOptions {
|
|
@@ -511,6 +521,8 @@ interface ApprovalBlockOptions {
|
|
|
511
521
|
/** Which decision this call is sending, or `null` for none. */
|
|
512
522
|
submitting: (toolCallId: string) => SettleAction | null;
|
|
513
523
|
errorOf: (toolCallId: string) => string | null;
|
|
524
|
+
/** The `code` of the error `errorOf` reports, when the server sent one. */
|
|
525
|
+
errorCodeOf?: (toolCallId: string) => string | null;
|
|
514
526
|
}
|
|
515
527
|
interface BuildBlocksOptions {
|
|
516
528
|
/** Disclosure lookup for a reasoning run; `isStreaming` is the fallback when untouched. */
|
|
@@ -329,6 +329,12 @@ interface TranscriptToolCall {
|
|
|
329
329
|
reject: TranscriptSettleState;
|
|
330
330
|
/** A failed decision — the call is still parked, so the affordance stays live. */
|
|
331
331
|
error: string | null;
|
|
332
|
+
/**
|
|
333
|
+
* The server's machine-readable reason for {@link error}, when it gave one. `run_not_active`
|
|
334
|
+
* means the turn that asked has ended: nothing is waiting for the decision, and pressing again
|
|
335
|
+
* will be refused again — word it yourself and let the person send the message again.
|
|
336
|
+
*/
|
|
337
|
+
errorCode: string | null;
|
|
332
338
|
}
|
|
333
339
|
/**
|
|
334
340
|
* A run of CONSECUTIVE tool parts, grouped so a UI can collapse "5 tools ran" into one affordance.
|
|
@@ -452,6 +458,8 @@ interface TranscriptElicitationBlock {
|
|
|
452
458
|
outcome: TranscriptElicitationOutcome | null;
|
|
453
459
|
/** A failed submission — the run is still parked, so the form stays live. */
|
|
454
460
|
error: string | null;
|
|
461
|
+
/** The server's machine-readable reason for {@link error} (`run_not_active`, …), when it gave one. */
|
|
462
|
+
errorCode: string | null;
|
|
455
463
|
answer: TranscriptSettleState;
|
|
456
464
|
skip: TranscriptSettleState;
|
|
457
465
|
}
|
|
@@ -501,6 +509,8 @@ interface ElicitationBlockOptions {
|
|
|
501
509
|
/** Which decision this call is sending, or `null` for none. */
|
|
502
510
|
submitting: (toolCallId: string) => SettleAction | null;
|
|
503
511
|
errorOf: (toolCallId: string) => string | null;
|
|
512
|
+
/** The `code` of the error `errorOf` reports, when the server sent one. */
|
|
513
|
+
errorCodeOf?: (toolCallId: string) => string | null;
|
|
504
514
|
}
|
|
505
515
|
/** Where an approval decision is sent, and what the last one did. */
|
|
506
516
|
interface ApprovalBlockOptions {
|
|
@@ -511,6 +521,8 @@ interface ApprovalBlockOptions {
|
|
|
511
521
|
/** Which decision this call is sending, or `null` for none. */
|
|
512
522
|
submitting: (toolCallId: string) => SettleAction | null;
|
|
513
523
|
errorOf: (toolCallId: string) => string | null;
|
|
524
|
+
/** The `code` of the error `errorOf` reports, when the server sent one. */
|
|
525
|
+
errorCodeOf?: (toolCallId: string) => string | null;
|
|
514
526
|
}
|
|
515
527
|
interface BuildBlocksOptions {
|
|
516
528
|
/** Disclosure lookup for a reasoning run; `isStreaming` is the fallback when untouched. */
|