@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/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, DataUIPart, UIDataTypes } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { ThreadSummary, ThreadDetail, MessageAttachment, ToolCatalogEntry, SkillCatalogEntry, QuotaView, ModelCatalogView, AgentCatalogEntry, MessageFeedbackValue, MessageFeedback, ModelCatalogEntry, StoredMessage } from '@dudousxd/nestjs-agent-core';
4
+ import { ThreadSummary, ThreadDetail, MessageAttachment, ToolCatalogEntry, SkillCatalogEntry, QuotaView, QuotaReport, ModelCatalogView, AgentCatalogEntry, MessageFeedbackValue, MessageFeedback, ModelCatalogEntry, QuotaWindow, QuotaBlock, StoredMessage } from '@dudousxd/nestjs-agent-core';
5
5
  export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
6
6
  import React__default from 'react';
7
7
  import { a as TranscriptBlock, U as UsageSummary, b as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, c as ToolCatalog, A as ApproveOptions, d as AnyToolUIPart, e as TranscriptFile, T as TranscriptUiBlock } from './model-gHqjNjLJ.cjs';
@@ -106,6 +106,8 @@ interface AgentBackend {
106
106
  listTools?(agent?: string): Promise<ToolCatalogEntry[]>;
107
107
  listSkills?(threadId?: string): Promise<SkillCatalogEntry[]>;
108
108
  getQuotaToday?(): Promise<QuotaView>;
109
+ /** `GET <base>/quota` — every budget window, and which one blocks sends, if any. */
110
+ getQuota?(): Promise<QuotaReport>;
109
111
  /** `GET <base>/models?agent=` — what a model picker offers. */
110
112
  listModels?(agent?: string): Promise<ModelCatalogView>;
111
113
  /** `GET <base>/agents` — what an agent picker offers. */
@@ -292,6 +294,138 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
292
294
  private toChunkStream;
293
295
  }
294
296
 
297
+ /** How a renderer is likely to show a file. */
298
+ type MessageFileKind = 'image' | 'pdf' | 'text' | 'audio' | 'video' | 'other';
299
+ /** One file on a message, live or replayed, with what a renderer needs to decide how to show it. */
300
+ interface MessageFile {
301
+ url: string;
302
+ mediaType: string;
303
+ /** The original name, or `null` when the part carried none. */
304
+ filename: string | null;
305
+ kind: MessageFileKind;
306
+ /** Lower-case extension from the name (`'pdf'`), or `null`. */
307
+ extension: string | null;
308
+ /** The stored media id — present on files replayed from history (`StoredMessage.attachments`). */
309
+ mediaId: string | null;
310
+ }
311
+ /** The {@link MessageFileKind} of a MIME type. */
312
+ declare function fileKind(mediaType: string): MessageFileKind;
313
+ /**
314
+ * The files on a message — the user's attachments (live, or replayed from `StoredMessage.attachments`
315
+ * by `storedMessageToUiMessage`) and any the model produced — in part order. Data only: pair it with
316
+ * your own thumbnails/links.
317
+ */
318
+ declare function messageFiles(message: Pick<UIMessage, 'parts'>): MessageFile[];
319
+ /**
320
+ * Whether `file` matches an `accept` list in the `<input accept>` grammar: MIME types
321
+ * (`application/pdf`), wildcards (`image/*`) and extensions (`.csv`). An empty list accepts all.
322
+ */
323
+ declare function acceptsFile(accept: string | readonly string[] | undefined, file: Pick<File, 'name' | 'type'>): boolean;
324
+ /** Files carried by a paste — screenshots and copied files. Text-only pastes give `[]`. */
325
+ declare function filesFromClipboard(data: DataTransfer | null | undefined): File[];
326
+ /** Whether a drag carries files (as opposed to text or a link) — gate your drop highlight on it. */
327
+ declare function dragHasFiles(data: DataTransfer | null | undefined): boolean;
328
+
329
+ /** Where one staged file stands. `rejected` never uploaded (validation); `error` can be retried. */
330
+ type StagedAttachmentStatus = 'uploading' | 'ready' | 'error' | 'rejected';
331
+ interface StagedAttachment {
332
+ /** Local id, stable for the item's life — use it as the React key and for `remove`/`retry`. */
333
+ id: string;
334
+ file: File;
335
+ name: string;
336
+ size: number;
337
+ type: string;
338
+ status: StagedAttachmentStatus;
339
+ /** 0..1 while uploading (0 until the backend reports progress), 1 once ready. */
340
+ progress: number;
341
+ /** Why it was rejected or failed. */
342
+ error?: string;
343
+ /** What the server returned — present once `ready`. */
344
+ attachment?: MessageAttachment;
345
+ /** An object URL for image previews (revoked on remove/unmount), when the runtime has one. */
346
+ previewUrl?: string;
347
+ }
348
+ /** Why a file was turned away before any upload. */
349
+ type AttachmentRejection = 'type' | 'size' | 'count';
350
+ interface UseAttachmentsOptions {
351
+ /**
352
+ * Upload one file — defaults to `backend.uploadAttachment`. Resolve with what the server
353
+ * answered; honour `signal` so `remove` can cancel; call `onProgress(0..1)` if you can.
354
+ */
355
+ upload?: (file: File, options: UploadAttachmentOptions) => Promise<MessageAttachment>;
356
+ /** Used for the default `upload`. One of `upload` / `backend` is required. */
357
+ backend?: AgentBackend;
358
+ /** `<input accept>` grammar: `'image/*,.pdf'` or `['image/*', 'application/pdf']`. */
359
+ accept?: string | readonly string[];
360
+ /** Per-file ceiling, in bytes. */
361
+ maxBytes?: number;
362
+ /** How many files may be staged at once (rejected ones do not count). */
363
+ maxFiles?: number;
364
+ /** Words for a rejection; default English. */
365
+ describeRejection?: (reason: AttachmentRejection, file: File) => string;
366
+ }
367
+ interface AttachmentsState {
368
+ items: StagedAttachment[];
369
+ /** Stage files: validate, then upload each that passes. */
370
+ add: (files: Iterable<File> | ArrayLike<File> | null | undefined) => void;
371
+ /** Drop an item, cancelling its upload. */
372
+ remove: (id: string) => void;
373
+ /** Upload a failed item again. */
374
+ retry: (id: string) => void;
375
+ /** Drop everything — call after a send. */
376
+ clear: () => void;
377
+ /** An upload is still running — hold the send button. */
378
+ isUploading: boolean;
379
+ /** What to send: the ready uploads, in order. */
380
+ attachments: MessageAttachment[];
381
+ /** The same, as the `{ mediaId }` refs `POST <base>/chat` takes. */
382
+ refs: Array<{
383
+ mediaId: string;
384
+ }>;
385
+ /** Props for a hidden `<input type="file">`: `accept`, `multiple`, `onChange`. */
386
+ inputProps: {
387
+ type: 'file';
388
+ accept: string | undefined;
389
+ multiple: boolean;
390
+ onChange: (event: {
391
+ currentTarget: HTMLInputElement;
392
+ }) => void;
393
+ };
394
+ /** Handlers for any element that should take dropped files. */
395
+ dropZoneProps: {
396
+ onDragEnter: (event: DragLikeEvent) => void;
397
+ onDragOver: (event: DragLikeEvent) => void;
398
+ onDragLeave: (event: DragLikeEvent) => void;
399
+ onDrop: (event: DragLikeEvent) => void;
400
+ };
401
+ /** Files are being dragged over the drop zone — for a highlight. */
402
+ isDragging: boolean;
403
+ /** Paste handler for the composer: stages pasted files (screenshots), leaves text alone. */
404
+ onPaste: (event: ClipboardLikeEvent) => void;
405
+ }
406
+ /** The slice of a React/DOM drag event these handlers read. */
407
+ interface DragLikeEvent {
408
+ dataTransfer: DataTransfer | null;
409
+ preventDefault: () => void;
410
+ }
411
+ /** The slice of a React/DOM clipboard event `onPaste` reads. */
412
+ interface ClipboardLikeEvent {
413
+ clipboardData: DataTransfer | null;
414
+ preventDefault: () => void;
415
+ }
416
+ /**
417
+ * Staged attachments for a composer, headless: validation (`accept`, `maxBytes`, `maxFiles`),
418
+ * one upload per file with progress and cancel, retry, previews, and the event handlers for a file
419
+ * input, a drop zone and paste — no markup, no styles. Send `attachments` (or `refs`) with the
420
+ * message, then `clear()`:
421
+ *
422
+ * ```ts
423
+ * await chat.sendMessage({ text }, { body: { attachments: files.refs } });
424
+ * files.clear();
425
+ * ```
426
+ */
427
+ declare function useAttachments(options: UseAttachmentsOptions): AttachmentsState;
428
+
295
429
  interface UseAgentsOptions {
296
430
  /** `useAgentChat(...).backend`, or your own. Must implement `listAgents`. */
297
431
  backend: AgentBackend;
@@ -347,6 +481,34 @@ interface ModelsState {
347
481
  */
348
482
  declare function useModels(options: UseModelsOptions): ModelsState;
349
483
 
484
+ interface UseQuotaOptions {
485
+ /** `useAgentChat(...).backend`, or your own. Must implement `getQuota`. */
486
+ backend: AgentBackend;
487
+ /** `false` holds the request. Default `true`. */
488
+ enabled?: boolean;
489
+ /** Re-read every `pollMs` ms as well. Default: only on mount, after runs, and on `refresh`. */
490
+ pollMs?: number;
491
+ }
492
+ interface QuotaState {
493
+ /** The full report, once loaded. */
494
+ report: QuotaReport | undefined;
495
+ windows: QuotaWindow[];
496
+ /** The `day` / `month` windows, when the server reports them. */
497
+ day: QuotaWindow | undefined;
498
+ month: QuotaWindow | undefined;
499
+ /** The window that blocks sends, or `null` — pass it to `useAgentChat({ blocked })`. */
500
+ blocked: QuotaBlock | null;
501
+ isLoading: boolean;
502
+ error: Error | null;
503
+ refresh: () => Promise<void>;
504
+ }
505
+ /**
506
+ * The caller's budget (`GET <base>/quota`): every window's usage against its ceilings, and which
507
+ * one — if any — blocks sends. Re-read after every run a chat on the same backend settles, so a
508
+ * meter moves with the conversation. Headless: draw the meter yourself.
509
+ */
510
+ declare function useQuota(options: UseQuotaOptions): QuotaState;
511
+
350
512
  interface UseMessageFeedbackOptions {
351
513
  /** `useAgentChat(...).backend`, or your own. Must implement `setMessageFeedback`. */
352
514
  backend: AgentBackend;
@@ -540,12 +702,15 @@ declare class AgentClient implements AgentBackend {
540
702
  * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
541
703
  */
542
704
  uploadAttachment(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;
705
+ private uploadWithProgress;
543
706
  promoteThread(id: string): Promise<OkResult>;
544
707
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
545
708
  /** `GET /agent/models?agent=` — the models this caller may pick, grouped by provider. */
546
709
  listModels(agent?: string): Promise<ModelCatalogView>;
547
710
  /** `GET /agent/agents` — the registered agents, the default one flagged. */
548
711
  listAgents(): Promise<AgentCatalogEntry[]>;
712
+ /** `GET /agent/quota` — the caller's budget windows and the one blocking sends, if any. */
713
+ getQuota(): Promise<QuotaReport>;
549
714
  getQuotaToday(): Promise<QuotaToday>;
550
715
  cancelStream(runId: string): Promise<CancelResult>;
551
716
  /**
@@ -1373,6 +1538,12 @@ interface UseAgentChatOptions<B extends AgentBackend = AgentClient> {
1373
1538
  client?: B;
1374
1539
  /** Named agent to run each turn. */
1375
1540
  agent?: string;
1541
+ /**
1542
+ * The quota window blocking sends — `useQuota(...).blocked`. While set, `sendMessage` and
1543
+ * `regenerate` refuse with {@link QuotaBlockedError} instead of starting a turn the server would
1544
+ * refuse anyway.
1545
+ */
1546
+ blocked?: QuotaBlock | null;
1376
1547
  /**
1377
1548
  * Catalog model to run each turn on (see `useModels`), sent as the body's `model`. Read at every
1378
1549
  * send, so a picker can change it between turns. Omitted → the thread's pinned model, else the
@@ -1563,5 +1734,10 @@ declare function useAgentChat<B extends AgentBackend = AgentClient>(options: Use
1563
1734
  addToolApprovalResponse: ai.ChatAddToolApproveResponseFunction;
1564
1735
  clearError: () => void;
1565
1736
  };
1737
+ /** A send refused on the client because a quota window is exhausted (`useAgentChat({ blocked })`). */
1738
+ declare class QuotaBlockedError extends Error {
1739
+ readonly block: QuotaBlock;
1740
+ constructor(block: QuotaBlock);
1741
+ }
1566
1742
 
1567
- export { type AgentBackend, AgentBackendUnsupportedError, AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentMessageMetadata, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, AnyToolUIPart, type ApprovalCountdown, ApproveOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatStreamRequest, type ChatStreamResponse, type ChatTranscript, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type MessageFeedbackInput, type MessageFeedbackState, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, MessageUsageInfo, type ModelOption, type ModelsState, type QuotaToday, type ReconnectOptions, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResumeStreamRequest, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, type ThreadPatch, type ThreadsEvent, type ThreadsState, TimestampInfo, ToolCatalog, type ToolCatalogState, type TranscriptActionState, TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, TranscriptFile, type TranscriptItem, type TranscriptItemOptions, type TranscriptStopState, TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentsOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseMessageFeedbackOptions, type UseModelsOptions, type UseSpeechRecognitionOptions, type UseThreadsOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, notifyThreads, onThreadsEvent, persistSpeechLang, readReasoningMs, requireBackendMethod, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useAgents, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
1743
+ export { type AgentBackend, AgentBackendUnsupportedError, AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentMessageMetadata, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, AnyToolUIPart, type ApprovalCountdown, ApproveOptions, type AttachmentRejection, type AttachmentsState, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatStreamRequest, type ChatStreamResponse, type ChatTranscript, type ClipboardLikeEvent, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DragLikeEvent, type MessageFeedbackInput, type MessageFeedbackState, type MessageFile, type MessageFileKind, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, MessageUsageInfo, type ModelOption, type ModelsState, QuotaBlockedError, type QuotaState, type QuotaToday, type ReconnectOptions, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResumeStreamRequest, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StagedAttachment, type StagedAttachmentStatus, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, type ThreadPatch, type ThreadsEvent, type ThreadsState, TimestampInfo, ToolCatalog, type ToolCatalogState, type TranscriptActionState, TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, TranscriptFile, type TranscriptItem, type TranscriptItemOptions, type TranscriptStopState, TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentsOptions, type UseApprovalCountdownOptions, type UseAttachmentsOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseMessageFeedbackOptions, type UseModelsOptions, type UseQuotaOptions, type UseSpeechRecognitionOptions, type UseThreadsOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, acceptsFile, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, dragHasFiles, fileKind, filesFromClipboard, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, messageFiles, notifyThreads, onThreadsEvent, persistSpeechLang, readReasoningMs, requireBackendMethod, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useAgents, useApprovalCountdown, useAttachments, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useQuota, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, DataUIPart, UIDataTypes } from 'ai';
3
3
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
4
- import { ThreadSummary, ThreadDetail, MessageAttachment, ToolCatalogEntry, SkillCatalogEntry, QuotaView, ModelCatalogView, AgentCatalogEntry, MessageFeedbackValue, MessageFeedback, ModelCatalogEntry, StoredMessage } from '@dudousxd/nestjs-agent-core';
4
+ import { ThreadSummary, ThreadDetail, MessageAttachment, ToolCatalogEntry, SkillCatalogEntry, QuotaView, QuotaReport, ModelCatalogView, AgentCatalogEntry, MessageFeedbackValue, MessageFeedback, ModelCatalogEntry, QuotaWindow, QuotaBlock, StoredMessage } from '@dudousxd/nestjs-agent-core';
5
5
  export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
6
6
  import React__default from 'react';
7
7
  import { a as TranscriptBlock, U as UsageSummary, b as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, c as ToolCatalog, A as ApproveOptions, d as AnyToolUIPart, e as TranscriptFile, T as TranscriptUiBlock } from './model-gHqjNjLJ.js';
@@ -106,6 +106,8 @@ interface AgentBackend {
106
106
  listTools?(agent?: string): Promise<ToolCatalogEntry[]>;
107
107
  listSkills?(threadId?: string): Promise<SkillCatalogEntry[]>;
108
108
  getQuotaToday?(): Promise<QuotaView>;
109
+ /** `GET <base>/quota` — every budget window, and which one blocks sends, if any. */
110
+ getQuota?(): Promise<QuotaReport>;
109
111
  /** `GET <base>/models?agent=` — what a model picker offers. */
110
112
  listModels?(agent?: string): Promise<ModelCatalogView>;
111
113
  /** `GET <base>/agents` — what an agent picker offers. */
@@ -292,6 +294,138 @@ declare class AgentChatTransport implements ChatTransport<UIMessage> {
292
294
  private toChunkStream;
293
295
  }
294
296
 
297
+ /** How a renderer is likely to show a file. */
298
+ type MessageFileKind = 'image' | 'pdf' | 'text' | 'audio' | 'video' | 'other';
299
+ /** One file on a message, live or replayed, with what a renderer needs to decide how to show it. */
300
+ interface MessageFile {
301
+ url: string;
302
+ mediaType: string;
303
+ /** The original name, or `null` when the part carried none. */
304
+ filename: string | null;
305
+ kind: MessageFileKind;
306
+ /** Lower-case extension from the name (`'pdf'`), or `null`. */
307
+ extension: string | null;
308
+ /** The stored media id — present on files replayed from history (`StoredMessage.attachments`). */
309
+ mediaId: string | null;
310
+ }
311
+ /** The {@link MessageFileKind} of a MIME type. */
312
+ declare function fileKind(mediaType: string): MessageFileKind;
313
+ /**
314
+ * The files on a message — the user's attachments (live, or replayed from `StoredMessage.attachments`
315
+ * by `storedMessageToUiMessage`) and any the model produced — in part order. Data only: pair it with
316
+ * your own thumbnails/links.
317
+ */
318
+ declare function messageFiles(message: Pick<UIMessage, 'parts'>): MessageFile[];
319
+ /**
320
+ * Whether `file` matches an `accept` list in the `<input accept>` grammar: MIME types
321
+ * (`application/pdf`), wildcards (`image/*`) and extensions (`.csv`). An empty list accepts all.
322
+ */
323
+ declare function acceptsFile(accept: string | readonly string[] | undefined, file: Pick<File, 'name' | 'type'>): boolean;
324
+ /** Files carried by a paste — screenshots and copied files. Text-only pastes give `[]`. */
325
+ declare function filesFromClipboard(data: DataTransfer | null | undefined): File[];
326
+ /** Whether a drag carries files (as opposed to text or a link) — gate your drop highlight on it. */
327
+ declare function dragHasFiles(data: DataTransfer | null | undefined): boolean;
328
+
329
+ /** Where one staged file stands. `rejected` never uploaded (validation); `error` can be retried. */
330
+ type StagedAttachmentStatus = 'uploading' | 'ready' | 'error' | 'rejected';
331
+ interface StagedAttachment {
332
+ /** Local id, stable for the item's life — use it as the React key and for `remove`/`retry`. */
333
+ id: string;
334
+ file: File;
335
+ name: string;
336
+ size: number;
337
+ type: string;
338
+ status: StagedAttachmentStatus;
339
+ /** 0..1 while uploading (0 until the backend reports progress), 1 once ready. */
340
+ progress: number;
341
+ /** Why it was rejected or failed. */
342
+ error?: string;
343
+ /** What the server returned — present once `ready`. */
344
+ attachment?: MessageAttachment;
345
+ /** An object URL for image previews (revoked on remove/unmount), when the runtime has one. */
346
+ previewUrl?: string;
347
+ }
348
+ /** Why a file was turned away before any upload. */
349
+ type AttachmentRejection = 'type' | 'size' | 'count';
350
+ interface UseAttachmentsOptions {
351
+ /**
352
+ * Upload one file — defaults to `backend.uploadAttachment`. Resolve with what the server
353
+ * answered; honour `signal` so `remove` can cancel; call `onProgress(0..1)` if you can.
354
+ */
355
+ upload?: (file: File, options: UploadAttachmentOptions) => Promise<MessageAttachment>;
356
+ /** Used for the default `upload`. One of `upload` / `backend` is required. */
357
+ backend?: AgentBackend;
358
+ /** `<input accept>` grammar: `'image/*,.pdf'` or `['image/*', 'application/pdf']`. */
359
+ accept?: string | readonly string[];
360
+ /** Per-file ceiling, in bytes. */
361
+ maxBytes?: number;
362
+ /** How many files may be staged at once (rejected ones do not count). */
363
+ maxFiles?: number;
364
+ /** Words for a rejection; default English. */
365
+ describeRejection?: (reason: AttachmentRejection, file: File) => string;
366
+ }
367
+ interface AttachmentsState {
368
+ items: StagedAttachment[];
369
+ /** Stage files: validate, then upload each that passes. */
370
+ add: (files: Iterable<File> | ArrayLike<File> | null | undefined) => void;
371
+ /** Drop an item, cancelling its upload. */
372
+ remove: (id: string) => void;
373
+ /** Upload a failed item again. */
374
+ retry: (id: string) => void;
375
+ /** Drop everything — call after a send. */
376
+ clear: () => void;
377
+ /** An upload is still running — hold the send button. */
378
+ isUploading: boolean;
379
+ /** What to send: the ready uploads, in order. */
380
+ attachments: MessageAttachment[];
381
+ /** The same, as the `{ mediaId }` refs `POST <base>/chat` takes. */
382
+ refs: Array<{
383
+ mediaId: string;
384
+ }>;
385
+ /** Props for a hidden `<input type="file">`: `accept`, `multiple`, `onChange`. */
386
+ inputProps: {
387
+ type: 'file';
388
+ accept: string | undefined;
389
+ multiple: boolean;
390
+ onChange: (event: {
391
+ currentTarget: HTMLInputElement;
392
+ }) => void;
393
+ };
394
+ /** Handlers for any element that should take dropped files. */
395
+ dropZoneProps: {
396
+ onDragEnter: (event: DragLikeEvent) => void;
397
+ onDragOver: (event: DragLikeEvent) => void;
398
+ onDragLeave: (event: DragLikeEvent) => void;
399
+ onDrop: (event: DragLikeEvent) => void;
400
+ };
401
+ /** Files are being dragged over the drop zone — for a highlight. */
402
+ isDragging: boolean;
403
+ /** Paste handler for the composer: stages pasted files (screenshots), leaves text alone. */
404
+ onPaste: (event: ClipboardLikeEvent) => void;
405
+ }
406
+ /** The slice of a React/DOM drag event these handlers read. */
407
+ interface DragLikeEvent {
408
+ dataTransfer: DataTransfer | null;
409
+ preventDefault: () => void;
410
+ }
411
+ /** The slice of a React/DOM clipboard event `onPaste` reads. */
412
+ interface ClipboardLikeEvent {
413
+ clipboardData: DataTransfer | null;
414
+ preventDefault: () => void;
415
+ }
416
+ /**
417
+ * Staged attachments for a composer, headless: validation (`accept`, `maxBytes`, `maxFiles`),
418
+ * one upload per file with progress and cancel, retry, previews, and the event handlers for a file
419
+ * input, a drop zone and paste — no markup, no styles. Send `attachments` (or `refs`) with the
420
+ * message, then `clear()`:
421
+ *
422
+ * ```ts
423
+ * await chat.sendMessage({ text }, { body: { attachments: files.refs } });
424
+ * files.clear();
425
+ * ```
426
+ */
427
+ declare function useAttachments(options: UseAttachmentsOptions): AttachmentsState;
428
+
295
429
  interface UseAgentsOptions {
296
430
  /** `useAgentChat(...).backend`, or your own. Must implement `listAgents`. */
297
431
  backend: AgentBackend;
@@ -347,6 +481,34 @@ interface ModelsState {
347
481
  */
348
482
  declare function useModels(options: UseModelsOptions): ModelsState;
349
483
 
484
+ interface UseQuotaOptions {
485
+ /** `useAgentChat(...).backend`, or your own. Must implement `getQuota`. */
486
+ backend: AgentBackend;
487
+ /** `false` holds the request. Default `true`. */
488
+ enabled?: boolean;
489
+ /** Re-read every `pollMs` ms as well. Default: only on mount, after runs, and on `refresh`. */
490
+ pollMs?: number;
491
+ }
492
+ interface QuotaState {
493
+ /** The full report, once loaded. */
494
+ report: QuotaReport | undefined;
495
+ windows: QuotaWindow[];
496
+ /** The `day` / `month` windows, when the server reports them. */
497
+ day: QuotaWindow | undefined;
498
+ month: QuotaWindow | undefined;
499
+ /** The window that blocks sends, or `null` — pass it to `useAgentChat({ blocked })`. */
500
+ blocked: QuotaBlock | null;
501
+ isLoading: boolean;
502
+ error: Error | null;
503
+ refresh: () => Promise<void>;
504
+ }
505
+ /**
506
+ * The caller's budget (`GET <base>/quota`): every window's usage against its ceilings, and which
507
+ * one — if any — blocks sends. Re-read after every run a chat on the same backend settles, so a
508
+ * meter moves with the conversation. Headless: draw the meter yourself.
509
+ */
510
+ declare function useQuota(options: UseQuotaOptions): QuotaState;
511
+
350
512
  interface UseMessageFeedbackOptions {
351
513
  /** `useAgentChat(...).backend`, or your own. Must implement `setMessageFeedback`. */
352
514
  backend: AgentBackend;
@@ -540,12 +702,15 @@ declare class AgentClient implements AgentBackend {
540
702
  * what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
541
703
  */
542
704
  uploadAttachment(file: File, options?: UploadAttachmentOptions): Promise<MessageAttachment>;
705
+ private uploadWithProgress;
543
706
  promoteThread(id: string): Promise<OkResult>;
544
707
  truncateFromMessage(threadId: string, messageId: string): Promise<OkResult>;
545
708
  /** `GET /agent/models?agent=` — the models this caller may pick, grouped by provider. */
546
709
  listModels(agent?: string): Promise<ModelCatalogView>;
547
710
  /** `GET /agent/agents` — the registered agents, the default one flagged. */
548
711
  listAgents(): Promise<AgentCatalogEntry[]>;
712
+ /** `GET /agent/quota` — the caller's budget windows and the one blocking sends, if any. */
713
+ getQuota(): Promise<QuotaReport>;
549
714
  getQuotaToday(): Promise<QuotaToday>;
550
715
  cancelStream(runId: string): Promise<CancelResult>;
551
716
  /**
@@ -1373,6 +1538,12 @@ interface UseAgentChatOptions<B extends AgentBackend = AgentClient> {
1373
1538
  client?: B;
1374
1539
  /** Named agent to run each turn. */
1375
1540
  agent?: string;
1541
+ /**
1542
+ * The quota window blocking sends — `useQuota(...).blocked`. While set, `sendMessage` and
1543
+ * `regenerate` refuse with {@link QuotaBlockedError} instead of starting a turn the server would
1544
+ * refuse anyway.
1545
+ */
1546
+ blocked?: QuotaBlock | null;
1376
1547
  /**
1377
1548
  * Catalog model to run each turn on (see `useModels`), sent as the body's `model`. Read at every
1378
1549
  * send, so a picker can change it between turns. Omitted → the thread's pinned model, else the
@@ -1563,5 +1734,10 @@ declare function useAgentChat<B extends AgentBackend = AgentClient>(options: Use
1563
1734
  addToolApprovalResponse: ai.ChatAddToolApproveResponseFunction;
1564
1735
  clearError: () => void;
1565
1736
  };
1737
+ /** A send refused on the client because a quota window is exhausted (`useAgentChat({ blocked })`). */
1738
+ declare class QuotaBlockedError extends Error {
1739
+ readonly block: QuotaBlock;
1740
+ constructor(block: QuotaBlock);
1741
+ }
1566
1742
 
1567
- export { type AgentBackend, AgentBackendUnsupportedError, AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentMessageMetadata, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, AnyToolUIPart, type ApprovalCountdown, ApproveOptions, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatStreamRequest, type ChatStreamResponse, type ChatTranscript, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type MessageFeedbackInput, type MessageFeedbackState, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, MessageUsageInfo, type ModelOption, type ModelsState, type QuotaToday, type ReconnectOptions, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResumeStreamRequest, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, type ThreadPatch, type ThreadsEvent, type ThreadsState, TimestampInfo, ToolCatalog, type ToolCatalogState, type TranscriptActionState, TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, TranscriptFile, type TranscriptItem, type TranscriptItemOptions, type TranscriptStopState, TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentsOptions, type UseApprovalCountdownOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseMessageFeedbackOptions, type UseModelsOptions, type UseSpeechRecognitionOptions, type UseThreadsOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, notifyThreads, onThreadsEvent, persistSpeechLang, readReasoningMs, requireBackendMethod, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useAgents, useApprovalCountdown, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
1743
+ export { type AgentBackend, AgentBackendUnsupportedError, AgentChatTransport, type AgentChatTransportOptions, AgentClient, type AgentClientOptions, AgentHttpError, type AgentMessageMetadata, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, AnyToolUIPart, type ApprovalCountdown, ApproveOptions, type AttachmentRejection, type AttachmentsState, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type CancelResult, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatStreamRequest, type ChatStreamResponse, type ChatTranscript, type ClipboardLikeEvent, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DragLikeEvent, type MessageFeedbackInput, type MessageFeedbackState, type MessageFile, type MessageFileKind, MessageItem, type MessageItemClassNames, type MessageItemProps, MessageItemView, type MessageItemViewProps, MessageList, type MessageListClassNames, type MessageListProps, MessageUsageInfo, type ModelOption, type ModelsState, QuotaBlockedError, type QuotaState, type QuotaToday, type ReconnectOptions, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, type ResumeStreamRequest, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SpeechLanguage, type SpeechRecognitionHook, type StagedAttachment, type StagedAttachmentStatus, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, type ThreadPatch, type ThreadsEvent, type ThreadsState, TimestampInfo, ToolCatalog, type ToolCatalogState, type TranscriptActionState, TranscriptBlock, type TranscriptCopyState, type TranscriptEditState, TranscriptFile, type TranscriptItem, type TranscriptItemOptions, type TranscriptStopState, TranscriptUiBlock, type TranscriptWindow, type TriggerMatch, type TriggerPosition, type UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentsOptions, type UseApprovalCountdownOptions, type UseAttachmentsOptions, type UseChatTranscriptOptions, type UseComposerAutocompleteOptions, type UseElapsedOptions, type UseMessageFeedbackOptions, type UseModelsOptions, type UseQuotaOptions, type UseSpeechRecognitionOptions, type UseThreadsOptions, type UseToolCatalogOptions, type UseTranscriptItemOptions, acceptsFile, applyCompletion, approvalCountdown, backgroundRunsFromThread, createSkillsSource, dragHasFiles, fileKind, filesFromClipboard, filterAutocompleteItems, findActiveTrigger, formatElapsed, loadStoredSpeechLang, messageFiles, notifyThreads, onThreadsEvent, persistSpeechLang, readReasoningMs, requireBackendMethod, storedMessageToUiMessage, storedThreadToUiMessages, useAgentChat, useAgents, useApprovalCountdown, useAttachments, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useQuota, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };