@dudousxd/nestjs-agent-react 0.7.5 → 0.9.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 +35 -2
- package/dist/index.cjs +451 -179
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +119 -12
- package/dist/index.d.ts +119 -12
- package/dist/index.js +358 -89
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -111,8 +111,8 @@ function Chat() {
|
|
|
111
111
|
| On the instance | What it is |
|
|
112
112
|
|---|---|
|
|
113
113
|
| `items` | The mounted window, oldest first. Each item carries `blocks`, `text`, `usage`, `timestamp`, `isStreaming`, `isLastAssistant`, and its action machines. |
|
|
114
|
-
| `items[i].blocks` | `{ kind: 'text' \| 'reasoning' \| 'tools' \| 'sources' \| 'elicitation' }`. A `tools` block is a run of CONSECUTIVE tool parts — any other part between two calls (including a `step-start` marker) ends the run. A `reasoning` block carries `isOpen`/`toggle`, open while it streams. A `sources` block appears only under `sources: true`, an `elicitation` block only under `onAnswer` — see below. |
|
|
115
|
-
| `items[i].blocks[n]` (`tools`) | Also carries `calls`: the same parts, each with `{ toolCallId, name, isAwaitingApproval, approve, reject, error }`. |
|
|
114
|
+
| `items[i].blocks` | `{ kind: 'text' \| 'reasoning' \| 'tools' \| 'sources' \| 'elicitation' \| 'ui' }`. A `ui` block is a component the server pushed (`{ id, component, props, version }`) — look `component` up in your own registry. A `tools` block is a run of CONSECUTIVE tool parts — any other part between two calls (including a `step-start` marker) ends the run. A `reasoning` block carries `isOpen`/`toggle`, open while it streams. A `sources` block appears only under `sources: true`, an `elicitation` block only under `onAnswer` — see below. |
|
|
115
|
+
| `items[i].blocks[n]` (`tools`) | Also carries `calls`: the same parts, each with `{ toolCallId, name, toolKind, parentId, children, approval, isAwaitingApproval, approve, reject, error }`, and `roots`: the same calls as a tree (a call nested under another by the stream's `parentId` sits in its parent's `children`). `approval` is `{ approver, expiresAt, reason }` when the runner said who has to decide, else `null`. |
|
|
116
116
|
| `items[i].copy` | `{ available, copied, copy() }` — `copied` flashes for `copyResetMs` (default 1500). |
|
|
117
117
|
| `items[i].edit` | `{ available, isEditing, draft, canSave, start(), cancel(), setDraft(), save(), getTextareaProps() }`. The prop-getter focuses with the caret at the end, saves on Enter, cancels on Escape. |
|
|
118
118
|
| `items[i].fork` / `.regenerate` | `{ available, run() }`. Regenerate is offered on the last assistant message only. |
|
|
@@ -324,6 +324,10 @@ function CustomChat({ threadId }: { threadId?: string }) {
|
|
|
324
324
|
onRunSettled: ({ status }) => {
|
|
325
325
|
if (status === 'completed') refetchThreadList();
|
|
326
326
|
},
|
|
327
|
+
// The server named (or renamed) the thread mid-stream — update the header now.
|
|
328
|
+
onTitle: (title) => setHeaderTitle(title),
|
|
329
|
+
// Every data part as it arrives: pushed `data-ui` components, `data-approval-requested`, …
|
|
330
|
+
onData: (part) => analytics.track(part.type),
|
|
327
331
|
});
|
|
328
332
|
|
|
329
333
|
return (
|
|
@@ -381,6 +385,20 @@ const transport = new AgentChatTransport({
|
|
|
381
385
|
const chat = useChat({ transport });
|
|
382
386
|
```
|
|
383
387
|
|
|
388
|
+
Beyond text, reasoning and tool calls, the transport maps the rest of the stream vocabulary to AI SDK
|
|
389
|
+
data parts, which `useChat`'s `onData` (and `useAgentChat({ onData })`) sees as they arrive:
|
|
390
|
+
|
|
391
|
+
| Stream frame | Becomes |
|
|
392
|
+
|---|---|
|
|
393
|
+
| `ui` | a `data-ui` part keyed by the component id (a repeat id updates it in place) |
|
|
394
|
+
| `approval-requested` | a `data-approval-requested` part keyed by the call id, plus the SDK's native approval request — the tool part moves to `state: 'approval-requested'` |
|
|
395
|
+
| `title` / `cancelled` | transient `data-title` / `data-cancelled` (never stored on the message); `useAgentChat({ onTitle })` |
|
|
396
|
+
| a kind this version does not know | a `data-<kind>` part — forwarded, never dropped |
|
|
397
|
+
|
|
398
|
+
`parentId` on a tool frame rides the part's `toolMetadata` next to `toolKind`. The full wire
|
|
399
|
+
contract — for a backend that serves these routes without this library's loop — is
|
|
400
|
+
[docs/stream-protocol.md](../../docs/stream-protocol.md).
|
|
401
|
+
|
|
384
402
|
### Loading persisted history
|
|
385
403
|
|
|
386
404
|
A reloaded thread's `StoredMessage[]` (from `AgentClient.getThread`) needs converting to `UIMessage[]`
|
|
@@ -399,6 +417,8 @@ const initialMessages = storedThreadToUiMessages(detail.messages);
|
|
|
399
417
|
calls persists as "thinking…" + tool calls, then a separate final-answer row) into ONE `UIMessage` per
|
|
400
418
|
conversational turn, matching how the live stream renders — and stamps `metadata.usage` on any turn it
|
|
401
419
|
merged. For a single already-atomic row, `storedMessageToUiMessage` maps it 1:1 with no merging.
|
|
420
|
+
Persisted reasoning comes back as a `reasoning` part before the text (with its duration), and
|
|
421
|
+
persisted pushed components as `data-ui` parts, so a reloaded thread shows what the live one did.
|
|
402
422
|
|
|
403
423
|
### Attachments and the raw client
|
|
404
424
|
|
|
@@ -434,6 +454,19 @@ Reasoning frames arrive as `reasoning` parts on the message (the transport maps
|
|
|
434
454
|
each run behind a disclosure toggle — open while it streams, folded once the answer lands — with
|
|
435
455
|
`renderReasoning` and `reasoningLabel` slots to override the body and the label.
|
|
436
456
|
|
|
457
|
+
Thinking is timed and persisted: the backend reports each step's `reasoningMs` on `step-finish`, the
|
|
458
|
+
transport stamps it on the reasoning part, and the stored message keeps it, so a reasoning block's
|
|
459
|
+
`durationMs` reads the same live and after a reload. `useElapsed(running)` is the headless ticker
|
|
460
|
+
for while it still streams, and `formatElapsed(ms)` the label:
|
|
461
|
+
|
|
462
|
+
```tsx
|
|
463
|
+
function ThoughtFor({ block }: { block: TranscriptReasoningBlock }) {
|
|
464
|
+
const elapsed = useElapsed(block.isStreaming);
|
|
465
|
+
const ms = block.isStreaming ? elapsed : block.durationMs;
|
|
466
|
+
return ms === null ? null : <span>Thought for {formatElapsed(ms)}</span>;
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
437
470
|
`ChatInput` surfaces cancel next to send:
|
|
438
471
|
|
|
439
472
|
```tsx
|