@dudousxd/nestjs-agent-react 0.10.0 → 0.12.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 +38 -4
- package/dist/index.cjs +327 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -10
- package/dist/index.d.ts +118 -10
- package/dist/index.js +299 -37
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -112,7 +112,7 @@ function Chat() {
|
|
|
112
112
|
|---|---|
|
|
113
113
|
| `items` | The mounted window, oldest first. Each item carries `blocks`, `text`, `usage`, `timestamp`, `isStreaming`, `isLastAssistant`, and its action machines. |
|
|
114
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`. |
|
|
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, status, remember, decidedBy, decidedVia, decisionReason }` when the runner said who has to decide, else `null` — `status` is `pending` / `approved` / `rejected` / `expired`. |
|
|
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. |
|
|
@@ -186,12 +186,32 @@ const transcript = useChatTranscript({
|
|
|
186
186
|
});
|
|
187
187
|
|
|
188
188
|
// block.kind === 'elicitation' →
|
|
189
|
-
// { toolCallId, preamble, questionCount, isPending, outcome, error,
|
|
190
|
-
// questions: [{ id, prompt, position, multiple, selected,
|
|
189
|
+
// { toolCallId, preamble, questionCount, isPending, isValid, outcome, error,
|
|
190
|
+
// questions: [{ id, prompt, description, input, position, multiple, selected, value, error,
|
|
191
|
+
// isPristine, setValue(raw),
|
|
191
192
|
// options: [{ value, label, hotkey, isSelected, isDefault, select() }] }],
|
|
192
193
|
// answer: { available, isSubmitting, run() }, skip: { … } }
|
|
193
194
|
```
|
|
194
195
|
|
|
196
|
+
**Typed questions.** A question with `input` asks for a value instead of a pick — `input.type` is
|
|
197
|
+
`text` · `textarea` · `number` · `boolean` · `date` · `email` · `url` · `select` (a pick from
|
|
198
|
+
`options` again), with optional `placeholder`, `required`, `min`, `max` and `pattern`. `options` may
|
|
199
|
+
be empty for one. Render the control from `input.type` and hand whatever it produces to
|
|
200
|
+
`question.setValue(raw)`: it is coerced with `coerceAnswer` to the canonical strings the wire
|
|
201
|
+
carries (numbers as decimals, booleans as `"true"`/`"false"`, dates as `YYYY-MM-DD`). `question.error`
|
|
202
|
+
is the server's own verdict on the current selection (`validateAnswer`), and `block.isValid` is all
|
|
203
|
+
of them — the answer route answers `400` with the same message for anything it would refuse.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
{q.input?.type === 'number' ? (
|
|
207
|
+
<input type="number" value={q.value} placeholder={q.input.placeholder}
|
|
208
|
+
min={q.input.min} max={q.input.max} onChange={(e) => q.setValue(e.target.value)} />
|
|
209
|
+
) : q.input?.type === 'boolean' ? (
|
|
210
|
+
<input type="checkbox" checked={q.value === 'true'} onChange={(e) => q.setValue(e.target.checked)} />
|
|
211
|
+
) : null}
|
|
212
|
+
{q.error && !q.isPristine ? <small role="alert">{q.error}</small> : null}
|
|
213
|
+
```
|
|
214
|
+
|
|
195
215
|
Every option the agent pre-picked comes back as `isDefault` and starts `isSelected`, so confirming
|
|
196
216
|
is enough. `answer.run()` submits **only the questions the user touched** — the rest are omitted on
|
|
197
217
|
purpose, so the server applies the same defaults it showed and the settled row still records which
|
|
@@ -223,7 +243,20 @@ An `action` tool's input lands and its output never follows on its own — the l
|
|
|
223
243
|
between the two — so a call stuck at `input-available` IS the pending approval. A question set parks
|
|
224
244
|
the same way and is deliberately excluded: approving one settles nothing.
|
|
225
245
|
|
|
226
|
-
|
|
246
|
+
`call.approve.run({ remember: true })` approves this tool for the rest of the thread (the server
|
|
247
|
+
stops asking); `call.approval` says who has to decide and, once settled, who did and through what.
|
|
248
|
+
For a request with an expiry, `useApprovalCountdown(call.approval?.expiresAt)` ticks the time left
|
|
249
|
+
(`{ remainingMs, isExpired }`, headless — pair it with `formatElapsed`):
|
|
250
|
+
|
|
251
|
+
```tsx
|
|
252
|
+
function ApprovalDeadline({ expiresAt }: { expiresAt: string | null }) {
|
|
253
|
+
const { remainingMs, isExpired } = useApprovalCountdown(expiresAt);
|
|
254
|
+
if (remainingMs === null) return null;
|
|
255
|
+
return <span>{isExpired ? 'Expired' : `${formatElapsed(remainingMs)} left`}</span>;
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
A refused settlement (403 "not your thread" or "not your approval", 410 "expired", a network failure) lands on `block.error` /
|
|
227
260
|
`call.error` with the affordance still live, rather than escaping as an unhandled rejection. Render
|
|
228
261
|
it — a button that silently does nothing is indistinguishable from a broken one.
|
|
229
262
|
|
|
@@ -420,6 +453,7 @@ data parts, which `useChat`'s `onData` (and `useAgentChat({ onData })`) sees as
|
|
|
420
453
|
|---|---|
|
|
421
454
|
| `ui` | a `data-ui` part keyed by the component id (a repeat id updates it in place) |
|
|
422
455
|
| `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'` |
|
|
456
|
+
| `approval-settled` | a `data-approval-settled` part keyed by the call id — who decided, through what, remembered or not; folded into `call.approval` |
|
|
423
457
|
| `title` / `cancelled` | transient `data-title` / `data-cancelled` (never stored on the message); `useAgentChat({ onTitle })` |
|
|
424
458
|
| a kind this version does not know | a `data-<kind>` part — forwarded, never dropped |
|
|
425
459
|
|