@ykurilov/agent-chat-react 0.0.0-stage → 0.55.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.
Files changed (106) hide show
  1. package/CHANGELOG.md +1670 -0
  2. package/LICENSE +21 -0
  3. package/README.md +128 -2
  4. package/dist/chunk-JZQ7ZOJI.js +6959 -0
  5. package/dist/chunk-JZQ7ZOJI.js.map +1 -0
  6. package/dist/index.js +501 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/panel.js +399 -0
  9. package/dist/panel.js.map +1 -0
  10. package/dist/types/agent-chat-extensions.d.ts +76 -0
  11. package/dist/types/agent-chat.d.ts +103 -0
  12. package/dist/types/agent-panel/agent-panel-hooks.d.ts +14 -0
  13. package/dist/types/agent-panel/agent-panel-provider.d.ts +24 -0
  14. package/dist/types/agent-panel/agent-panel-skin.d.ts +41 -0
  15. package/dist/types/agent-panel/agent-panel.d.ts +13 -0
  16. package/dist/types/agent-panel/index.d.ts +8 -0
  17. package/dist/types/agent-panel/panel-context.d.ts +46 -0
  18. package/dist/types/agent-panel/panel-state.d.ts +12 -0
  19. package/dist/types/answer-editing/answer-editing.d.ts +25 -0
  20. package/dist/types/app-bridge/app-bridge.d.ts +50 -0
  21. package/dist/types/app-bridge/browser-calls.d.ts +24 -0
  22. package/dist/types/app-bridge/create-app-bridge.d.ts +35 -0
  23. package/dist/types/app-bridge/remembered-ids.d.ts +6 -0
  24. package/dist/types/app-bridge/tab-id.d.ts +10 -0
  25. package/dist/types/app-events.d.ts +39 -0
  26. package/dist/types/app-refusal.d.ts +21 -0
  27. package/dist/types/attachments-contract.d.ts +82 -0
  28. package/dist/types/background-tasks/use-background-tasks.d.ts +53 -0
  29. package/dist/types/chat-access.d.ts +33 -0
  30. package/dist/types/chat-list/active-chat-memory.d.ts +5 -0
  31. package/dist/types/chat-list/chat-list-client.d.ts +35 -0
  32. package/dist/types/chat-list/chat-list-skin.d.ts +63 -0
  33. package/dist/types/chat-list/chat-workspace.d.ts +17 -0
  34. package/dist/types/chat-list/use-chat-list-view.d.ts +12 -0
  35. package/dist/types/chat-list/use-chat-list.d.ts +47 -0
  36. package/dist/types/chat-list/use-workspace-list-sync.d.ts +7 -0
  37. package/dist/types/chat-state/chat-state.d.ts +27 -0
  38. package/dist/types/chat-types.d.ts +85 -0
  39. package/dist/types/chat-watch/chat-watch.d.ts +57 -0
  40. package/dist/types/close-stopped-tool-calls.d.ts +8 -0
  41. package/dist/types/composer-actions.d.ts +29 -0
  42. package/dist/types/diagrams/diagram-renders.d.ts +16 -0
  43. package/dist/types/diagrams/mermaid-blocks.d.ts +18 -0
  44. package/dist/types/diagrams/unique-svg-ids.d.ts +6 -0
  45. package/dist/types/diagrams/use-diagram-blocks.d.ts +25 -0
  46. package/dist/types/diagrams/use-diagram-colors.d.ts +8 -0
  47. package/dist/types/dictation-field.d.ts +19 -0
  48. package/dist/types/expanded-parts.d.ts +11 -0
  49. package/dist/types/feed-announcement.d.ts +7 -0
  50. package/dist/types/helpers/helper-call.d.ts +57 -0
  51. package/dist/types/index.d.ts +53 -0
  52. package/dist/types/labels.d.ts +468 -0
  53. package/dist/types/live-demos/answer-fences.d.ts +25 -0
  54. package/dist/types/live-demos/live-demo-document.d.ts +42 -0
  55. package/dist/types/live-demos/live-demo-frame.d.ts +14 -0
  56. package/dist/types/live-demos/use-live-demo-blocks.d.ts +18 -0
  57. package/dist/types/liveness/connection-errors.d.ts +15 -0
  58. package/dist/types/liveness/reconnect-attempts.d.ts +14 -0
  59. package/dist/types/liveness/request-deadline.d.ts +16 -0
  60. package/dist/types/liveness/silence-watchdog.d.ts +21 -0
  61. package/dist/types/media-viewer/answer-file-images.d.ts +18 -0
  62. package/dist/types/media-viewer/collect-viewer-items.d.ts +16 -0
  63. package/dist/types/media-viewer/generated-images.d.ts +18 -0
  64. package/dist/types/media-viewer/media-viewer-types.d.ts +17 -0
  65. package/dist/types/media-viewer/open-attachments.d.ts +9 -0
  66. package/dist/types/media-viewer/use-media-viewer.d.ts +23 -0
  67. package/dist/types/memory/agent-memory.d.ts +13 -0
  68. package/dist/types/memory/memory-client.d.ts +19 -0
  69. package/dist/types/memory/memory-skin.d.ts +103 -0
  70. package/dist/types/memory/memory-tree.d.ts +17 -0
  71. package/dist/types/memory/memory-types.d.ts +77 -0
  72. package/dist/types/memory/use-memory-notes.d.ts +23 -0
  73. package/dist/types/message-actions.d.ts +45 -0
  74. package/dist/types/message-feed.d.ts +27 -0
  75. package/dist/types/notices/agent-notices.d.ts +40 -0
  76. package/dist/types/pause.d.ts +2 -0
  77. package/dist/types/server-refusal.d.ts +16 -0
  78. package/dist/types/skin-contract.d.ts +673 -0
  79. package/dist/types/spending-status.d.ts +76 -0
  80. package/dist/types/steering/corrections.d.ts +19 -0
  81. package/dist/types/step-reset.d.ts +15 -0
  82. package/dist/types/subject-chat/subject-chat-loading.d.ts +8 -0
  83. package/dist/types/subject-chat/use-subject-chat-id.d.ts +21 -0
  84. package/dist/types/thinking-status/thinking-status.d.ts +33 -0
  85. package/dist/types/turn-finished.d.ts +14 -0
  86. package/dist/types/use-agent-chat.d.ts +228 -0
  87. package/dist/types/use-model-choice.d.ts +31 -0
  88. package/dist/types/use-voice-dialog.d.ts +18 -0
  89. package/dist/types/use-voice-dictation.d.ts +17 -0
  90. package/dist/types/voice-dialog.d.ts +103 -0
  91. package/dist/types/voice-input.d.ts +47 -0
  92. package/dist/types/voice-tags.d.ts +18 -0
  93. package/dist/types/voice-turn.d.ts +11 -0
  94. package/dist/types/widgets/custom-widget-guard.d.ts +21 -0
  95. package/dist/types/widgets/form-check.d.ts +29 -0
  96. package/dist/types/widgets/suggested-replies.d.ts +6 -0
  97. package/dist/types/widgets/use-widget-answer.d.ts +54 -0
  98. package/dist/types/widgets/widget-answer-keys.d.ts +14 -0
  99. package/dist/types/widgets/widget-messages.d.ts +14 -0
  100. package/dist/types/widgets/widget-part.d.ts +17 -0
  101. package/dist/types/widgets/widget-view.d.ts +50 -0
  102. package/dist/types/without-markdown.d.ts +1 -0
  103. package/dist/types/work-view/step-phrases.d.ts +37 -0
  104. package/dist/types/work-view/work-layout.d.ts +57 -0
  105. package/dist/types/work-view/work-steps-part.d.ts +15 -0
  106. package/package.json +53 -3
@@ -0,0 +1,53 @@
1
+ import type { TaskStatusView } from "../skin-contract.js";
2
+ /** Задача, как её отдаёт `GET {chat}/tasks`. */
3
+ export interface BackgroundTask {
4
+ id: string;
5
+ title: string;
6
+ kind: string;
7
+ name: string;
8
+ status: TaskStatusView;
9
+ startedAt: string;
10
+ finishedAt?: string;
11
+ progress?: unknown;
12
+ }
13
+ /** Решение человека по задаче, которая ждёт подтверждения. */
14
+ export type TaskApprovalDecision = "allow" | "deny";
15
+ export type TaskDecisionState = {
16
+ state: "pending";
17
+ } | {
18
+ state: "failed";
19
+ } | {
20
+ state: "decided";
21
+ decision: TaskApprovalDecision;
22
+ };
23
+ export interface UseBackgroundTasksOptions {
24
+ /** Адрес чата: `{api}/{chatId}`. */
25
+ chatUrl: string;
26
+ /** Скин показывает карточки или плашки, история загружена. Нет — задачи не запрашиваются. */
27
+ enabled: boolean;
28
+ /** Растёт, когда список мог измениться (подписка открылась, пришло `tasks-changed`): список перечитывается. */
29
+ version: number;
30
+ fetch?: (url: string, init?: RequestInit) => Promise<Response>;
31
+ }
32
+ export interface BackgroundTasks {
33
+ /** Задачи чата; пусто, пока не загружены или у сервера фона нет. */
34
+ tasks: readonly BackgroundTask[];
35
+ /** Текущее время для «сколько идёт»: тикает раз в секунду, пока есть живые задачи. */
36
+ now: number;
37
+ cancel: (taskId: string) => Promise<void>;
38
+ cancelingIds: ReadonlySet<string>;
39
+ /** Ответ на вопрос `approvalId` задачи: ответ на вопрос, который задача уже не задаёт, сервер не примет. */
40
+ decide: (taskId: string, approvalId: string, decision: TaskApprovalDecision) => Promise<void>;
41
+ /** Решения по номеру вопроса: у одной задачи вопросов бывает несколько. */
42
+ decisions: Readonly<Record<string, TaskDecisionState>>;
43
+ }
44
+ export declare const isLiveTask: (task: BackgroundTask) => boolean;
45
+ /** Номер вопроса, ответа на который задача ждёт сейчас (`progress.pendingApproval.approvalId`). */
46
+ export declare function pendingApprovalIdOf(task: BackgroundTask): string | undefined;
47
+ /** Сколько идёт (или шла) задача к моменту `now`. */
48
+ export declare function taskElapsedMs(task: BackgroundTask, now: number): number;
49
+ /**
50
+ * Фоновые задачи чата: список с сервера, отмена и решение по подтверждению. Сервер без фона (404) — задач нет,
51
+ * повторных запросов тоже.
52
+ */
53
+ export declare function useBackgroundTasks({ chatUrl, enabled, version, fetch: customFetch }: UseBackgroundTasksOptions): BackgroundTasks;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Права человека в чате и закрытие чата — копия договора ядра (`ChatCapabilities`, `ChatClosure`): пакет экрана от
3
+ * ядра не зависит. Права приходят с историей (`capabilities`), закрытие — в `chat.closed` истории, в отказе 409
4
+ * `chat_closed`, куском потока `data-chat-closed` и событиями наблюдения `chat-closed`/`chat-reopened`.
5
+ */
6
+ export type ChatCapability = "edit" | "regenerate" | "retry" | "branches" | "modelChoice" | "answerEditing" | "chatList" | "compact" | "attachments" | "voice" | "reasoning" | "toolDetails" | "steer" | "modelDetails";
7
+ /**
8
+ * `modelDetails` — модель, провайдер, расход и владелец в истории и потоке; запрет выключает и выбор модели, меню моделей
9
+ * экран тогда не спрашивает. В типе необязательно (нет — `true`): свой литерал прав без него остаётся верным.
10
+ */
11
+ export type ChatCapabilities = Record<Exclude<ChatCapability, "modelDetails">, boolean> & {
12
+ modelDetails?: boolean;
13
+ };
14
+ /** Почему чат закрыт: код для программы, текст для человека. */
15
+ export interface ChatClosure {
16
+ code: string;
17
+ message: string;
18
+ }
19
+ /** Что можно в открытом чате и закрыт ли он. */
20
+ export interface ChatAccess {
21
+ capabilities: ChatCapabilities;
22
+ /** `null` — чат открыт. */
23
+ closed: ChatClosure | null;
24
+ }
25
+ /** Транзитный кусок потока ответа: инструмент закрыл чат. */
26
+ export declare const CHAT_CLOSED_PART_TYPE = "data-chat-closed";
27
+ /** Всё разрешено: сервер до 0.27 прав не присылает. */
28
+ export declare const ALL_CAPABILITIES: Required<ChatCapabilities>;
29
+ /** Права из ответа сервера: пропущенное и не булево — разрешено. */
30
+ export declare function capabilitiesOf(value: unknown): Required<ChatCapabilities>;
31
+ /** Закрытие из ответа сервера; `null` — нет или неверной формы. */
32
+ export declare function closureOf(value: unknown): ChatClosure | null;
33
+ export declare function sameCapabilities(a: ChatCapabilities, b: ChatCapabilities): boolean;
@@ -0,0 +1,5 @@
1
+ /** Ключ, под которым запоминается открытый чат, если приложение не задало свой. */
2
+ export declare const defaultRememberKey: (api: string) => string;
3
+ /** Чат, открытый в прошлый раз в этом браузере (под этим ключом). Хранилище недоступно или пусто — `null`. */
4
+ export declare function readRememberedChat(key: string): string | null;
5
+ export declare function rememberChat(key: string, chatId: string): void;
@@ -0,0 +1,35 @@
1
+ import type { AppRefusal } from "../app-refusal.js";
2
+ import type { ChatClosure } from "../chat-access.js";
3
+ /** Строка списка чатов, как её отдаёт сервер (`GET {api}`). */
4
+ export interface ChatListEntry {
5
+ id: string;
6
+ /** `null` — у чата ещё нет названия. */
7
+ title: string | null;
8
+ createdAt: string;
9
+ updatedAt: string;
10
+ /** Мессенджер, из которого создан чат; нет — чат из веба. */
11
+ origin?: string;
12
+ /** Ключ объекта приложения (урок, заказ): есть у чатов объектов, когда сервер их показывает (`chatList.subjectChats`). */
13
+ subjectKey?: string;
14
+ /** Чат закрыт (`closeChat`): причина кодом и словами; у открытого чата поля нет. Форму проверяет слой поведения. */
15
+ closed?: ChatClosure;
16
+ }
17
+ type Fetch = typeof globalThis.fetch;
18
+ /** Сервер ответил отказом; `status` — код ответа. */
19
+ export declare class ChatListRequestError extends Error {
20
+ readonly status: number;
21
+ constructor(status: number, action: string);
22
+ }
23
+ /** Приложение не дало создать чат (`403 { error: { kind: "chat_creation_refused", code, message } }`). */
24
+ export declare class ChatCreationRefusedError extends Error {
25
+ readonly refusal: AppRefusal;
26
+ constructor(refusal: AppRefusal);
27
+ }
28
+ export declare function fetchChatList(api: string, fetchImpl: Fetch): Promise<ChatListEntry[]>;
29
+ /** Создаёт пустой чат; возвращает его id. */
30
+ export declare function createChatOnServer(api: string, fetchImpl: Fetch): Promise<string>;
31
+ /** Возвращает название, как оно записано на сервере. */
32
+ export declare function renameChatOnServer(api: string, fetchImpl: Fetch, chatId: string, title: string): Promise<string>;
33
+ /** Удаляет чат. Чата уже нет (404) — это тоже успех: человек хотел, чтобы его не было. */
34
+ export declare function deleteChatOnServer(api: string, fetchImpl: Fetch, chatId: string): Promise<void>;
35
+ export {};
@@ -0,0 +1,63 @@
1
+ import type { ChatClosure } from "../chat-access.js";
2
+ import type { ChatOriginView } from "../skin-contract.js";
3
+ import type { ComponentType, ReactNode } from "react";
4
+ /** Строка списка чатов для скина. */
5
+ export interface ChatListItemView {
6
+ id: string;
7
+ /** `null` — у чата ещё нет названия: скин показывает надпись `chatListUntitled`, а в поле переименования ставит пустую строку. */
8
+ title: string | null;
9
+ /** Этот чат открыт. */
10
+ active: boolean;
11
+ /** Чат создан из мессенджера (версия 18): скин ставит пометку. Нет — чат из веба. */
12
+ origin?: ChatOriginView;
13
+ /** Чат закрыт: скин ставит пометку `chatListClosed`, причину (`message`) — подсказкой. Нет — чат открыт. */
14
+ closed?: ChatClosure;
15
+ }
16
+ /** Окно подтверждения удаления. Удалить чат можно только через `onConfirm`. */
17
+ export interface ChatListDeleteRequestView {
18
+ /** Название удаляемого чата. */
19
+ title: string;
20
+ /** Запрос на удаление ушёл, ждём ответа. */
21
+ pending: boolean;
22
+ onConfirm: () => void;
23
+ onCancel: () => void;
24
+ }
25
+ /**
26
+ * Договор скина, версия 7 (расширение «список чатов»; договор чата `ChatSkin` не менялся): только для `ChatWorkspace`.
27
+ * Слой поведения решает, что показать и когда что-то удалять; скин рисует. Надписи компоненты берут из `useChatLabels()`.
28
+ */
29
+ export interface ChatListSkin {
30
+ /**
31
+ * Каркас: список чатов и открытый чат. На широком экране список рядом с чатом; на узком — выезжающая панель
32
+ * (открыта при `listOpen`), а название открытого чата и кнопка «Чаты» всегда на виду.
33
+ */
34
+ ChatWorkspace: ComponentType<{
35
+ /** Нет (версия 20) — у открытого чата запрещено право `chatList`: списка и кнопки «Чаты» не рисовать, только чат. */
36
+ list?: ReactNode;
37
+ /** Открытый чат. */
38
+ children: ReactNode;
39
+ /** Название открытого чата для узкого экрана. */
40
+ activeTitle: string;
41
+ listOpen: boolean;
42
+ onListOpenChange: (open: boolean) => void;
43
+ }>;
44
+ ChatList: ComponentType<{
45
+ /** `loading` — список грузится, `error` — не загрузился (тогда `onRetry`), `ready` — `items` можно рисовать. */
46
+ status: "loading" | "ready" | "error";
47
+ items: ChatListItemView[];
48
+ onSelect: (chatId: string) => void;
49
+ /** «Новый чат». */
50
+ onCreate: () => void;
51
+ /** Новый чат создаётся: кнопку не нажимать повторно. */
52
+ creating: boolean;
53
+ /** Пустое и прежнее название слой поведения отбрасывает сам. */
54
+ onRename: (chatId: string, title: string) => void;
55
+ /** Просит подтверждения; сам ничего не удаляет. */
56
+ onRequestDelete: (chatId: string) => void;
57
+ /** Есть — показать окно подтверждения. */
58
+ deleteRequest?: ChatListDeleteRequestView;
59
+ /** Что пошло не так, готовой надписью (действие не удалось или список не загрузился). */
60
+ error?: string;
61
+ onRetry?: () => void;
62
+ }>;
63
+ }
@@ -0,0 +1,17 @@
1
+ import type { AgentChatProps } from "../agent-chat.js";
2
+ import type { ChatSkin } from "../skin-contract.js";
3
+ import type { ChatListSkin } from "./chat-list-skin.js";
4
+ export interface ChatWorkspaceProps extends Omit<AgentChatProps, "chatId" | "subject" | "skin" | "onBusyChange" | "onChatUnavailable" | "initialDraft"> {
5
+ /** Скин чата плюс скин списка (например, `tandemSkin`). */
6
+ skin: ChatSkin & ChatListSkin;
7
+ /** Какой чат открыть первым, например из адреса страницы. Главнее запомненного; чата нет — «Чат не найден». */
8
+ initialChatId?: string;
9
+ /** Открытый чат сменился (выбор, создание, удаление): например, чтобы поменять адрес страницы. */
10
+ onChatChange?: (chatId: string | null) => void;
11
+ }
12
+ /**
13
+ * Чат со списком чатов рядом: выбрать, создать, переименовать, удалить. Всё видимое рисует скин. У открытого чата
14
+ * запрещено право `chatList` — списка нет, только чат: он не показывается и не обновляется, пока права открытого чата неизвестны
15
+ * (до первой истории) и если запрещён.
16
+ */
17
+ export declare function ChatWorkspace({ skin, initialChatId, onChatChange, onChatAccessChange, ...chatProps }: ChatWorkspaceProps): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { ComponentProps } from "react";
2
+ import type { ChatLabels } from "../labels.js";
3
+ import type { ChatListSkin } from "./chat-list-skin.js";
4
+ import type { ChatListState } from "./use-chat-list.js";
5
+ export type ChatListViewProps = ComponentProps<ChatListSkin["ChatList"]>;
6
+ /**
7
+ * Что получает `skin.ChatList`: строки, действия, подтверждение удаления и ошибка готовой надписью.
8
+ * `onChosen` — чат выбран или создан (например, чтобы закрыть список поверх чата). Общее у `ChatWorkspace` и панели агента.
9
+ */
10
+ export declare function useChatListView(list: ChatListState, onChosen: () => void): ChatListViewProps;
11
+ /** Название открытого чата для шапки; нет названия или чата нет в списке — «Новый чат». */
12
+ export declare function activeChatTitle(list: Pick<ChatListState, "items" | "activeChatId">, labels: ChatLabels): string;
@@ -0,0 +1,47 @@
1
+ import type { AppRefusal } from "../app-refusal.js";
2
+ import type { ChatListEntry } from "./chat-list-client.js";
3
+ export type ChatListStatus = "loading" | "ready" | "error";
4
+ /** Какое действие не удалось; сам список не загрузился — `status: "error"`. */
5
+ export type ChatListActionError = "create" | "rename" | "delete";
6
+ export interface UseChatListOptions {
7
+ /** Адрес обработчика чата, например `/api/chat`. */
8
+ api: string;
9
+ /** Какой чат открыть первым (например, из адреса страницы). Главнее запомненного; чата нет в списке — откроется «Чат не найден». */
10
+ initialChatId?: string;
11
+ /** Свой `fetch` — для тестов и особых сред. */
12
+ fetch?: typeof globalThis.fetch;
13
+ /** Ключ запомненного чата. По умолчанию `agent-chat:active-chat:${api}`; у панели агента свой, на человека. Смена ключа — список загружается заново, прежний открытый чат не переносится. */
14
+ rememberKey?: string;
15
+ /** Приложение не дало создать чат (`chat_creation_refused`): та же весть, что `onTurnRefused` у чата. Текст отказа список показывает сам. */
16
+ onCreateRefused?: (refusal: AppRefusal) => void;
17
+ }
18
+ export interface ChatListState {
19
+ status: ChatListStatus;
20
+ items: ChatListEntry[];
21
+ /** Открытый чат; `null`, пока список грузится или не загрузился. */
22
+ activeChatId: string | null;
23
+ error: ChatListActionError | null;
24
+ /** Отказ приложения, из-за которого `error` — `create`: его слова показываются вместо общего «Не удалось создать чат». */
25
+ creationRefusal: AppRefusal | null;
26
+ creating: boolean;
27
+ /** Чат, удаление которого ждёт подтверждения. Удаляет только `confirmDelete`. */
28
+ deleteRequest: {
29
+ id: string;
30
+ title: string | null;
31
+ } | null;
32
+ deleting: boolean;
33
+ select(chatId: string): void;
34
+ /** Открывает пустой чат (без названия и без сообщений), если он уже есть, иначе создаёт новый. `false` — не вышло (`error` — `create`). */
35
+ create(): Promise<boolean>;
36
+ /** Пустое или прежнее название — ничего не делает. Не вышло — прежнее название возвращается. */
37
+ rename(chatId: string, title: string): Promise<void>;
38
+ requestDelete(chatId: string): void;
39
+ cancelDelete(): void;
40
+ confirmDelete(): Promise<void>;
41
+ /** Тихо обновляет список (название появилось, порядок сменился); отказ не показывается. */
42
+ refresh(): Promise<void>;
43
+ /** Загружает список заново после отказа. */
44
+ reload(): void;
45
+ }
46
+ /** Состояние списка чатов: загрузка, выбор открытого чата, создание, переименование и удаление. Ничего не рисует. */
47
+ export declare function useChatList({ api, initialChatId, fetch: customFetch, rememberKey, onCreateRefused }: UseChatListOptions): ChatListState;
@@ -0,0 +1,7 @@
1
+ import type { ChatListState } from "./use-chat-list.js";
2
+ /**
3
+ * Список чатов следит за открытым чатом: ответ начался или закончился — тихое обновление (порядок и название могли
4
+ * измениться); пока идёт ответ, а названия у чата нет, — опрос раз в секунду. Общее у `ChatWorkspace` и панели агента.
5
+ * `enabled: false` — список не нужен (у чата запрещён `chatList`): ничего не запрашивается.
6
+ */
7
+ export declare function useWorkspaceListSync(list: Pick<ChatListState, "items" | "activeChatId" | "refresh">, busy: boolean, enabled?: boolean): void;
@@ -0,0 +1,27 @@
1
+ /** Состояние чата: значения, записанные инструментами (`model.state`), без служебных ключей SDK. */
2
+ export type ChatStateValues = Record<string, unknown>;
3
+ export declare const APP_STATE_PART_TYPE = "data-app-state";
4
+ /** Свёртка записей состояния показанной ветки по порядку: в записи сначала `unset`, потом `set`. */
5
+ export declare function foldChatState(messages: ReadonlyArray<{
6
+ parts: ReadonlyArray<{
7
+ type: string;
8
+ }>;
9
+ }>): ChatStateValues;
10
+ /** Состояние из события сервера (`state-changed`): объект без служебных ключей; не объект — `null`. */
11
+ export declare function chatStateOfEvent(state: unknown): ChatStateValues | null;
12
+ /** Одинаковые ли состояния: то же значение не перерисовывает экран и не зовёт `onStateChange` повторно. */
13
+ export declare const sameChatState: (a: ChatStateValues, b: ChatStateValues) => boolean;
14
+ export declare const ChatStateContext: import("react").Context<ChatStateValues>;
15
+ /** Публикует состояние чата для `useChatState(chatId)`; возвращает смену значения и снятие с публикации. */
16
+ export declare function publishChatState(chatId: string, values: ChatStateValues): {
17
+ update(values: ChatStateValues): void;
18
+ remove(): void;
19
+ };
20
+ /**
21
+ * Состояние чата показанной ветки, без служебных ключей. Без аргумента — внутри `AgentChat` (компоненты скина, виджеты,
22
+ * свои кнопки): живьём по ходу ответа и после смены ветки; вне `AgentChat` — пустое; с `useAgentChat` — поле
23
+ * `chatState`. С `chatId` — где угодно на странице (панель рядом с чатом): то же состояние, что у `AgentChat` или
24
+ * `useAgentChat` этого чата на странице, с теми же живыми обновлениями и без своих запросов. Чата на странице нет или
25
+ * его история ещё грузится — пустое.
26
+ */
27
+ export declare function useChatState(chatId?: string): ChatStateValues;
@@ -0,0 +1,85 @@
1
+ import type { UIMessage } from "ai";
2
+ /** `awaiting_approval` — агент ждёт, разрешит ли человек вызов инструмента. */
3
+ export type AnswerStatus = "streaming" | "complete" | "stopped" | "error" | "interrupted" | "awaiting_approval";
4
+ export type ChatErrorKind = "overloaded" | "rate_limited" | "insufficient_funds" | "invalid_key" | "context_overflow" | "other";
5
+ /**
6
+ * Что показывает `ErrorNotice`: ошибка ответа или отказ сервера чату целиком. `signed_out` — вход истёк (401),
7
+ * `too_many_turns` — у человека уже идут ответы в других чатах (429), ход не начат; `forbidden_origin` — сервер
8
+ * не признал страницу своей (403): фронт и API на разных адресах, а адреса фронта нет в `allowedOrigins` сервера.
9
+ */
10
+ export type ErrorNoticeKind = ChatErrorKind | "signed_out" | "too_many_turns" | "forbidden_origin";
11
+ /** Уровень рассуждений модели (как в профиле модели ядра). */
12
+ export type ReasoningLevelId = "off" | "on" | "minimal" | "low" | "medium" | "high" | "max";
13
+ /** Решение человека по запросу подтверждения. `always` — разрешить и больше не спрашивать про этот инструмент в этом чате. */
14
+ export type ApprovalDecision = "allow" | "deny" | "always";
15
+ /** Метка сервера в решении «Всегда в этом чате»; часть протокола, слово не менять. */
16
+ export declare const ALWAYS_IN_CHAT = "always-in-chat";
17
+ /** Метка сервера в запросе (`approval.requestReason`): для этого вызова «Всегда в этом чате» предложена; часть протокола, слово не менять. */
18
+ export declare const ALWAYS_OFFERED = "always-offered";
19
+ /**
20
+ * Почему ответ на запрос не принят: нет связи или сбой, лимит расходов, чат занят другим ходом, идут ответы в других чатах,
21
+ * приложение не пустило ход (`refused`: причина словами приложения лежит в `text` рядом с видом).
22
+ */
23
+ export type ApprovalFailureKind = "connection" | "spending_limit" | "busy" | "too_many_turns" | "refused";
24
+ /** Выбор собеседника, каким его хранит и отдаёт сервер. */
25
+ export interface ChatModelChoice {
26
+ modelId: string;
27
+ providerId: string;
28
+ reasoning?: string;
29
+ }
30
+ export interface TokenUsage {
31
+ inputTokens: number;
32
+ cachedInputTokens: number;
33
+ outputTokens: number;
34
+ reasoningTokens: number;
35
+ /** Размер контекста после ответа: вход плюс выход последнего шага. */
36
+ contextTokens?: number;
37
+ /** Есть, если числа «примерно»: прикинуты по длине текста, а не сообщены провайдером. */
38
+ estimated?: true;
39
+ }
40
+ /** Вид звука человека (смех, вздох…); копия закрытого списка ядра: ядро браузеру не нужно. */
41
+ export type VoiceSound = "laughter" | "sigh" | "cough" | "sneeze" | "gasp" | "crying" | "yawn" | "groan";
42
+ /** Отметка обрыва озвучки: человек перебил голосом. `partIndex`/`charOffset` — где оборвалось в тексте, `spokenTail` — хвост озвученного. */
43
+ export interface VoiceCut {
44
+ partIndex: number;
45
+ charOffset: number;
46
+ spokenTail: string;
47
+ }
48
+ export interface ChatMessageMetadata {
49
+ modelId?: string;
50
+ providerId?: string;
51
+ usage?: TokenUsage;
52
+ /** Длительность рассуждений по порядковому номеру части рассуждения в сообщении. */
53
+ reasoningDurationsMs?: Record<string, number>;
54
+ status?: AnswerStatus;
55
+ error?: {
56
+ kind: ChatErrorKind;
57
+ };
58
+ /** Есть, если озвучку ответа оборвало перебивание. */
59
+ voiceCut?: VoiceCut;
60
+ /** Ответ не дошёл до человека (сервер пометил «не доставлено»): модель его не видит. */
61
+ undelivered?: true;
62
+ }
63
+ export type AgentChatMessage = UIMessage<ChatMessageMetadata>;
64
+ /** Запись сжатия истории: сводка заменила для модели сообщения с `fromMessageId` по `throughMessageId`. */
65
+ export interface CompactionMarker {
66
+ id: string;
67
+ fromMessageId: string;
68
+ throughMessageId: string;
69
+ /** Сводка в Markdown. */
70
+ summary: string;
71
+ summaryTokens: number;
72
+ createdAt: string;
73
+ }
74
+ /** Развилка на текущей ветке: сообщение и все его соседи по порядку создания, включая его самого. */
75
+ export interface BranchFork {
76
+ messageId: string;
77
+ siblingIds: string[];
78
+ }
79
+ /**
80
+ * Текст сообщения из частей: абзацы через пустую строку. У ответа голосового хода (`voiceAnswer`) теги голоса вырезаны:
81
+ * человек видит, копирует и слышит диктором только слова. В остальных ответах скобки — обычный текст.
82
+ */
83
+ export declare function messageText(message: AgentChatMessage, { voiceAnswer }?: {
84
+ voiceAnswer?: boolean;
85
+ }): string;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Подписка на события чата: `GET /:chatId/watch` отдаёт поток SSE, пока вкладка открыта.
3
+ * Обрыв или затянувшаяся тишина — переподключение с паузами; адреса нет — подписка заканчивается.
4
+ * Доступ закрыт (401, 403) — повтор через долгую паузу: вход могли восстановить. Вкладка, кроме того, открывает подписку
5
+ * заново после каждого своего хода.
6
+ */
7
+ export type ChatWatchEvent = {
8
+ type: "turn-started";
9
+ messageId: string;
10
+ trigger: string;
11
+ channel: string;
12
+ } | {
13
+ type: "turn-finished";
14
+ messageId?: string;
15
+ } | {
16
+ type: "tasks-changed";
17
+ } | {
18
+ type: "notice-added";
19
+ messageId: string;
20
+ }
21
+ /** Сообщение записано без хода (пачка из мессенджера ждёт тишины, «Стоп» отменил пачку). */
22
+ | {
23
+ type: "message-added";
24
+ messageId: string;
25
+ } | {
26
+ type: "chat-closed";
27
+ closed: {
28
+ code: string;
29
+ message: string;
30
+ };
31
+ } | {
32
+ type: "chat-reopened";
33
+ }
34
+ /** Состояние чата сменилось (ход, смена ветки, правка ответа — в том числе в другой вкладке). */
35
+ | {
36
+ type: "state-changed";
37
+ state: unknown;
38
+ atMessageId: string | null;
39
+ } | {
40
+ type: string;
41
+ [key: string]: unknown;
42
+ };
43
+ export type WatchChatOptions = {
44
+ url: string;
45
+ fetch: (url: string, init?: RequestInit) => Promise<Response>;
46
+ signal: AbortSignal;
47
+ /** Паузы перед повторами по порядку; последняя повторяется. */
48
+ delaysMs: readonly number[];
49
+ /** Пауза перед повтором после 401 или 403. По умолчанию минута. */
50
+ refusedRetryMs?: number;
51
+ /** Сколько ждать хоть какого-то байта (событие или пинг), прежде чем считать поток мёртвым. */
52
+ silenceTimeoutMs: number;
53
+ onOpen?: () => void;
54
+ onEvent: (event: ChatWatchEvent) => void;
55
+ };
56
+ export type WatchChatEnd = "unavailable" | "stopped";
57
+ export declare function watchChat(options: WatchChatOptions): Promise<WatchChatEnd>;
@@ -0,0 +1,8 @@
1
+ import type { AgentChatMessage } from "./chat-types.js";
2
+ type MessagePart = AgentChatMessage["parts"][number];
3
+ /**
4
+ * Вызовы без окончательного результата закрыты: запущенные — ошибкой, ждавшие ответа человека или уже разрешённые — отказом
5
+ * (у разрешённого — «результат неизвестен», у отклонённого — причина человека). Остальное не тронуто.
6
+ */
7
+ export declare function closeStoppedToolCalls(parts: readonly MessagePart[]): MessagePart[];
8
+ export {};
@@ -0,0 +1,29 @@
1
+ import type { ReactNode } from "react";
2
+ /** Что `AgentChat.composerActions` может сделать с полем ввода и отправкой. */
3
+ export interface ComposerHelper {
4
+ /** Текст в поле ввода сейчас. */
5
+ value: string;
6
+ /** Заменить текст в поле ввода. */
7
+ setValue(text: string): void;
8
+ /**
9
+ * Отправить сообщение по тем же правилам, что кнопка «Отправить». С `text` уходит он, поле не трогается;
10
+ * без `text` — то, что в поле (с файлами). Пока `canSend` ложно (история не загрузилась, идёт ответ, лимит исчерпан),
11
+ * обе формы отказывают сразу и ничего не откладывают: проверяйте `canSend` и гасите кнопку.
12
+ */
13
+ send(text?: string): void;
14
+ /** Положить файлы в поле ввода, как скрепка. Без плагина вложений ничего не делает. */
15
+ addFiles(files: File[]): void;
16
+ /** Агент отвечает: отправка сейчас не пройдёт. */
17
+ busy: boolean;
18
+ /** Отправка остановлена (исчерпан лимит расходов). */
19
+ blocked: boolean;
20
+ /** Отправка сейчас пройдёт: история загружена, ответ не идёт, лимит не исчерпан. */
21
+ canSend: boolean;
22
+ }
23
+ /**
24
+ * Свои кнопки у поля ввода: готовый узел или функция от помощника. Функция вызывается при каждом рендере чата:
25
+ * делайте её быстрой и без побочных эффектов; помощника не сохраняйте, каждый раз приходит новый.
26
+ */
27
+ export type ComposerActions = ReactNode | ((composer: ComposerHelper) => ReactNode);
28
+ /** Готовый узел для `Composer.actions` скина; `undefined` — кнопок нет. */
29
+ export declare function renderComposerActions(actions: ComposerActions, helper: ComposerHelper): ReactNode;
@@ -0,0 +1,16 @@
1
+ import type { DiagramsClient } from "../agent-chat-extensions.js";
2
+ import type { DiagramColors } from "../skin-contract.js";
3
+ export type DiagramRenderResult = {
4
+ svg: string;
5
+ } | {
6
+ error: string;
7
+ };
8
+ /**
9
+ * Готовые рисунки чата по `source + colors`. Рисунок, уже готовый, отдаётся сразу: сообщение, которое лента убрала
10
+ * и вернула, показывает схему без заглушки, и лента не прыгает.
11
+ */
12
+ export interface DiagramRenders {
13
+ get(source: string, colors: DiagramColors): DiagramRenderResult | undefined;
14
+ request(source: string, colors: DiagramColors): Promise<DiagramRenderResult>;
15
+ }
16
+ export declare function createDiagramRenders(client: DiagramsClient): DiagramRenders;
@@ -0,0 +1,18 @@
1
+ /** Кусок текста ответа: обычная разметка или блок ```mermaid. */
2
+ export type MarkdownSegment = {
3
+ kind: "markdown";
4
+ markdown: string;
5
+ }
6
+ /** `source` — текст схемы без ограждений; `closed` — блок закрыт; `markdown` — блок целиком, как в тексте. */
7
+ | {
8
+ kind: "mermaid";
9
+ source: string;
10
+ closed: boolean;
11
+ markdown: string;
12
+ };
13
+ /**
14
+ * Делит Markdown на обычные куски и блоки ```mermaid верхнего уровня (по правилам ограждений CommonMark): блок внутри
15
+ * другого блока кода и блок с отступом в четыре пробела — не схема. Номер схемы — её порядок среди кусков `mermaid`;
16
+ * им скин зовёт `renderDiagram(source, blockIndex)`, и слой поведения считает так же.
17
+ */
18
+ export declare function splitMermaidBlocks(markdown: string): MarkdownSegment[];
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Разметка схемы со своими id для одной вставки в страницу. Один готовый рисунок из кэша может стоять в ленте
3
+ * дважды и ещё в окне просмотра; при одинаковых id `url(#…)` берёт первый в странице, и стрелки пропадают вместе
4
+ * с ним. Каждый id рисунка получает суффикс вставки, ссылки на него в атрибутах и стилях — тоже.
5
+ */
6
+ export declare function withUniqueIds(svg: string, suffix: string): string;
@@ -0,0 +1,25 @@
1
+ import type { MediaViewerItem } from "../media-viewer/media-viewer-types.js";
2
+ import type { DiagramColors, DiagramView } from "../skin-contract.js";
3
+ import type { DiagramRenders } from "./diagram-renders.js";
4
+ /** Сколько блоков ```mermaid в тексте: по нему номера схем следующей текстовой части продолжают нумерацию ответа. */
5
+ export declare const countMermaidBlocks: (markdown: string) => number;
6
+ export interface UseDiagramBlocksOptions {
7
+ markdown: string;
8
+ /** Текстовая часть ещё печатается. */
9
+ streaming: boolean;
10
+ messageId: string;
11
+ /** Номер первой схемы этой части в ответе: схемы прежних текстовых частей того же ответа. */
12
+ firstBlock: number;
13
+ renders: DiagramRenders;
14
+ colors: DiagramColors;
15
+ /** Открыть окно просмотра своим набором; нет — схема не открывается. */
16
+ open?: (key: string, trigger: HTMLElement, items: readonly MediaViewerItem[]) => void;
17
+ }
18
+ /**
19
+ * Схемы одной текстовой части для скина (`AgentText.renderDiagram`/`onOpenDiagram`). Незакрытый блок, пока текст
20
+ * печатается, — `streaming`; закрытый рисуется сразу, не дожидаясь конца ответа; дальше `ready` или `failed`.
21
+ */
22
+ export declare function useDiagramBlocks({ markdown, streaming, messageId, firstBlock, renders, colors, open }: UseDiagramBlocksOptions): {
23
+ renderDiagram: (source: string, blockIndex: number) => DiagramView;
24
+ onOpenDiagram?: ((blockIndex: number, trigger: HTMLElement) => void) | undefined;
25
+ };
@@ -0,0 +1,8 @@
1
+ import type { ChatSkin, DiagramColors } from "../skin-contract.js";
2
+ /** Тёмная ли страница, со слежением за сменой темы; `enabled: false` — не следит и отдаёт `false`. */
3
+ export declare function usePageDark(enabled: boolean): boolean;
4
+ /**
5
+ * Цвета схем для текущей темы страницы (FR-028): `skin.diagramColors(dark)`, без него — свои. Смена темы даёт новые
6
+ * цвета, и схемы перерисовываются. `enabled: false` (схемы не подключены) — за темой не следит и отдаёт `undefined`.
7
+ */
8
+ export declare function useDiagramColors(skin: ChatSkin, enabled: boolean): DiagramColors | undefined;
@@ -0,0 +1,19 @@
1
+ import type { DictatedText } from "./voice-input.js";
2
+ /**
3
+ * Как диктовка пишет в поле ввода. Продиктованное дописывается к тому, что было набрано;
4
+ * ручная правка остаётся, а сказанное до неё заново не появляется.
5
+ */
6
+ export interface DictationField {
7
+ /** Значение поля для накопленной диктовки; `null` — поле не трогать (диктовка уже заморожена). */
8
+ write(text: DictatedText): string | null;
9
+ /** Сообщить, что в поле сейчас `value`: если это не наша запись, значит поле правили руками. */
10
+ observe(value: string): void;
11
+ /** Сказано всё и закреплено, дальше только чистка: правки поля запоминаем, но запись больше не двигаем и `write` ничего не пишет. */
12
+ freeze(): void;
13
+ /**
14
+ * Заменить надиктованный кусок исправленным текстом. Возвращает новое значение поля или `null`, если заменять нельзя:
15
+ * поле правили до надиктованного или внутри него (правка не должна пропасть). Дописанное после надиктованного сохраняется.
16
+ */
17
+ applyPolished(polished: string): string | null;
18
+ }
19
+ export declare function createDictationField(startValue: string): DictationField;
@@ -0,0 +1,11 @@
1
+ export interface ExpandedParts {
2
+ isOpen: (key: string) => boolean;
3
+ setOpen: (key: string, open: boolean) => void;
4
+ subscribe: (listener: () => void) => () => void;
5
+ }
6
+ /** Ключ части ответа: id сообщения и номер части. */
7
+ export declare function partKey(messageId: string, partIndex: number): string;
8
+ /** Хранилище раскрытых частей одного чата; при смене `chatId` начинается пустое. */
9
+ export declare function useExpandedParts(chatId: string): ExpandedParts;
10
+ /** Раскрыта ли часть и как её переключить; часть перерисовывается только от своего ключа. */
11
+ export declare function usePartOpen(store: ExpandedParts, key: string): [boolean, (open: boolean) => void];
@@ -0,0 +1,7 @@
1
+ import type { AgentChatMessage } from "./chat-types.js";
2
+ /**
3
+ * Текст для диктора: пустой при открытии чата, итог ответа — когда ответ перешёл из «идёт» в
4
+ * итоговое состояние. Когда начинается новый ответ, текст обнуляется: так одинаковые итоги
5
+ * подряд («Остановлено» дважды) озвучиваются оба раза. `resetKey` (id чата) тоже обнуляет текст.
6
+ */
7
+ export declare function useFeedAnnouncement(messages: AgentChatMessage[], busy: boolean, resetKey?: string): string;