@dudousxd/nestjs-agent-react 0.24.0 → 0.25.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,13 +1,13 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, DataUIPart, UIDataTypes } from 'ai';
3
- import { A as AgentBackend, U as UploadAttachmentOptions, a as AttachmentUploadStrategy } from './client-ioKDyV2q.cjs';
4
- export { b as AgentBackendUnsupportedError, c as AgentClient, d as AgentClientOptions, e as AgentConnection, f as AgentHttpError, C as CancelResult, g as ChatStreamRequest, h as ChatStreamResponse, M as MessageFeedbackInput, R as ResumeStreamRequest, T as ThreadPatch, r as requireBackendMethod } from './client-ioKDyV2q.cjs';
5
- import { MessageAttachment, AgentClientConfig, AgentCatalogEntry, ModelCatalogEntry, ModelCatalogView, QuotaReport, QuotaWindow, QuotaBlock, MessageFeedback, MessageFeedbackValue, ThreadSummary, StoredMessage, ToolCatalogEntry } from '@dudousxd/nestjs-agent-core';
3
+ import { A as AgentBackend, U as UploadAttachmentOptions, H as HttpErrorListener, a as AttachmentUploadStrategy } from './client-D4ZSbZJ8.cjs';
4
+ export { b as AgentBackendUnsupportedError, c as AgentClient, d as AgentClientOptions, e as AgentConnection, f as AgentHttpError, g as AgentRequestError, C as CancelResult, h as ChatStreamRequest, i as ChatStreamResponse, M as MessageFeedbackInput, R as ResumeStreamRequest, T as ThreadPatch, r as requireBackendMethod } from './client-D4ZSbZJ8.cjs';
5
+ import { MessageAttachment, AgentClientConfig, AgentCatalogEntry, ModelCatalogEntry, ModelCatalogView, ModelCatalogLock, QuotaReport, QuotaWindow, QuotaBlock, QuotaWarning, MessageFeedback, MessageFeedbackValue, ThreadSummary, StoredMessage, ToolCatalogEntry } from '@dudousxd/nestjs-agent-core';
6
6
  export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
7
7
  import * as React from 'react';
8
8
  import React__default, { ReactNode, Context } from 'react';
9
- import { o as GenuiProviderValue, T as TranscriptUiBlock, A as ApproveOptions, t as TranscriptBlock, U as UsageSummary, v as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, w as ToolCatalog, x as AnyToolUIPart, y as TranscriptFile } from './generative-ui-9AJNVKBZ.cjs';
10
- export { z as ApprovalBlockOptions, B as BuildBlocksOptions, D as CoercibleQuestion, E as DescribeToolCallOptions, F as ElicitationBlockOptions, H as GroupToolActivityOptions, I as RawAnswer, J as ResolvedReading, K as ResolvedResultView, L as RetrievedPassage, S as SettleAction, N as ToolActivityGroup, O as ToolCallDescription, P as ToolCallState, Q as ToolCallStatus, V as TranscriptApproval, W as TranscriptApprovalStatus, X as TranscriptElicitationBlock, Y as TranscriptElicitationOutcome, Z as TranscriptFilesBlock, _ as TranscriptQuestion, $ as TranscriptQuestionOption, a0 as TranscriptReasoningBlock, a1 as TranscriptSettleState, a2 as TranscriptSource, a3 as TranscriptSourcesBlock, a4 as TranscriptTextBlock, a5 as TranscriptToolBlock, a6 as TranscriptToolCall, a7 as buildTranscriptBlocks, a8 as coerceAnswer, a9 as correctedCallIds, aa as describeTimestamp, ab as describeToolCall, ac as describeUsage, ad as extractMessageText, ae as fillTemplate, af as formatRelativeTime, ag as groupToolActivity, ah as inferResultView, ai as isActionCall, aj as phraseFor, ak as readPath, al as resolveResultView, am as toolCallState, an as toolCatalogFrom } from './generative-ui-9AJNVKBZ.cjs';
9
+ import { o as GenuiProviderValue, T as TranscriptUiBlock, A as ApproveOptions, t as TranscriptBlock, U as UsageSummary, v as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, w as ToolCatalog, x as AnyToolUIPart, y as TranscriptFile } from './generative-ui-BejHxxbR.cjs';
10
+ export { z as ApprovalBlockOptions, B as BuildBlocksOptions, D as CoercibleQuestion, E as DescribeToolCallOptions, F as ElicitationBlockOptions, H as GroupToolActivityOptions, I as RawAnswer, J as ResolvedReading, K as ResolvedResultView, L as RetrievedPassage, S as SettleAction, N as ToolActivityGroup, O as ToolCallDescription, P as ToolCallState, Q as ToolCallStatus, V as TranscriptApproval, W as TranscriptApprovalStatus, X as TranscriptElicitationBlock, Y as TranscriptElicitationOutcome, Z as TranscriptFilesBlock, _ as TranscriptQuestion, $ as TranscriptQuestionOption, a0 as TranscriptReasoningBlock, a1 as TranscriptSettleState, a2 as TranscriptSource, a3 as TranscriptSourcesBlock, a4 as TranscriptTextBlock, a5 as TranscriptToolBlock, a6 as TranscriptToolCall, a7 as buildTranscriptBlocks, a8 as coerceAnswer, a9 as correctedCallIds, aa as describeTimestamp, ab as describeToolCall, ac as describeUsage, ad as extractMessageText, ae as fillTemplate, af as formatRelativeTime, ag as groupToolActivity, ah as inferResultView, ai as isActionCall, aj as phraseFor, ak as readPath, al as resolveResultView, am as toolCallState, an as toolCatalogFrom } from './generative-ui-BejHxxbR.cjs';
11
11
 
12
12
  /** Identity surfaced by the backend's `meta` SSE frame / response headers. */
13
13
  interface AgentStreamMeta {
@@ -329,6 +329,12 @@ interface AgentProviderProps {
329
329
  credentials?: RequestCredentials;
330
330
  /** Injectable for tests / non-browser runtimes. */
331
331
  fetch?: typeof fetch;
332
+ /**
333
+ * Every error answer of the built-in client (an `AgentHttpError`, or a `MediaUploadError` from
334
+ * `mediaAttachments()`), right before it is thrown — for app-wide reactions such as "401 → sign
335
+ * in again". Read at call time, so it may change between renders.
336
+ */
337
+ onHttpError?: HttpErrorListener;
332
338
  /** Attachment uploads of the built-in client. */
333
339
  attachments?: {
334
340
  /** e.g. `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media`. */
@@ -354,7 +360,7 @@ interface AgentProviderProps {
354
360
  *
355
361
  * Without a provider every hook shares one same-origin client on `/agent`.
356
362
  */
357
- declare function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, attachments, genui, children, }: AgentProviderProps): React.JSX.Element;
363
+ declare function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, onHttpError, attachments, genui, children, }: AgentProviderProps): React.JSX.Element;
358
364
  /**
359
365
  * The backend a hook talks to: `own` when given, else the enclosing {@link AgentProvider}'s, else a
360
366
  * shared same-origin client on `/agent`. For your own hooks over the same connection.
@@ -421,6 +427,11 @@ interface ModelsState {
421
427
  models: ModelOption[];
422
428
  /** The model a turn runs on when none is picked, or `null` when the provider decides. */
423
429
  defaultModel: string | null;
430
+ /**
431
+ * The agent always runs on one model (`{ model, reason? }`), or `null`. A picker shows it
432
+ * read-only: the server runs every turn on it and refuses any other.
433
+ */
434
+ locked: ModelCatalogLock | null;
424
435
  /** The entry for `id`, or `undefined`. */
425
436
  find: (id: string | null | undefined) => ModelOption | undefined;
426
437
  isLoading: boolean;
@@ -430,8 +441,8 @@ interface ModelsState {
430
441
  /**
431
442
  * The models this caller may pick (`GET <base>/models?agent=`), with badges and availability — the
432
443
  * data behind a model picker. Headless: render the options however you like, then send the pick
433
- * as `useAgentChat({ model })`, `sendMessage(msg, { body: { model } })`, or pin it on the thread
434
- * with `chat.setThreadModel(id)`.
444
+ * as `useAgentChat({ model })` or `sendMessage(msg, { body: { model } })` (that turn only), or
445
+ * pin it on the thread with `chat.models.pinToThread(id)`.
435
446
  */
436
447
  declare function useModels(options?: UseModelsOptions): ModelsState;
437
448
 
@@ -452,6 +463,11 @@ interface QuotaState {
452
463
  month: QuotaWindow | undefined;
453
464
  /** The window that blocks sends, or `null` — pass it to `useAgentChat({ blocked })`. */
454
465
  blocked: QuotaBlock | null;
466
+ /**
467
+ * The soft limit: the fullest window past its `warnAt` (`{ period, ratio, reason? }`), or `null`.
468
+ * The server's `warning`, else derived from the windows; never set while `blocked`.
469
+ */
470
+ warning: QuotaWarning | null;
455
471
  isLoading: boolean;
456
472
  error: Error | null;
457
473
  refresh: () => Promise<void>;
@@ -723,10 +739,14 @@ interface MessageActionInput {
723
739
  interface AnswerInput {
724
740
  toolCallId: string;
725
741
  answers?: Record<string, string[]>;
742
+ /** The surface the answer came through; the server records `'web'` when omitted. */
743
+ via?: string;
726
744
  }
727
745
  /** Declining a parked question set. */
728
746
  interface SkipInput {
729
747
  toolCallId: string;
748
+ /** The surface the skip came through; the server records `'web'` when omitted. */
749
+ via?: string;
730
750
  }
731
751
  /** Approving a tool call parked on a human. */
732
752
  interface ApproveInput extends ApproveOptions {
@@ -1425,7 +1445,9 @@ interface UseAgentChatOptions<B extends AgentBackend = AgentBackend> {
1425
1445
  /**
1426
1446
  * The model every turn runs on, controlled by you. Omitted → `chat.models.selected` (what
1427
1447
  * `chat.models.select(id)` picked), else the thread's pinned model, else the server default. A
1428
- * single send can still override it with `sendMessage(msg, { body: { model } })`.
1448
+ * single send can still override it with `sendMessage(msg, { body: { model } })`. Sent as the
1449
+ * turn's `model`, which the server applies to that turn only — pinning a model on the thread is
1450
+ * `chat.models.pinToThread(id)`.
1429
1451
  */
1430
1452
  model?: string;
1431
1453
  /**
@@ -1499,21 +1521,41 @@ interface ChatBackground {
1499
1521
  /** Re-read the thread now, instead of waiting for the next poll. */
1500
1522
  refresh: () => Promise<void>;
1501
1523
  }
1502
- /** The chat's model picker state. Loaded the first time `list`/`providers` is read. */
1524
+ /**
1525
+ * The chat's model picker state. Loaded the first time `list`/`providers`/`defaultModel`/`locked`
1526
+ * is read.
1527
+ *
1528
+ * Two different choices: `select(id)` picks the model this chat's following sends name — each send
1529
+ * carries it as `model`, which the server applies to that turn only and never stores; the pick is
1530
+ * this conversation's, so switching threads drops it. `pinToThread(id)` stores a model on the
1531
+ * thread (`PATCH threads/:id { model }`), which every later turn without a `model` of its own runs
1532
+ * on, across reloads and devices.
1533
+ */
1503
1534
  interface ChatModels {
1504
1535
  /** Every model the caller may pick, flattened (`[]` until loaded). */
1505
1536
  readonly list: ModelOption[];
1506
1537
  /** The same, grouped by provider. */
1507
1538
  readonly providers: ModelsState['providers'];
1508
- /** What the next turn runs on: the `model` option, the pick, the thread's pin, else the default. */
1539
+ /**
1540
+ * What the next turn runs on: the lock, the `model` option, the pick, the thread's pin, else the
1541
+ * default.
1542
+ */
1509
1543
  selected: string | null;
1544
+ /** The model pinned on the thread (`null` when none, or before the thread is read). */
1545
+ pinned: string | null;
1510
1546
  /** The catalog's default — what a turn runs on when nothing is picked or pinned (`null` until loaded). */
1511
1547
  readonly defaultModel: string | null;
1512
- /** Run the following turns on `id` (sent as the body's `model`). */
1548
+ /**
1549
+ * The agent always runs on one model (`{ model, reason? }`), or `null`. While locked, `select`
1550
+ * does nothing and `selected` is the locked model.
1551
+ */
1552
+ readonly locked: ModelsState['locked'];
1553
+ /** Run this chat's following sends on `id` — each send's `model`, that turn only. */
1513
1554
  select: (id: string) => void;
1514
1555
  /**
1515
1556
  * Pin `id` on the thread (`null` unpins) — every later turn without its own `model` runs on it,
1516
- * across reloads. On a chat with no thread yet, the pin lands when the first send creates one.
1557
+ * across reloads. Replaces the pick, so the next send runs on the pin. On a chat with no thread
1558
+ * yet, the pin lands when the first send creates one.
1517
1559
  */
1518
1560
  pinToThread: (id: string | null) => Promise<void>;
1519
1561
  isLoading: boolean;
@@ -1598,8 +1640,8 @@ declare function useAgentChat<B extends AgentBackend = AgentBackend>(options?: U
1598
1640
  cancel: () => Promise<void>;
1599
1641
  approve: ({ toolCallId, remember, via }: ApproveInput) => Promise<void>;
1600
1642
  reject: ({ toolCallId, reason, via }: RejectInput) => Promise<void>;
1601
- answer: ({ toolCallId, answers }: AnswerInput) => Promise<void>;
1602
- skip: ({ toolCallId }: SkipInput) => Promise<void>;
1643
+ answer: ({ toolCallId, answers, via }: AnswerInput) => Promise<void>;
1644
+ skip: ({ toolCallId, via }: SkipInput) => Promise<void>;
1603
1645
  regenerate: (_input?: Partial<MessageActionInput>) => void;
1604
1646
  fork: ({ messageId, threadId, }: MessageActionInput & {
1605
1647
  threadId?: string;
@@ -1626,4 +1668,4 @@ declare class QuotaBlockedError extends Error {
1626
1668
  constructor(block: QuotaBlock);
1627
1669
  }
1628
1670
 
1629
- export { AgentBackend, AgentChatTransport, type AgentChatTransportOptions, type AgentConfigState, type AgentMessageMetadata, AgentProvider, type AgentProviderProps, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, type AmbientRenderUi, AmbientRenderUiContext, type AnswerInput, AnyToolUIPart, type ApprovalCountdown, type ApproveInput, ApproveOptions, type AttachmentRejection, AttachmentUploadStrategy, type AttachmentsState, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatTranscript, type ClipboardLikeEvent, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DragLikeEvent, type EditSubmitInput, type MessageActionInput, 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 ReconnectOptions, type RejectInput, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SkipInput, type SpeechLanguage, type SpeechRecognitionHook, type StagedAttachment, type StagedAttachmentStatus, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, 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, UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentConfigOptions, 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, storedMessageToUiMessage, storedThreadToUiMessages, useAgentBackend, useAgentChat, useAgentConfig, useAgents, useAmbientRenderUi, useApprovalCountdown, useAttachments, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useQuota, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
1671
+ export { AgentBackend, AgentChatTransport, type AgentChatTransportOptions, type AgentConfigState, type AgentMessageMetadata, AgentProvider, type AgentProviderProps, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, type AmbientRenderUi, AmbientRenderUiContext, type AnswerInput, AnyToolUIPart, type ApprovalCountdown, type ApproveInput, ApproveOptions, type AttachmentRejection, AttachmentUploadStrategy, type AttachmentsState, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatTranscript, type ClipboardLikeEvent, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DragLikeEvent, type EditSubmitInput, HttpErrorListener, type MessageActionInput, 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 ReconnectOptions, type RejectInput, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SkipInput, type SpeechLanguage, type SpeechRecognitionHook, type StagedAttachment, type StagedAttachmentStatus, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, 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, UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentConfigOptions, 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, storedMessageToUiMessage, storedThreadToUiMessages, useAgentBackend, useAgentChat, useAgentConfig, useAgents, useAmbientRenderUi, useApprovalCountdown, useAttachments, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useQuota, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  import * as ai from 'ai';
2
2
  import { ChatTransport, UIMessage, UIMessageChunk, DataUIPart, UIDataTypes } from 'ai';
3
- import { A as AgentBackend, U as UploadAttachmentOptions, a as AttachmentUploadStrategy } from './client-ioKDyV2q.js';
4
- export { b as AgentBackendUnsupportedError, c as AgentClient, d as AgentClientOptions, e as AgentConnection, f as AgentHttpError, C as CancelResult, g as ChatStreamRequest, h as ChatStreamResponse, M as MessageFeedbackInput, R as ResumeStreamRequest, T as ThreadPatch, r as requireBackendMethod } from './client-ioKDyV2q.js';
5
- import { MessageAttachment, AgentClientConfig, AgentCatalogEntry, ModelCatalogEntry, ModelCatalogView, QuotaReport, QuotaWindow, QuotaBlock, MessageFeedback, MessageFeedbackValue, ThreadSummary, StoredMessage, ToolCatalogEntry } from '@dudousxd/nestjs-agent-core';
3
+ import { A as AgentBackend, U as UploadAttachmentOptions, H as HttpErrorListener, a as AttachmentUploadStrategy } from './client-D4ZSbZJ8.js';
4
+ export { b as AgentBackendUnsupportedError, c as AgentClient, d as AgentClientOptions, e as AgentConnection, f as AgentHttpError, g as AgentRequestError, C as CancelResult, h as ChatStreamRequest, i as ChatStreamResponse, M as MessageFeedbackInput, R as ResumeStreamRequest, T as ThreadPatch, r as requireBackendMethod } from './client-D4ZSbZJ8.js';
5
+ import { MessageAttachment, AgentClientConfig, AgentCatalogEntry, ModelCatalogEntry, ModelCatalogView, ModelCatalogLock, QuotaReport, QuotaWindow, QuotaBlock, QuotaWarning, MessageFeedback, MessageFeedbackValue, ThreadSummary, StoredMessage, ToolCatalogEntry } from '@dudousxd/nestjs-agent-core';
6
6
  export { ElicitationInput, ElicitationInputType, validateElicitationAnswer as validateAnswer, validateElicitationValue as validateAnswerValue } from '@dudousxd/nestjs-agent-core';
7
7
  import * as React from 'react';
8
8
  import React__default, { ReactNode, Context } from 'react';
9
- import { o as GenuiProviderValue, T as TranscriptUiBlock, A as ApproveOptions, t as TranscriptBlock, U as UsageSummary, v as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, w as ToolCatalog, x as AnyToolUIPart, y as TranscriptFile } from './generative-ui-9AJNVKBZ.js';
10
- export { z as ApprovalBlockOptions, B as BuildBlocksOptions, D as CoercibleQuestion, E as DescribeToolCallOptions, F as ElicitationBlockOptions, H as GroupToolActivityOptions, I as RawAnswer, J as ResolvedReading, K as ResolvedResultView, L as RetrievedPassage, S as SettleAction, N as ToolActivityGroup, O as ToolCallDescription, P as ToolCallState, Q as ToolCallStatus, V as TranscriptApproval, W as TranscriptApprovalStatus, X as TranscriptElicitationBlock, Y as TranscriptElicitationOutcome, Z as TranscriptFilesBlock, _ as TranscriptQuestion, $ as TranscriptQuestionOption, a0 as TranscriptReasoningBlock, a1 as TranscriptSettleState, a2 as TranscriptSource, a3 as TranscriptSourcesBlock, a4 as TranscriptTextBlock, a5 as TranscriptToolBlock, a6 as TranscriptToolCall, a7 as buildTranscriptBlocks, a8 as coerceAnswer, a9 as correctedCallIds, aa as describeTimestamp, ab as describeToolCall, ac as describeUsage, ad as extractMessageText, ae as fillTemplate, af as formatRelativeTime, ag as groupToolActivity, ah as inferResultView, ai as isActionCall, aj as phraseFor, ak as readPath, al as resolveResultView, am as toolCallState, an as toolCatalogFrom } from './generative-ui-9AJNVKBZ.js';
9
+ import { o as GenuiProviderValue, T as TranscriptUiBlock, A as ApproveOptions, t as TranscriptBlock, U as UsageSummary, v as TimestampInfo, C as ChatStatus, M as MessageUsageInfo, w as ToolCatalog, x as AnyToolUIPart, y as TranscriptFile } from './generative-ui-BejHxxbR.js';
10
+ export { z as ApprovalBlockOptions, B as BuildBlocksOptions, D as CoercibleQuestion, E as DescribeToolCallOptions, F as ElicitationBlockOptions, H as GroupToolActivityOptions, I as RawAnswer, J as ResolvedReading, K as ResolvedResultView, L as RetrievedPassage, S as SettleAction, N as ToolActivityGroup, O as ToolCallDescription, P as ToolCallState, Q as ToolCallStatus, V as TranscriptApproval, W as TranscriptApprovalStatus, X as TranscriptElicitationBlock, Y as TranscriptElicitationOutcome, Z as TranscriptFilesBlock, _ as TranscriptQuestion, $ as TranscriptQuestionOption, a0 as TranscriptReasoningBlock, a1 as TranscriptSettleState, a2 as TranscriptSource, a3 as TranscriptSourcesBlock, a4 as TranscriptTextBlock, a5 as TranscriptToolBlock, a6 as TranscriptToolCall, a7 as buildTranscriptBlocks, a8 as coerceAnswer, a9 as correctedCallIds, aa as describeTimestamp, ab as describeToolCall, ac as describeUsage, ad as extractMessageText, ae as fillTemplate, af as formatRelativeTime, ag as groupToolActivity, ah as inferResultView, ai as isActionCall, aj as phraseFor, ak as readPath, al as resolveResultView, am as toolCallState, an as toolCatalogFrom } from './generative-ui-BejHxxbR.js';
11
11
 
12
12
  /** Identity surfaced by the backend's `meta` SSE frame / response headers. */
13
13
  interface AgentStreamMeta {
@@ -329,6 +329,12 @@ interface AgentProviderProps {
329
329
  credentials?: RequestCredentials;
330
330
  /** Injectable for tests / non-browser runtimes. */
331
331
  fetch?: typeof fetch;
332
+ /**
333
+ * Every error answer of the built-in client (an `AgentHttpError`, or a `MediaUploadError` from
334
+ * `mediaAttachments()`), right before it is thrown — for app-wide reactions such as "401 → sign
335
+ * in again". Read at call time, so it may change between renders.
336
+ */
337
+ onHttpError?: HttpErrorListener;
332
338
  /** Attachment uploads of the built-in client. */
333
339
  attachments?: {
334
340
  /** e.g. `mediaAttachments()` from `@dudousxd/nestjs-agent-react/media`. */
@@ -354,7 +360,7 @@ interface AgentProviderProps {
354
360
  *
355
361
  * Without a provider every hook shares one same-origin client on `/agent`.
356
362
  */
357
- declare function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, attachments, genui, children, }: AgentProviderProps): React.JSX.Element;
363
+ declare function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, onHttpError, attachments, genui, children, }: AgentProviderProps): React.JSX.Element;
358
364
  /**
359
365
  * The backend a hook talks to: `own` when given, else the enclosing {@link AgentProvider}'s, else a
360
366
  * shared same-origin client on `/agent`. For your own hooks over the same connection.
@@ -421,6 +427,11 @@ interface ModelsState {
421
427
  models: ModelOption[];
422
428
  /** The model a turn runs on when none is picked, or `null` when the provider decides. */
423
429
  defaultModel: string | null;
430
+ /**
431
+ * The agent always runs on one model (`{ model, reason? }`), or `null`. A picker shows it
432
+ * read-only: the server runs every turn on it and refuses any other.
433
+ */
434
+ locked: ModelCatalogLock | null;
424
435
  /** The entry for `id`, or `undefined`. */
425
436
  find: (id: string | null | undefined) => ModelOption | undefined;
426
437
  isLoading: boolean;
@@ -430,8 +441,8 @@ interface ModelsState {
430
441
  /**
431
442
  * The models this caller may pick (`GET <base>/models?agent=`), with badges and availability — the
432
443
  * data behind a model picker. Headless: render the options however you like, then send the pick
433
- * as `useAgentChat({ model })`, `sendMessage(msg, { body: { model } })`, or pin it on the thread
434
- * with `chat.setThreadModel(id)`.
444
+ * as `useAgentChat({ model })` or `sendMessage(msg, { body: { model } })` (that turn only), or
445
+ * pin it on the thread with `chat.models.pinToThread(id)`.
435
446
  */
436
447
  declare function useModels(options?: UseModelsOptions): ModelsState;
437
448
 
@@ -452,6 +463,11 @@ interface QuotaState {
452
463
  month: QuotaWindow | undefined;
453
464
  /** The window that blocks sends, or `null` — pass it to `useAgentChat({ blocked })`. */
454
465
  blocked: QuotaBlock | null;
466
+ /**
467
+ * The soft limit: the fullest window past its `warnAt` (`{ period, ratio, reason? }`), or `null`.
468
+ * The server's `warning`, else derived from the windows; never set while `blocked`.
469
+ */
470
+ warning: QuotaWarning | null;
455
471
  isLoading: boolean;
456
472
  error: Error | null;
457
473
  refresh: () => Promise<void>;
@@ -723,10 +739,14 @@ interface MessageActionInput {
723
739
  interface AnswerInput {
724
740
  toolCallId: string;
725
741
  answers?: Record<string, string[]>;
742
+ /** The surface the answer came through; the server records `'web'` when omitted. */
743
+ via?: string;
726
744
  }
727
745
  /** Declining a parked question set. */
728
746
  interface SkipInput {
729
747
  toolCallId: string;
748
+ /** The surface the skip came through; the server records `'web'` when omitted. */
749
+ via?: string;
730
750
  }
731
751
  /** Approving a tool call parked on a human. */
732
752
  interface ApproveInput extends ApproveOptions {
@@ -1425,7 +1445,9 @@ interface UseAgentChatOptions<B extends AgentBackend = AgentBackend> {
1425
1445
  /**
1426
1446
  * The model every turn runs on, controlled by you. Omitted → `chat.models.selected` (what
1427
1447
  * `chat.models.select(id)` picked), else the thread's pinned model, else the server default. A
1428
- * single send can still override it with `sendMessage(msg, { body: { model } })`.
1448
+ * single send can still override it with `sendMessage(msg, { body: { model } })`. Sent as the
1449
+ * turn's `model`, which the server applies to that turn only — pinning a model on the thread is
1450
+ * `chat.models.pinToThread(id)`.
1429
1451
  */
1430
1452
  model?: string;
1431
1453
  /**
@@ -1499,21 +1521,41 @@ interface ChatBackground {
1499
1521
  /** Re-read the thread now, instead of waiting for the next poll. */
1500
1522
  refresh: () => Promise<void>;
1501
1523
  }
1502
- /** The chat's model picker state. Loaded the first time `list`/`providers` is read. */
1524
+ /**
1525
+ * The chat's model picker state. Loaded the first time `list`/`providers`/`defaultModel`/`locked`
1526
+ * is read.
1527
+ *
1528
+ * Two different choices: `select(id)` picks the model this chat's following sends name — each send
1529
+ * carries it as `model`, which the server applies to that turn only and never stores; the pick is
1530
+ * this conversation's, so switching threads drops it. `pinToThread(id)` stores a model on the
1531
+ * thread (`PATCH threads/:id { model }`), which every later turn without a `model` of its own runs
1532
+ * on, across reloads and devices.
1533
+ */
1503
1534
  interface ChatModels {
1504
1535
  /** Every model the caller may pick, flattened (`[]` until loaded). */
1505
1536
  readonly list: ModelOption[];
1506
1537
  /** The same, grouped by provider. */
1507
1538
  readonly providers: ModelsState['providers'];
1508
- /** What the next turn runs on: the `model` option, the pick, the thread's pin, else the default. */
1539
+ /**
1540
+ * What the next turn runs on: the lock, the `model` option, the pick, the thread's pin, else the
1541
+ * default.
1542
+ */
1509
1543
  selected: string | null;
1544
+ /** The model pinned on the thread (`null` when none, or before the thread is read). */
1545
+ pinned: string | null;
1510
1546
  /** The catalog's default — what a turn runs on when nothing is picked or pinned (`null` until loaded). */
1511
1547
  readonly defaultModel: string | null;
1512
- /** Run the following turns on `id` (sent as the body's `model`). */
1548
+ /**
1549
+ * The agent always runs on one model (`{ model, reason? }`), or `null`. While locked, `select`
1550
+ * does nothing and `selected` is the locked model.
1551
+ */
1552
+ readonly locked: ModelsState['locked'];
1553
+ /** Run this chat's following sends on `id` — each send's `model`, that turn only. */
1513
1554
  select: (id: string) => void;
1514
1555
  /**
1515
1556
  * Pin `id` on the thread (`null` unpins) — every later turn without its own `model` runs on it,
1516
- * across reloads. On a chat with no thread yet, the pin lands when the first send creates one.
1557
+ * across reloads. Replaces the pick, so the next send runs on the pin. On a chat with no thread
1558
+ * yet, the pin lands when the first send creates one.
1517
1559
  */
1518
1560
  pinToThread: (id: string | null) => Promise<void>;
1519
1561
  isLoading: boolean;
@@ -1598,8 +1640,8 @@ declare function useAgentChat<B extends AgentBackend = AgentBackend>(options?: U
1598
1640
  cancel: () => Promise<void>;
1599
1641
  approve: ({ toolCallId, remember, via }: ApproveInput) => Promise<void>;
1600
1642
  reject: ({ toolCallId, reason, via }: RejectInput) => Promise<void>;
1601
- answer: ({ toolCallId, answers }: AnswerInput) => Promise<void>;
1602
- skip: ({ toolCallId }: SkipInput) => Promise<void>;
1643
+ answer: ({ toolCallId, answers, via }: AnswerInput) => Promise<void>;
1644
+ skip: ({ toolCallId, via }: SkipInput) => Promise<void>;
1603
1645
  regenerate: (_input?: Partial<MessageActionInput>) => void;
1604
1646
  fork: ({ messageId, threadId, }: MessageActionInput & {
1605
1647
  threadId?: string;
@@ -1626,4 +1668,4 @@ declare class QuotaBlockedError extends Error {
1626
1668
  constructor(block: QuotaBlock);
1627
1669
  }
1628
1670
 
1629
- export { AgentBackend, AgentChatTransport, type AgentChatTransportOptions, type AgentConfigState, type AgentMessageMetadata, AgentProvider, type AgentProviderProps, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, type AmbientRenderUi, AmbientRenderUiContext, type AnswerInput, AnyToolUIPart, type ApprovalCountdown, type ApproveInput, ApproveOptions, type AttachmentRejection, AttachmentUploadStrategy, type AttachmentsState, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatTranscript, type ClipboardLikeEvent, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DragLikeEvent, type EditSubmitInput, type MessageActionInput, 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 ReconnectOptions, type RejectInput, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SkipInput, type SpeechLanguage, type SpeechRecognitionHook, type StagedAttachment, type StagedAttachmentStatus, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, 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, UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentConfigOptions, 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, storedMessageToUiMessage, storedThreadToUiMessages, useAgentBackend, useAgentChat, useAgentConfig, useAgents, useAmbientRenderUi, useApprovalCountdown, useAttachments, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useQuota, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
1671
+ export { AgentBackend, AgentChatTransport, type AgentChatTransportOptions, type AgentConfigState, type AgentMessageMetadata, AgentProvider, type AgentProviderProps, type AgentStreamMeta, type AgentsState, type AggregatedTurnUsage, type AmbientRenderUi, AmbientRenderUiContext, type AnswerInput, AnyToolUIPart, type ApprovalCountdown, type ApproveInput, ApproveOptions, type AttachmentRejection, AttachmentUploadStrategy, type AttachmentsState, type AutocompleteInputProps, type AutocompleteItem, type AutocompleteListboxProps, type AutocompleteOptionProps, type AutocompleteSource, type BackgroundRun, type ChatBackground, ChatInput, type ChatInputProps, ChatStatus, type ChatTranscript, type ClipboardLikeEvent, type CompletionEdit, type ComposerAutocomplete, DEFAULT_SPEECH_LANG, type DragLikeEvent, type EditSubmitInput, HttpErrorListener, type MessageActionInput, 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 ReconnectOptions, type RejectInput, type RenderFilesFn, type RenderReasoningFn, type RenderTextFn, type RenderToolGroupFn, type RenderToolPartFn, type RenderUiFn, SPEECH_LANGUAGES, type SkillSuggestionData, type SkillsSourceOptions, type SkipInput, type SpeechLanguage, type SpeechRecognitionHook, type StagedAttachment, type StagedAttachmentStatus, type StickToBottom, type StickToBottomOptions, type StoredTurnMetadata, type StreamConnectionState, 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, UploadAttachmentOptions, UsageSummary, type UseAgentChatOptions, type UseAgentConfigOptions, 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, storedMessageToUiMessage, storedThreadToUiMessages, useAgentBackend, useAgentChat, useAgentConfig, useAgents, useAmbientRenderUi, useApprovalCountdown, useAttachments, useChatTranscript, useComposerAutocomplete, useElapsed, useMessageFeedback, useModels, useQuota, useSpeechRecognition, useStickToBottom, useThreads, useToolCatalog, useTranscriptItem };
package/dist/index.js CHANGED
@@ -1,17 +1,82 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
3
 
4
+ // src/http-error.ts
5
+ function readErrorAnswer(text) {
6
+ if (text == null || text === "") return {
7
+ body: void 0,
8
+ message: void 0,
9
+ code: void 0
10
+ };
11
+ let body = text;
12
+ try {
13
+ body = JSON.parse(text);
14
+ } catch {
15
+ return {
16
+ body: text,
17
+ message: void 0,
18
+ code: void 0
19
+ };
20
+ }
21
+ if (body === null || typeof body !== "object") return {
22
+ body,
23
+ message: void 0,
24
+ code: void 0
25
+ };
26
+ const record = body;
27
+ const message = typeof record.message === "string" && record.message !== "" ? record.message : Array.isArray(record.message) && record.message.length > 0 && record.message.every((each) => typeof each === "string") ? record.message.join("; ") : void 0;
28
+ const code = typeof record.code === "string" && record.code !== "" ? record.code : void 0;
29
+ return {
30
+ body,
31
+ message,
32
+ code
33
+ };
34
+ }
35
+ __name(readErrorAnswer, "readErrorAnswer");
36
+ async function readErrorResponse(response) {
37
+ let text;
38
+ try {
39
+ text = await response.text();
40
+ } catch {
41
+ text = void 0;
42
+ }
43
+ return readErrorAnswer(text);
44
+ }
45
+ __name(readErrorResponse, "readErrorResponse");
46
+ function reportHttpError(listener, error) {
47
+ if (listener === void 0) return;
48
+ try {
49
+ listener(error);
50
+ } catch {
51
+ }
52
+ }
53
+ __name(reportHttpError, "reportHttpError");
54
+
4
55
  // src/client.ts
5
- var AgentHttpError = class extends Error {
56
+ var AgentHttpError = class _AgentHttpError extends Error {
6
57
  static {
7
58
  __name(this, "AgentHttpError");
8
59
  }
9
60
  status;
10
61
  method;
11
62
  path;
12
- constructor(status, method, path, statusText) {
13
- super(`Agent request failed: ${method} ${path} \u2192 ${status} ${statusText}`), this.status = status, this.method = method, this.path = path;
63
+ /** The answer's body: parsed JSON, else its text; `undefined` when empty. */
64
+ body;
65
+ /** The body's `code` (`quota_exceeded`, …), when the server sent one. */
66
+ code;
67
+ constructor(status, method, path, statusText, answer = {
68
+ body: void 0,
69
+ message: void 0,
70
+ code: void 0
71
+ }) {
72
+ super(answer.message ?? `Agent request failed: ${method} ${path} \u2192 ${status} ${statusText}`), this.status = status, this.method = method, this.path = path;
14
73
  this.name = "AgentHttpError";
74
+ this.body = answer.body;
75
+ this.code = answer.code;
76
+ }
77
+ /** Read a refused `response`'s body into an error. */
78
+ static async from(response, method, path) {
79
+ return new _AgentHttpError(response.status, method, path, response.statusText, await readErrorResponse(response));
15
80
  }
16
81
  };
17
82
  function normalizeAgentPath(path) {
@@ -46,7 +111,7 @@ var AgentClient = class {
46
111
  } : {}
47
112
  });
48
113
  if (!response.ok || !response.body) {
49
- throw new AgentHttpError(response.status, "POST", `${this.agentPath()}/chat`, response.statusText);
114
+ throw await this.failure(response, "POST", `${this.agentPath()}/chat`);
50
115
  }
51
116
  return streamResponse(response);
52
117
  }
@@ -73,7 +138,7 @@ var AgentClient = class {
73
138
  return null;
74
139
  }
75
140
  if (!response.ok || !response.body) {
76
- throw new AgentHttpError(response.status, "GET", `${this.agentPath()}${path}`, response.statusText);
141
+ throw await this.failure(response, "GET", `${this.agentPath()}${path}`);
77
142
  }
78
143
  return streamResponse(response);
79
144
  }
@@ -166,7 +231,9 @@ var AgentClient = class {
166
231
  };
167
232
  xhr.onload = () => {
168
233
  if (xhr.status < 200 || xhr.status >= 300) {
169
- reject(new AgentHttpError(xhr.status, "POST", `${this.agentPath()}/attachments`, xhr.statusText));
234
+ const error = new AgentHttpError(xhr.status, "POST", `${this.agentPath()}/attachments`, xhr.statusText, readErrorAnswer(xhr.responseText));
235
+ reportHttpError(this.options.onHttpError, error);
236
+ reject(error);
170
237
  return;
171
238
  }
172
239
  onProgress?.(1);
@@ -229,6 +296,7 @@ var AgentClient = class {
229
296
  * out takes the pre-picked default the request carried, resolved server-side against the request
230
297
  * the run already holds. Omit the whole object and the user has confirmed every pre-picked
231
298
  * answer — which is the point of the surface, so it is a valid submission rather than a blank.
299
+ * `via` names the surface the answer came through (the server records `'web'` when omitted).
232
300
  */
233
301
  answerToolCall(input) {
234
302
  return this.request("POST", "/tool-call/answer", input);
@@ -251,7 +319,10 @@ var AgentClient = class {
251
319
  path: this.agentPath(),
252
320
  headers: /* @__PURE__ */ __name(() => this.resolveHeaders(), "headers"),
253
321
  fetch: this.fetchImpl(),
254
- ...this.credentials()
322
+ ...this.credentials(),
323
+ ...this.options.onHttpError !== void 0 ? {
324
+ onHttpError: this.options.onHttpError
325
+ } : {}
255
326
  };
256
327
  }
257
328
  baseUrl() {
@@ -294,9 +365,15 @@ var AgentClient = class {
294
365
  });
295
366
  return this.handleResponse(response, method, path);
296
367
  }
368
+ /** The error for a refused `response`, already reported to `onHttpError`. */
369
+ async failure(response, method, path) {
370
+ const error = await AgentHttpError.from(response, method, path);
371
+ reportHttpError(this.options.onHttpError, error);
372
+ return error;
373
+ }
297
374
  async handleResponse(response, method, path) {
298
375
  if (!response.ok) {
299
- throw new AgentHttpError(response.status, method, path, response.statusText);
376
+ throw await this.failure(response, method, path);
300
377
  }
301
378
  if (response.status === 204) return void 0;
302
379
  const text = await response.text();
@@ -1651,14 +1728,16 @@ __name(GenerativeUI, "GenerativeUI");
1651
1728
 
1652
1729
  // src/provider.tsx
1653
1730
  var AgentBackendContext = sharedContext("@dudousxd/nestjs-agent-react:agent-backend");
1654
- function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, attachments, genui, children }) {
1731
+ function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credentials, fetch, onHttpError, attachments, genui, children }) {
1655
1732
  const latestHeaders = useRef2({
1656
1733
  headers,
1657
- getHeaders
1734
+ getHeaders,
1735
+ onHttpError
1658
1736
  });
1659
1737
  latestHeaders.current = {
1660
1738
  headers,
1661
- getHeaders
1739
+ getHeaders,
1740
+ onHttpError
1662
1741
  };
1663
1742
  const upload = attachments?.upload;
1664
1743
  const value = useMemo3(() => backend ?? new AgentClient({
@@ -1679,6 +1758,7 @@ function AgentProvider({ backend, baseUrl, path, headers, getHeaders, credential
1679
1758
  upload
1680
1759
  }
1681
1760
  } : {},
1761
+ onHttpError: /* @__PURE__ */ __name((error) => latestHeaders.current.onHttpError?.(error), "onHttpError"),
1682
1762
  getHeaders: /* @__PURE__ */ __name(async () => {
1683
1763
  const current = latestHeaders.current;
1684
1764
  const dynamic = await current.getHeaders?.() ?? {};
@@ -2092,6 +2172,7 @@ function useModels(options = {}) {
2092
2172
  providers,
2093
2173
  models,
2094
2174
  defaultModel: data?.default ?? null,
2175
+ locked: data?.locked ?? null,
2095
2176
  find: /* @__PURE__ */ __name((id) => id == null ? void 0 : byId.get(id), "find"),
2096
2177
  isLoading,
2097
2178
  error,
@@ -2107,6 +2188,7 @@ function useModels(options = {}) {
2107
2188
  __name(useModels, "useModels");
2108
2189
 
2109
2190
  // src/quota/use-quota.ts
2191
+ import { quotaWarning } from "@dudousxd/nestjs-agent-core";
2110
2192
  import { useEffect as useEffect6, useMemo as useMemo7 } from "react";
2111
2193
 
2112
2194
  // src/threads/threads-events.ts
@@ -2162,6 +2244,7 @@ function useQuota(options = {}) {
2162
2244
  day: windows.find((window2) => window2.period === "day"),
2163
2245
  month: windows.find((window2) => window2.period === "month"),
2164
2246
  blocked: data?.blocked ?? null,
2247
+ warning: data === void 0 || data.blocked !== void 0 ? null : data.warning ?? quotaWarning(windows) ?? null,
2165
2248
  isLoading,
2166
2249
  error,
2167
2250
  refresh
@@ -3250,7 +3333,9 @@ function readElicitationOutcome(part) {
3250
3333
  answers,
3251
3334
  skipped: output.skipped,
3252
3335
  defaulted: Array.isArray(output.defaulted) ? output.defaulted.filter((id) => typeof id === "string") : [],
3253
- summary: typeof output.summary === "string" ? output.summary : null
3336
+ summary: typeof output.summary === "string" ? output.summary : null,
3337
+ answeredBy: typeof output.answeredBy === "string" ? output.answeredBy : null,
3338
+ answeredVia: typeof output.answeredVia === "string" ? output.answeredVia : null
3254
3339
  };
3255
3340
  }
3256
3341
  __name(readElicitationOutcome, "readElicitationOutcome");
@@ -5200,6 +5285,7 @@ function useAgentChat(options = {}) {
5200
5285
  const [pickedModel, setPickedModel] = useState15(void 0);
5201
5286
  const pickedModelRef = useRef12(pickedModel);
5202
5287
  pickedModelRef.current = pickedModel;
5288
+ const lockedRef = useRef12(false);
5203
5289
  const pendingPin = useRef12(void 0);
5204
5290
  const regenerateNext = useRef12(false);
5205
5291
  const currentThreadId = useCallback11(() => latest.current.threadId ?? createdThreadId.current, []);
@@ -5247,7 +5333,7 @@ function useAgentChat(options = {}) {
5247
5333
  const regenerate2 = regenerateNext.current;
5248
5334
  regenerateNext.current = false;
5249
5335
  const threadId = currentThreadId();
5250
- const model = current.model ?? pickedModelRef.current;
5336
+ const model = current.model ?? (lockedRef.current ? void 0 : pickedModelRef.current);
5251
5337
  return {
5252
5338
  // Read per send: a host that switches agents before the first message (a picker on a
5253
5339
  // new chat) sends the one picked now, not the one this chat mounted with.
@@ -5341,6 +5427,7 @@ function useAgentChat(options = {}) {
5341
5427
  setRunId(void 0);
5342
5428
  setActiveRunId(null);
5343
5429
  setThreadModel(null);
5430
+ setPickedModel(void 0);
5344
5431
  setBackgroundRuns([]);
5345
5432
  setHistoryError(null);
5346
5433
  autoResumeRunIdRef.current = void 0;
@@ -5505,19 +5592,25 @@ function useAgentChat(options = {}) {
5505
5592
  }, [
5506
5593
  client
5507
5594
  ]);
5508
- const answer = useCallback11(async ({ toolCallId, answers }) => {
5595
+ const answer = useCallback11(async ({ toolCallId, answers, via }) => {
5509
5596
  await requireBackendMethod(client, "answerToolCall")({
5510
5597
  toolCallId,
5511
5598
  ...answers !== void 0 ? {
5512
5599
  answers
5600
+ } : {},
5601
+ ...via !== void 0 ? {
5602
+ via
5513
5603
  } : {}
5514
5604
  });
5515
5605
  }, [
5516
5606
  client
5517
5607
  ]);
5518
- const skip = useCallback11(async ({ toolCallId }) => {
5608
+ const skip = useCallback11(async ({ toolCallId, via }) => {
5519
5609
  await requireBackendMethod(client, "skipToolCall")({
5520
- toolCallId
5610
+ toolCallId,
5611
+ ...via !== void 0 ? {
5612
+ via
5613
+ } : {}
5521
5614
  });
5522
5615
  }, [
5523
5616
  client
@@ -5597,10 +5690,14 @@ function useAgentChat(options = {}) {
5597
5690
  modelsWantedRef.current = true;
5598
5691
  queueMicrotask(() => setModelsWanted(true));
5599
5692
  }, []);
5600
- const selectModel = useCallback11((id) => setPickedModel(id), []);
5693
+ lockedRef.current = catalog.locked !== null;
5694
+ const selectModel = useCallback11((id) => {
5695
+ if (!lockedRef.current) setPickedModel(id);
5696
+ }, []);
5601
5697
  const pinToThread = useCallback11(async (model) => {
5602
5698
  const threadId = currentThreadId();
5603
5699
  setThreadModel(model);
5700
+ setPickedModel(void 0);
5604
5701
  if (threadId === void 0) {
5605
5702
  pendingPin.current = {
5606
5703
  model
@@ -5626,11 +5723,16 @@ function useAgentChat(options = {}) {
5626
5723
  wantModels();
5627
5724
  return catalog.providers;
5628
5725
  },
5629
- selected: options.model ?? pickedModel ?? threadModel ?? catalog.defaultModel ?? null,
5726
+ selected: catalog.locked?.model ?? options.model ?? pickedModel ?? threadModel ?? catalog.defaultModel ?? null,
5727
+ pinned: threadModel,
5630
5728
  get defaultModel() {
5631
5729
  wantModels();
5632
5730
  return catalog.defaultModel;
5633
5731
  },
5732
+ get locked() {
5733
+ wantModels();
5734
+ return catalog.locked;
5735
+ },
5634
5736
  select: selectModel,
5635
5737
  pinToThread,
5636
5738
  isLoading: modelsWanted && catalog.isLoading,