@dudousxd/nestjs-agent-react 0.16.0 → 0.18.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 +60 -6
- package/dist/index.cjs +642 -230
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +178 -2
- package/dist/index.d.ts +178 -2
- package/dist/index.js +596 -192
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -592,6 +592,23 @@ override with `sendMessage(msg, { body: { model } })`; `chat.setThreadModel(id)`
|
|
|
592
592
|
the thread (`null` unpins), so every later turn without its own runs on it. The server refuses a
|
|
593
593
|
model its catalog does not offer as available.
|
|
594
594
|
|
|
595
|
+
### Quota
|
|
596
|
+
|
|
597
|
+
```tsx
|
|
598
|
+
import { QuotaBlockedError, useQuota } from '@dudousxd/nestjs-agent-react';
|
|
599
|
+
|
|
600
|
+
const quota = useQuota({ backend }); // GET <base>/quota
|
|
601
|
+
const chat = useAgentChat({ backend, blocked: quota.blocked });
|
|
602
|
+
|
|
603
|
+
<meter value={quota.month?.usedUsd} max={quota.month?.limitUsd} />
|
|
604
|
+
{quota.blocked ? <p>{quota.blocked.reason}</p> : null}
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
`useQuota` returns every window (`day`, `month`, …) with its usage and ceilings, and `blocked` when
|
|
608
|
+
one is exhausted; it re-reads after every run a chat on the same backend settles (`pollMs` to poll
|
|
609
|
+
as well). With `blocked` passed in, `sendMessage`/`regenerate` reject with `QuotaBlockedError`
|
|
610
|
+
instead of starting a turn the server would refuse with `429`.
|
|
611
|
+
|
|
595
612
|
### The transport, standalone
|
|
596
613
|
|
|
597
614
|
`AgentChatTransport` is a plain AI SDK v7 `ChatTransport` — wire it straight into `useChat` for the SSE
|
|
@@ -645,15 +662,52 @@ merged. For a single already-atomic row, `storedMessageToUiMessage` maps it 1:1
|
|
|
645
662
|
Persisted reasoning comes back as a `reasoning` part before the text (with its duration), and
|
|
646
663
|
persisted pushed components as `data-ui` parts, so a reloaded thread shows what the live one did.
|
|
647
664
|
|
|
648
|
-
### Attachments
|
|
665
|
+
### Attachments
|
|
649
666
|
|
|
650
|
-
`
|
|
651
|
-
file
|
|
667
|
+
`useAttachments` is the composer's file tray without the tray: validation, one upload per file
|
|
668
|
+
with progress and cancel, retry, image previews, and the handlers for a file input, a drop zone and
|
|
669
|
+
paste.
|
|
652
670
|
|
|
653
|
-
```
|
|
654
|
-
|
|
655
|
-
await chat.sendMessage({ text: 'what is in this?' }, { body: { attachments: [attachment] } });
|
|
671
|
+
```tsx
|
|
672
|
+
import { messageFiles, useAttachments } from '@dudousxd/nestjs-agent-react';
|
|
656
673
|
|
|
674
|
+
const files = useAttachments({
|
|
675
|
+
backend: chat.backend, // or `upload: (file, { signal, onProgress }) => myUpload(file)`
|
|
676
|
+
accept: 'image/*,.pdf',
|
|
677
|
+
maxBytes: 20 * 1024 * 1024,
|
|
678
|
+
maxFiles: 5,
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
<div {...files.dropZoneProps} data-dragging={files.isDragging}>
|
|
682
|
+
<textarea onPaste={files.onPaste} />
|
|
683
|
+
<input {...files.inputProps} hidden ref={pickerRef} />
|
|
684
|
+
{files.items.map((item) => (
|
|
685
|
+
<span key={item.id} data-status={item.status}>
|
|
686
|
+
{item.previewUrl ? <img src={item.previewUrl} alt="" /> : item.name}
|
|
687
|
+
{item.status === 'uploading' ? ` ${Math.round(item.progress * 100)}%` : null}
|
|
688
|
+
{item.error}
|
|
689
|
+
<button onClick={() => files.remove(item.id)}>Remove</button>
|
|
690
|
+
</span>
|
|
691
|
+
))}
|
|
692
|
+
</div>
|
|
693
|
+
|
|
694
|
+
<button
|
|
695
|
+
disabled={files.isUploading}
|
|
696
|
+
onClick={async () => {
|
|
697
|
+
await chat.sendMessage({ text }, { body: { attachments: files.refs } });
|
|
698
|
+
files.clear();
|
|
699
|
+
}}
|
|
700
|
+
/>
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
An item is `uploading`, `ready`, `error` (retry with `files.retry(id)`) or `rejected` (failed
|
|
704
|
+
`accept`/`maxBytes`/`maxFiles` and never uploaded; `error` says why). `remove` cancels an upload in
|
|
705
|
+
flight. `messageFiles(message)` reads the files back off any message — live or replayed — with a
|
|
706
|
+
`kind` (`image`, `pdf`, `text`, …), the extension and, for replayed ones, the stored `mediaId`.
|
|
707
|
+
|
|
708
|
+
The rest of `AgentClient` works outside `useAgentChat` too — e.g. a standalone approvals inbox:
|
|
709
|
+
|
|
710
|
+
```ts
|
|
657
711
|
// Human-in-the-loop, callable from any component — not just the chat screen that raised it:
|
|
658
712
|
await chat.approve({ toolCallId });
|
|
659
713
|
await chat.reject({ toolCallId, reason: 'not now' });
|