@deuz-sdk/react 2.1.0 → 2.3.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,11 +1,23 @@
1
1
  import { Message, ToolApprovalRequest, Usage, FinishReason, ToolApprovalResponse, ImagePart, DeepPartial } from '@deuz-sdk/core';
2
2
  export { Message, ToolApprovalRequest, ToolApprovalResponse } from '@deuz-sdk/core';
3
- import { UIMessage, ChatHistory, UIToolCall, AssistantTurnState, ChatInput } from '@deuz-sdk/core/chat';
3
+ import { AssistantTurnState, UIMessage, ChatHistory, UIToolCall, ChatInput } from '@deuz-sdk/core/chat';
4
4
  export { AssistantTurnState, ChatHistory, ChatInput, UIMessage, UIMessagePart, UIToolCall } from '@deuz-sdk/core/chat';
5
5
  import * as react from 'react';
6
6
  import { ReactNode } from 'react';
7
7
  export { DeuzUIPart } from '@deuz-sdk/core/ui';
8
8
 
9
+ /**
10
+ * The native agent run a turn carries (2.3): core's `DeuzAgentState`, read off
11
+ * `AssistantTurnState.agent`. Derived rather than imported, so these types
12
+ * still compile against a core older than 2.3 (where it is `unknown`).
13
+ */
14
+ type UseChatAgent = AssistantTurnState extends {
15
+ agent?: infer A;
16
+ } ? Exclude<A, undefined> : unknown;
17
+ /** The provider's explanation of a stop (2.3): core's `StopDetails`, derived like `UseChatAgent`. */
18
+ type UseChatStopDetails = AssistantTurnState extends {
19
+ stopDetails?: infer S;
20
+ } ? Exclude<S, undefined> : unknown;
9
21
  /**
10
22
  * Picked files → canonical parts for a {@link ChatInput}. A thin, null-tolerant
11
23
  * wrapper over core's `filesToImageParts`: the bytes work (Web APIs only, no
@@ -71,10 +83,21 @@ interface UseChatResumeOptions {
71
83
  * whose resume endpoint answers 404 (nothing in flight) would otherwise paint
72
84
  * a permanent error. A caught-up endpoint (immediate `[DONE]`) is a silent
73
85
  * no-op — no bubble, no state change. Call `reconnect()` yourself when you
74
- * want the failure surfaced.
86
+ * want the failure surfaced. Only the READ is silent: when the replayed turn
87
+ * continues the chat (2.3 — `onToolCall` answered its client calls), that
88
+ * POST to `api` reports a failure like any other.
75
89
  */
76
90
  auto?: boolean;
77
- /** Cursor persistence adapter (see {@link UseChatCursorStore}). */
91
+ /**
92
+ * Cursor persistence adapter (see {@link UseChatCursorStore}). Only reads
93
+ * through `endpoint` save the cursor, so it marks how far the RESUME reads
94
+ * got. (Since 2.3 a POST response that carries the journal's `id:` lines
95
+ * moves the hook's in-memory cursor too, so a `reconnect()` within the same
96
+ * mounted hook resumes after what the POST read delivered; it is not saved
97
+ * here, because a reload mid-turn must replay that turn from its start.
98
+ * `setHistory` drops that in-memory cursor, so a chat switch never sends
99
+ * one chat's cursor to another chat's endpoint.)
100
+ */
78
101
  cursor?: UseChatCursorStore;
79
102
  }
80
103
  interface UseChatOptions {
@@ -116,11 +139,23 @@ interface UseChatOptions {
116
139
  /**
117
140
  * Client-tool executor: called for every streamed tool call the SERVER did
118
141
  * not execute. The return value is appended as its tool_result and the chat
119
- * auto-continues; a throw self-heals as an is_error result.
142
+ * auto-continues; a throw self-heals as an is_error result. A result that
143
+ * lands after the chat moved on (a new message, a regenerate, a replaced
144
+ * history) is dropped (2.3).
120
145
  *
121
146
  * OMIT it to drive client tools from outside the hook instead: the
122
147
  * round-trip PARKS, the calls appear in `pendingToolCalls`, and
123
148
  * `addToolResult` answers them.
149
+ *
150
+ * Since 2.3 a turn read back through `reconnect()` / `resume.auto` reaches
151
+ * this the same way. A replayed call is dispatched AT MOST ONCE per mounted
152
+ * hook: not when the canonical history already holds its result, and not
153
+ * while it is parked or still running. Across a reload that evidence is the
154
+ * history the app restored — a call whose result was not persisted before
155
+ * the page went away runs again, so make such tools idempotent, or omit
156
+ * `onToolCall` and confirm parked calls yourself. A tab that only WATCHES a
157
+ * stream another tab drives should omit it too, or it would run that tab's
158
+ * calls.
124
159
  */
125
160
  onToolCall?: (call: {
126
161
  toolCallId: string;
@@ -160,11 +195,15 @@ interface UseChatResult {
160
195
  history: ChatHistory;
161
196
  status: 'idle' | 'streaming' | 'error';
162
197
  error: Error | undefined;
163
- /** Gated tool calls awaiting verdicts — the chat is PAUSED while non-empty. */
198
+ /**
199
+ * Gated tool calls awaiting verdicts — the chat is PAUSED while non-empty.
200
+ * One entry per request: a repeated wire frame does not add a second card.
201
+ */
164
202
  pendingApprovals: ToolApprovalRequest[];
165
203
  /**
166
204
  * Client tool calls the round-trip is PARKED on (no `onToolCall` executor).
167
205
  * Answer each with `addToolResult`; the chat continues once all are answered.
206
+ * A turn read back through `reconnect()` parks its calls here too (2.3).
168
207
  */
169
208
  pendingToolCalls: UIToolCall[];
170
209
  /** Live cumulative cost from the wire's `cost` parts (last one wins). */
@@ -217,6 +256,22 @@ interface UseChatResult {
217
256
  usage?: Usage;
218
257
  /** Terminal finish reason (1.9) — `'length'` means the answer was truncated. */
219
258
  finishReason?: FinishReason;
259
+ /**
260
+ * The provider's explanation of this turn's stop (2.3), from the wire's
261
+ * `finish`: with `finishReason: 'content_filter'`, a refusal's `category`
262
+ * and `explanation`. Absent when the provider explained nothing.
263
+ */
264
+ stopDetails?: UseChatStopDetails;
265
+ /**
266
+ * The native agent run behind this turn (2.3), on a route that serves
267
+ * `toDeuzAgentStreamResponse`: its `runId`, `status` (`'running'`,
268
+ * `'suspended'`, `'completed'`, `'stopped'`, `'failed'`), the latest `partial`
269
+ * draft while it runs, and — only once `completed` — the `output` the server
270
+ * validated. Absent on a chat route. Pending approvals and client calls of a
271
+ * suspended run also appear in `pendingApprovals` / `pendingToolCalls`, and
272
+ * the hook resumes the run with them.
273
+ */
274
+ agent?: UseChatAgent;
220
275
  /**
221
276
  * Send one user turn: plain text (1.8-identical, including the canonical
222
277
  * `content` string) or text plus canonical parts — images/PDFs from
@@ -236,7 +291,9 @@ interface UseChatResult {
236
291
  * system prompt and provider round-trip data that the UI view cannot carry.
237
292
  *
238
293
  * Pending gates (approvals, parked client tool calls) are DROPPED: they were
239
- * anchored to the transcript you just replaced.
294
+ * anchored to the transcript you just replaced. So is the in-memory resume
295
+ * cursor (2.3), which addresses that transcript's stream: the next
296
+ * `reconnect()` reads from the persisted cursor or from the start.
240
297
  */
241
298
  setHistory: (update: ChatHistory | ((prev: ChatHistory) => ChatHistory)) => void;
242
299
  /**
@@ -263,13 +320,32 @@ interface UseChatResult {
263
320
  clearError: () => void;
264
321
  /**
265
322
  * Record one verdict (the request's signed `token` is auto-preserved). Once
266
- * EVERY pending approval has a verdict, the chat auto-resumes with
323
+ * EVERY pending approval has a verdict, the chat auto-resumes ONCE with
267
324
  * `approvalResponses` in the request body.
325
+ *
326
+ * The verdict must answer an approval in `pendingApprovals`: its
327
+ * `approvalId`, and — when the verdict carries a `token` — that request's
328
+ * token, which binds it to the run that issued it. ANYTHING ELSE IS A NO-OP
329
+ * (2.3): no request, no state change, and the promise resolves — the same
330
+ * contract as `addToolResult`. That covers a verdict with nothing pending, a
331
+ * repeat of one already sent (a double click), a card left over from an
332
+ * earlier turn or a replaced transcript, and another run's verdict. Before
333
+ * the last verdict lands, answering an approval again replaces its verdict.
268
334
  */
269
335
  addToolApprovalResponse: (response: ToolApprovalResponse) => Promise<void>;
270
336
  /**
271
337
  * Re-read the stream from `resume.endpoint` via `connectDeuzStream` and fold
272
338
  * the parts into the current turn. No-op unless `options.resume` is set.
339
+ *
340
+ * The read turn settles exactly like a streamed one (2.3): its approvals
341
+ * pause the chat, its unresolved client calls reach `onToolCall` (and the
342
+ * chat continues with a POST) or `pendingToolCalls`, and a call the replay
343
+ * re-delivers after this client answered it is not dispatched again. A
344
+ * `stop()` during the read settles nothing; the next call continues it.
345
+ *
346
+ * Since 2.3 a POST read whose response carries the journal's event ids
347
+ * moves the cursor too, so a reconnect after a settled turn resumes after
348
+ * it and appends nothing the hook already holds.
273
349
  */
274
350
  reconnect: () => Promise<void>;
275
351
  }
@@ -330,4 +406,4 @@ interface CostBadgeProps {
330
406
  /** Live cost readout: `$X.XXXX`, plus ` (saved $Y.YYYY)` when caching saved money. */
331
407
  declare function CostBadge({ cost, format }: CostBadgeProps): react.JSX.Element | null;
332
408
 
333
- export { CostBadge, type CostBadgeProps, ToolApprovalCard, type ToolApprovalCardProps, type UseChatBudgetExceeded, type UseChatCost, type UseChatCursorStore, type UseChatOptions, type UseChatResult, type UseChatResumeOptions, type UseObjectOptions, type UseObjectResult, partsFromFiles, useChat, useObject };
409
+ export { CostBadge, type CostBadgeProps, ToolApprovalCard, type ToolApprovalCardProps, type UseChatAgent, type UseChatBudgetExceeded, type UseChatCost, type UseChatCursorStore, type UseChatOptions, type UseChatResult, type UseChatResumeOptions, type UseChatStopDetails, type UseObjectOptions, type UseObjectResult, partsFromFiles, useChat, useObject };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,23 @@
1
1
  import { Message, ToolApprovalRequest, Usage, FinishReason, ToolApprovalResponse, ImagePart, DeepPartial } from '@deuz-sdk/core';
2
2
  export { Message, ToolApprovalRequest, ToolApprovalResponse } from '@deuz-sdk/core';
3
- import { UIMessage, ChatHistory, UIToolCall, AssistantTurnState, ChatInput } from '@deuz-sdk/core/chat';
3
+ import { AssistantTurnState, UIMessage, ChatHistory, UIToolCall, ChatInput } from '@deuz-sdk/core/chat';
4
4
  export { AssistantTurnState, ChatHistory, ChatInput, UIMessage, UIMessagePart, UIToolCall } from '@deuz-sdk/core/chat';
5
5
  import * as react from 'react';
6
6
  import { ReactNode } from 'react';
7
7
  export { DeuzUIPart } from '@deuz-sdk/core/ui';
8
8
 
9
+ /**
10
+ * The native agent run a turn carries (2.3): core's `DeuzAgentState`, read off
11
+ * `AssistantTurnState.agent`. Derived rather than imported, so these types
12
+ * still compile against a core older than 2.3 (where it is `unknown`).
13
+ */
14
+ type UseChatAgent = AssistantTurnState extends {
15
+ agent?: infer A;
16
+ } ? Exclude<A, undefined> : unknown;
17
+ /** The provider's explanation of a stop (2.3): core's `StopDetails`, derived like `UseChatAgent`. */
18
+ type UseChatStopDetails = AssistantTurnState extends {
19
+ stopDetails?: infer S;
20
+ } ? Exclude<S, undefined> : unknown;
9
21
  /**
10
22
  * Picked files → canonical parts for a {@link ChatInput}. A thin, null-tolerant
11
23
  * wrapper over core's `filesToImageParts`: the bytes work (Web APIs only, no
@@ -71,10 +83,21 @@ interface UseChatResumeOptions {
71
83
  * whose resume endpoint answers 404 (nothing in flight) would otherwise paint
72
84
  * a permanent error. A caught-up endpoint (immediate `[DONE]`) is a silent
73
85
  * no-op — no bubble, no state change. Call `reconnect()` yourself when you
74
- * want the failure surfaced.
86
+ * want the failure surfaced. Only the READ is silent: when the replayed turn
87
+ * continues the chat (2.3 — `onToolCall` answered its client calls), that
88
+ * POST to `api` reports a failure like any other.
75
89
  */
76
90
  auto?: boolean;
77
- /** Cursor persistence adapter (see {@link UseChatCursorStore}). */
91
+ /**
92
+ * Cursor persistence adapter (see {@link UseChatCursorStore}). Only reads
93
+ * through `endpoint` save the cursor, so it marks how far the RESUME reads
94
+ * got. (Since 2.3 a POST response that carries the journal's `id:` lines
95
+ * moves the hook's in-memory cursor too, so a `reconnect()` within the same
96
+ * mounted hook resumes after what the POST read delivered; it is not saved
97
+ * here, because a reload mid-turn must replay that turn from its start.
98
+ * `setHistory` drops that in-memory cursor, so a chat switch never sends
99
+ * one chat's cursor to another chat's endpoint.)
100
+ */
78
101
  cursor?: UseChatCursorStore;
79
102
  }
80
103
  interface UseChatOptions {
@@ -116,11 +139,23 @@ interface UseChatOptions {
116
139
  /**
117
140
  * Client-tool executor: called for every streamed tool call the SERVER did
118
141
  * not execute. The return value is appended as its tool_result and the chat
119
- * auto-continues; a throw self-heals as an is_error result.
142
+ * auto-continues; a throw self-heals as an is_error result. A result that
143
+ * lands after the chat moved on (a new message, a regenerate, a replaced
144
+ * history) is dropped (2.3).
120
145
  *
121
146
  * OMIT it to drive client tools from outside the hook instead: the
122
147
  * round-trip PARKS, the calls appear in `pendingToolCalls`, and
123
148
  * `addToolResult` answers them.
149
+ *
150
+ * Since 2.3 a turn read back through `reconnect()` / `resume.auto` reaches
151
+ * this the same way. A replayed call is dispatched AT MOST ONCE per mounted
152
+ * hook: not when the canonical history already holds its result, and not
153
+ * while it is parked or still running. Across a reload that evidence is the
154
+ * history the app restored — a call whose result was not persisted before
155
+ * the page went away runs again, so make such tools idempotent, or omit
156
+ * `onToolCall` and confirm parked calls yourself. A tab that only WATCHES a
157
+ * stream another tab drives should omit it too, or it would run that tab's
158
+ * calls.
124
159
  */
125
160
  onToolCall?: (call: {
126
161
  toolCallId: string;
@@ -160,11 +195,15 @@ interface UseChatResult {
160
195
  history: ChatHistory;
161
196
  status: 'idle' | 'streaming' | 'error';
162
197
  error: Error | undefined;
163
- /** Gated tool calls awaiting verdicts — the chat is PAUSED while non-empty. */
198
+ /**
199
+ * Gated tool calls awaiting verdicts — the chat is PAUSED while non-empty.
200
+ * One entry per request: a repeated wire frame does not add a second card.
201
+ */
164
202
  pendingApprovals: ToolApprovalRequest[];
165
203
  /**
166
204
  * Client tool calls the round-trip is PARKED on (no `onToolCall` executor).
167
205
  * Answer each with `addToolResult`; the chat continues once all are answered.
206
+ * A turn read back through `reconnect()` parks its calls here too (2.3).
168
207
  */
169
208
  pendingToolCalls: UIToolCall[];
170
209
  /** Live cumulative cost from the wire's `cost` parts (last one wins). */
@@ -217,6 +256,22 @@ interface UseChatResult {
217
256
  usage?: Usage;
218
257
  /** Terminal finish reason (1.9) — `'length'` means the answer was truncated. */
219
258
  finishReason?: FinishReason;
259
+ /**
260
+ * The provider's explanation of this turn's stop (2.3), from the wire's
261
+ * `finish`: with `finishReason: 'content_filter'`, a refusal's `category`
262
+ * and `explanation`. Absent when the provider explained nothing.
263
+ */
264
+ stopDetails?: UseChatStopDetails;
265
+ /**
266
+ * The native agent run behind this turn (2.3), on a route that serves
267
+ * `toDeuzAgentStreamResponse`: its `runId`, `status` (`'running'`,
268
+ * `'suspended'`, `'completed'`, `'stopped'`, `'failed'`), the latest `partial`
269
+ * draft while it runs, and — only once `completed` — the `output` the server
270
+ * validated. Absent on a chat route. Pending approvals and client calls of a
271
+ * suspended run also appear in `pendingApprovals` / `pendingToolCalls`, and
272
+ * the hook resumes the run with them.
273
+ */
274
+ agent?: UseChatAgent;
220
275
  /**
221
276
  * Send one user turn: plain text (1.8-identical, including the canonical
222
277
  * `content` string) or text plus canonical parts — images/PDFs from
@@ -236,7 +291,9 @@ interface UseChatResult {
236
291
  * system prompt and provider round-trip data that the UI view cannot carry.
237
292
  *
238
293
  * Pending gates (approvals, parked client tool calls) are DROPPED: they were
239
- * anchored to the transcript you just replaced.
294
+ * anchored to the transcript you just replaced. So is the in-memory resume
295
+ * cursor (2.3), which addresses that transcript's stream: the next
296
+ * `reconnect()` reads from the persisted cursor or from the start.
240
297
  */
241
298
  setHistory: (update: ChatHistory | ((prev: ChatHistory) => ChatHistory)) => void;
242
299
  /**
@@ -263,13 +320,32 @@ interface UseChatResult {
263
320
  clearError: () => void;
264
321
  /**
265
322
  * Record one verdict (the request's signed `token` is auto-preserved). Once
266
- * EVERY pending approval has a verdict, the chat auto-resumes with
323
+ * EVERY pending approval has a verdict, the chat auto-resumes ONCE with
267
324
  * `approvalResponses` in the request body.
325
+ *
326
+ * The verdict must answer an approval in `pendingApprovals`: its
327
+ * `approvalId`, and — when the verdict carries a `token` — that request's
328
+ * token, which binds it to the run that issued it. ANYTHING ELSE IS A NO-OP
329
+ * (2.3): no request, no state change, and the promise resolves — the same
330
+ * contract as `addToolResult`. That covers a verdict with nothing pending, a
331
+ * repeat of one already sent (a double click), a card left over from an
332
+ * earlier turn or a replaced transcript, and another run's verdict. Before
333
+ * the last verdict lands, answering an approval again replaces its verdict.
268
334
  */
269
335
  addToolApprovalResponse: (response: ToolApprovalResponse) => Promise<void>;
270
336
  /**
271
337
  * Re-read the stream from `resume.endpoint` via `connectDeuzStream` and fold
272
338
  * the parts into the current turn. No-op unless `options.resume` is set.
339
+ *
340
+ * The read turn settles exactly like a streamed one (2.3): its approvals
341
+ * pause the chat, its unresolved client calls reach `onToolCall` (and the
342
+ * chat continues with a POST) or `pendingToolCalls`, and a call the replay
343
+ * re-delivers after this client answered it is not dispatched again. A
344
+ * `stop()` during the read settles nothing; the next call continues it.
345
+ *
346
+ * Since 2.3 a POST read whose response carries the journal's event ids
347
+ * moves the cursor too, so a reconnect after a settled turn resumes after
348
+ * it and appends nothing the hook already holds.
273
349
  */
274
350
  reconnect: () => Promise<void>;
275
351
  }
@@ -330,4 +406,4 @@ interface CostBadgeProps {
330
406
  /** Live cost readout: `$X.XXXX`, plus ` (saved $Y.YYYY)` when caching saved money. */
331
407
  declare function CostBadge({ cost, format }: CostBadgeProps): react.JSX.Element | null;
332
408
 
333
- export { CostBadge, type CostBadgeProps, ToolApprovalCard, type ToolApprovalCardProps, type UseChatBudgetExceeded, type UseChatCost, type UseChatCursorStore, type UseChatOptions, type UseChatResult, type UseChatResumeOptions, type UseObjectOptions, type UseObjectResult, partsFromFiles, useChat, useObject };
409
+ export { CostBadge, type CostBadgeProps, ToolApprovalCard, type ToolApprovalCardProps, type UseChatAgent, type UseChatBudgetExceeded, type UseChatCost, type UseChatCursorStore, type UseChatOptions, type UseChatResult, type UseChatResumeOptions, type UseChatStopDetails, type UseObjectOptions, type UseObjectResult, partsFromFiles, useChat, useObject };