@ykurilov/agent-chat-react 0.0.0-stage → 0.56.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/CHANGELOG.md +1688 -0
- package/LICENSE +21 -0
- package/README.md +132 -2
- package/dist/chunk-7DVTSVKQ.js +6967 -0
- package/dist/chunk-7DVTSVKQ.js.map +1 -0
- package/dist/index.js +501 -0
- package/dist/index.js.map +1 -0
- package/dist/panel.js +399 -0
- package/dist/panel.js.map +1 -0
- package/dist/types/agent-chat-extensions.d.ts +80 -0
- package/dist/types/agent-chat.d.ts +103 -0
- package/dist/types/agent-panel/agent-panel-hooks.d.ts +14 -0
- package/dist/types/agent-panel/agent-panel-provider.d.ts +24 -0
- package/dist/types/agent-panel/agent-panel-skin.d.ts +41 -0
- package/dist/types/agent-panel/agent-panel.d.ts +13 -0
- package/dist/types/agent-panel/index.d.ts +8 -0
- package/dist/types/agent-panel/panel-context.d.ts +46 -0
- package/dist/types/agent-panel/panel-state.d.ts +12 -0
- package/dist/types/answer-editing/answer-editing.d.ts +25 -0
- package/dist/types/app-bridge/app-bridge.d.ts +50 -0
- package/dist/types/app-bridge/browser-calls.d.ts +24 -0
- package/dist/types/app-bridge/create-app-bridge.d.ts +35 -0
- package/dist/types/app-bridge/remembered-ids.d.ts +6 -0
- package/dist/types/app-bridge/tab-id.d.ts +10 -0
- package/dist/types/app-events.d.ts +39 -0
- package/dist/types/app-refusal.d.ts +21 -0
- package/dist/types/attachments-contract.d.ts +82 -0
- package/dist/types/background-tasks/use-background-tasks.d.ts +53 -0
- package/dist/types/chat-access.d.ts +33 -0
- package/dist/types/chat-list/active-chat-memory.d.ts +5 -0
- package/dist/types/chat-list/chat-list-client.d.ts +35 -0
- package/dist/types/chat-list/chat-list-skin.d.ts +63 -0
- package/dist/types/chat-list/chat-workspace.d.ts +17 -0
- package/dist/types/chat-list/use-chat-list-view.d.ts +12 -0
- package/dist/types/chat-list/use-chat-list.d.ts +47 -0
- package/dist/types/chat-list/use-workspace-list-sync.d.ts +7 -0
- package/dist/types/chat-state/chat-state.d.ts +27 -0
- package/dist/types/chat-types.d.ts +85 -0
- package/dist/types/chat-watch/chat-watch.d.ts +57 -0
- package/dist/types/close-stopped-tool-calls.d.ts +8 -0
- package/dist/types/composer-actions.d.ts +29 -0
- package/dist/types/diagrams/diagram-renders.d.ts +16 -0
- package/dist/types/diagrams/mermaid-blocks.d.ts +18 -0
- package/dist/types/diagrams/unique-svg-ids.d.ts +6 -0
- package/dist/types/diagrams/use-diagram-blocks.d.ts +25 -0
- package/dist/types/diagrams/use-diagram-colors.d.ts +8 -0
- package/dist/types/dictation-field.d.ts +19 -0
- package/dist/types/expanded-parts.d.ts +11 -0
- package/dist/types/feed-announcement.d.ts +7 -0
- package/dist/types/helpers/helper-call.d.ts +57 -0
- package/dist/types/index.d.ts +53 -0
- package/dist/types/labels.d.ts +468 -0
- package/dist/types/live-demos/answer-fences.d.ts +25 -0
- package/dist/types/live-demos/live-demo-document.d.ts +42 -0
- package/dist/types/live-demos/live-demo-frame.d.ts +14 -0
- package/dist/types/live-demos/use-live-demo-blocks.d.ts +18 -0
- package/dist/types/liveness/connection-errors.d.ts +15 -0
- package/dist/types/liveness/reconnect-attempts.d.ts +14 -0
- package/dist/types/liveness/request-deadline.d.ts +16 -0
- package/dist/types/liveness/silence-watchdog.d.ts +21 -0
- package/dist/types/media-viewer/answer-file-images.d.ts +18 -0
- package/dist/types/media-viewer/collect-viewer-items.d.ts +16 -0
- package/dist/types/media-viewer/generated-images.d.ts +20 -0
- package/dist/types/media-viewer/media-viewer-types.d.ts +17 -0
- package/dist/types/media-viewer/open-attachments.d.ts +9 -0
- package/dist/types/media-viewer/use-media-viewer.d.ts +23 -0
- package/dist/types/memory/agent-memory.d.ts +13 -0
- package/dist/types/memory/memory-client.d.ts +19 -0
- package/dist/types/memory/memory-skin.d.ts +103 -0
- package/dist/types/memory/memory-tree.d.ts +17 -0
- package/dist/types/memory/memory-types.d.ts +77 -0
- package/dist/types/memory/use-memory-notes.d.ts +23 -0
- package/dist/types/message-actions.d.ts +45 -0
- package/dist/types/message-feed.d.ts +27 -0
- package/dist/types/notices/agent-notices.d.ts +40 -0
- package/dist/types/pause.d.ts +2 -0
- package/dist/types/server-refusal.d.ts +16 -0
- package/dist/types/skin-contract.d.ts +687 -0
- package/dist/types/spending-status.d.ts +76 -0
- package/dist/types/steering/corrections.d.ts +19 -0
- package/dist/types/step-reset.d.ts +15 -0
- package/dist/types/subject-chat/subject-chat-loading.d.ts +8 -0
- package/dist/types/subject-chat/use-subject-chat-id.d.ts +21 -0
- package/dist/types/thinking-status/thinking-status.d.ts +33 -0
- package/dist/types/turn-finished.d.ts +14 -0
- package/dist/types/use-agent-chat.d.ts +228 -0
- package/dist/types/use-model-choice.d.ts +31 -0
- package/dist/types/use-voice-dialog.d.ts +18 -0
- package/dist/types/use-voice-dictation.d.ts +17 -0
- package/dist/types/voice-dialog.d.ts +103 -0
- package/dist/types/voice-input.d.ts +47 -0
- package/dist/types/voice-tags.d.ts +18 -0
- package/dist/types/voice-turn.d.ts +11 -0
- package/dist/types/widgets/custom-widget-guard.d.ts +21 -0
- package/dist/types/widgets/form-check.d.ts +29 -0
- package/dist/types/widgets/suggested-replies.d.ts +6 -0
- package/dist/types/widgets/use-widget-answer.d.ts +54 -0
- package/dist/types/widgets/widget-answer-keys.d.ts +14 -0
- package/dist/types/widgets/widget-messages.d.ts +14 -0
- package/dist/types/widgets/widget-part.d.ts +17 -0
- package/dist/types/widgets/widget-view.d.ts +50 -0
- package/dist/types/without-markdown.d.ts +1 -0
- package/dist/types/work-view/step-phrases.d.ts +37 -0
- package/dist/types/work-view/work-layout.d.ts +57 -0
- package/dist/types/work-view/work-steps-part.d.ts +15 -0
- package/package.json +53 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Yury Kurilov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,133 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ykurilov/agent-chat-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Поведение чата с агентом для React 19, без внешнего вида. Всё видимое рисует скин —
|
|
4
|
+
объект из десяти компонентов. Готовый скин Тандема — пакет `@ykurilov/agent-chat-skin-tandem`.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
import { AgentChat, ChatLabelsProvider, russianLabels } from "@ykurilov/agent-chat-react";
|
|
8
|
+
|
|
9
|
+
<ChatLabelsProvider labels={{ ...russianLabels, retry: "Ещё раз" }}>
|
|
10
|
+
<AgentChat api="/api/chat" chatId={chatId} skin={{ ...tandemSkin, ToolCallRow: MyToolCallRow }} />
|
|
11
|
+
</ChatLabelsProvider>;
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- `AgentChat` — лента, поле ввода, остановка, «повторить», переподключение к идущему ответу, переключатель вариантов «‹ 2/3 ›»,
|
|
15
|
+
«Переделать ответ» и правка отправленного сообщения (вид рисует скин: `BranchSwitcher`, `MessageEditor`).
|
|
16
|
+
- `skin` — компоненты по договору `ChatSkin`; любой можно заменить своим.
|
|
17
|
+
- `liveness` — сроки живой связи (см. ниже); обычно не нужен.
|
|
18
|
+
- Надписи — в словаре: `russianLabels`, `ChatLabelsProvider`, `useChatLabels()`.
|
|
19
|
+
- Пока модель думает, надпись живая: фраза из `labels.thinkingPhrases` сменяется каждые 3–4 с, рядом время (`labels.thinkingElapsed`).
|
|
20
|
+
Свой скин берёт их из `useThinkingStatus()`; диктору — постоянная `reasoningRunning`, меняющиеся фразы ему скрывать.
|
|
21
|
+
- Выбор модели: `AgentChat` сам грузит список (`GET …/models`) и передаёт скину `Composer` свойство `modelChoice`
|
|
22
|
+
(меню провайдеров и моделей, уровни рассуждений). Сохраняет выбор `PUT …/:id/model`. Отдельно — хук `useModelChoice`.
|
|
23
|
+
- `voice` — голосовой ввод из `@ykurilov/agent-chat-voice`; без него кнопки микрофона нет. Скину `Composer` уходит `voice`
|
|
24
|
+
(`VoiceInputView`), слова диктовки дописываются в поле, ручная правка остаётся.
|
|
25
|
+
- `spendingLimits` — на сервере включены лимиты расходов (`@ykurilov/agent-chat-limits`): чат читает `GET …/spending`, показывает
|
|
26
|
+
скину `SpendingNotice` («Использовано 80% лимита на месяц», «Лимит на месяц исчерпан, обновится 1 ноября») и при исчерпании
|
|
27
|
+
останавливает отправку (`Composer.sendingBlocked`). Отказ 429 переподключений не запускает: текст возвращается в поле (при правке редактор остаётся открытым, надпись — `editErrors.spendingLimit`).
|
|
28
|
+
Хук `useAgentChat({ spendingLimits: true })` отдаёт `spending`.
|
|
29
|
+
- Подтверждение действий: карточка запроса приходит в ленту сама; скину `ToolCallRow` уходят `title` и `approval` (`ToolApprovalView`), кнопки —
|
|
30
|
+
`approval.onDecide("allow" | "deny" | "always")`; «Всегда» рисовать только при `approval.canAlways`, причину отказа брать из `approval.failureText`. Новое сообщение вместо ответа считается отказом (договор скина версии 9).
|
|
31
|
+
- Ответ, который не дошёл до человека (сервер пометил `markUndelivered`), приходит скину с `undelivered: true`: серая
|
|
32
|
+
отметка `labels.answerUndelivered` («Не доставлено»). Договор скина версии 24, скин версии 23 работает без правок —
|
|
33
|
+
[docs/skin-v24.md](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/skin-v24.md).
|
|
34
|
+
- Реплика живого сотрудника (сервер: `appendStaffMessage` или `flow.noteStaffReply`) приходит скину в `StaffMessage`
|
|
35
|
+
(`text`, `staffName`) — не пузырём человека. Договор скина версии 25; скин версии 24 работает без правок: реплика
|
|
36
|
+
показывается ответом агента с подписью `labels.notices.staffSaid` («Сотрудник Ольга») —
|
|
37
|
+
[docs/skin-v25.md](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/skin-v25.md).
|
|
38
|
+
- Картинка библиотеки (`show_image`, пакет `@ykurilov/agent-chat-image-library`) приходит в `GeneratedImages` с
|
|
39
|
+
необязательными `wide` (по ширине ответа со своей пропорцией) и `caption` (подпись под картинкой). Договор скина
|
|
40
|
+
версии 26; скин версии 25 работает без правок: плитка ближайшей обычной пропорции без подписи —
|
|
41
|
+
[docs/skin-v26.md](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/skin-v26.md).
|
|
42
|
+
- `ChatWorkspace` — список чатов и открытый чат вместе: создать, переименовать, удалить (нужен `chatList: true` на сервере). Хук — `useChatList`. Скину дополнительно нужны `ChatWorkspace` и `ChatList` (`ChatListSkin`, договор версии 7).
|
|
43
|
+
- `AgentMemory` — экран долгой памяти агента: записи по разделам, добавить, изменить, удалить, «Стереть всю память» (нужна опция `memory` на сервере, пакет `@ykurilov/agent-chat-memory`). `api` — `createMemoryApi({ api: "/api/chat" })`, создавать один раз; `skin` — `MemorySkin` (`tandemMemorySkin`). Хук — `useMemoryNotes`. Без памяти на сервере экран пишет, что память не включена. Договор скина версии 11 — отдельный `MemorySkin`, `ChatSkin` не менялся ([contracts/memory.md](../../specs/017-long-term-memory/contracts/memory.md)).
|
|
44
|
+
- Панель агента: вход `@ykurilov/agent-chat-react/panel`; основной вход его не подтягивает. `AgentPanelProvider` ставится в корневой макет выше страниц (`api`, `userKey`, `browserTools`, `mode` — `overlay` или `push`, `width`, `onDataChanged`, `fetch` — свой `fetch` только для списка чатов), `AgentPanel` рисует кнопку, рамку и чат через скин. Хуки: `useAgentPanel` (`open`, `openChat`, `openNewChat({ draft })`, `pageInset` — отступ страницы в режиме `push`, на экране ≤ 640 px он 0, `busy`), `useAgentPlace({ description, data? })` (где человек; модель видит только описание, `data` — только инструменты), `useAgentDataChanges(tag, handler)` (страница узнаёт, что инструмент изменил данные). Браузерные инструменты — функции в `browserTools` с теми же именами, что описания на сервере (`BrowserToolImplementations`); нет функции — модель получает «Инструмент недоступен на этой странице» (надпись `agentPanelToolUnavailable`). Подробно — [docs/getting-started.md](../../docs/getting-started.md#панель-агента-в-приложении-по-желанию). Общие части: `AgentAppBridge` (связь чата с приложением; `appBridge` в `AgentChat`, `useAgentChat`, `ChatWorkspace`), `initialDraft` (текст в поле ввода при открытии чата), `rememberKey` в `useChatList` (свой ключ запомненного чата). Договор скина версии 12 — отдельный `AgentPanelSkin` (`AgentPanelLauncher`, `AgentPanel`), надписи `agentPanel…` в словаре; `ChatSkin`, `ChatListSkin` и `MemorySkin` не менялись ([contracts/skin.md](../../specs/021-agent-panel/contracts/skin.md)).
|
|
45
|
+
- `messageActions` — свои кнопки под ответами агента (`AgentChat`, `ChatWorkspace`, `AgentPanel`): `{ id, label, icon?, visible?, onRun }`.
|
|
46
|
+
Иконка — готовый элемент приложения (`<Heart />`), скин кладёт её в кнопку как есть. `visible({ message, status, last })` — показывать
|
|
47
|
+
ли у этого ответа (нет — у каждого законченного). `onRun({ chatId, messageId, message, text })`: пока обещание не выполнено, кнопка
|
|
48
|
+
«занята» и второй раз не жмётся; ошибка — в консоль, не в чат. Пока ответ пишется, кнопок у него нет. Массив держите постоянным
|
|
49
|
+
(вне компонента или в `useMemo`), иначе лента перерисовывает все ответы. Скину `AgentMessage` уходит `actions` (`MessageActionView[]`,
|
|
50
|
+
договор версии 17; скин версии 16 их просто не рисует).
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
const actions: MessageAction[] = [
|
|
54
|
+
{ id: "like", label: "Нравится", icon: <Heart />, visible: ({ status }) => status === "complete", onRun: ({ messageId }) => api.like(messageId) },
|
|
55
|
+
];
|
|
56
|
+
<AgentChat api="/api/chat" chatId={chatId} skin={tandemSkin} messageActions={actions} />;
|
|
57
|
+
```
|
|
58
|
+
- Поправка на лету (включена у скина с `steering: true`, у Тандема — да): пока агент отвечает, поле свободно, поправка встаёт в ленту с пометкой
|
|
59
|
+
«Агент учтёт на следующем шаге» (`steeringPending` в словаре) и уходит на `POST …/steer`. `steering={false}` — выключить. У `useAgentChat` — опция
|
|
60
|
+
`steering: true` (по умолчанию выключено), `canSteer` и `corrections` (ждущие поправки, рисовать после `messages`); `submit()` во время ответа шлёт
|
|
61
|
+
поправку. Скину — `ChatSkin.steering`, `Composer.canSteer` и `UserMessage.pending` (договор v21, [docs/skin-v21.md](../../docs/skin-v21.md)).
|
|
62
|
+
- `liveDemos` — живые демонстрации: блок ` ```html-demo ` в ответе запускается в изолированной рамке во всю ширину ответа (на сервере —
|
|
63
|
+
`agent.liveDemos: true`). Скину — `AgentText.renderDemo` и `ChatSkin.demoColors` (договор v22, [docs/live-demos.md](../../docs/live-demos.md)).
|
|
64
|
+
- Английский интерфейс: `<ChatLabelsProvider labels={englishLabels}>` — полный словарь (см. docs/getting-started.md, «Надписи»).
|
|
65
|
+
- `onTurnFinished({ chatId, messageId, status })` — ход закончен на экране: один раз на ход, когда ответ получил итог, включая остановку
|
|
66
|
+
и ошибку. Ответ, закрытый ради поправки на лету, получает своё событие перед ответом на поправку. Открытие чата с готовой историей события не даёт. На сервере то же — `onTurnFinished` у `createChatHandler`.
|
|
67
|
+
- Агент внутри продукта ([docs/in-product-agent.md](../../docs/in-product-agent.md)):
|
|
68
|
+
- `subject="lesson:42"` — чат объекта: id чата берётся у сервера (`POST …/subject`). Вместе с `chatId` не задавать.
|
|
69
|
+
- `onTurnRefused({ kind, code, message })` — отказ приложения (`turn_refused`), в доступе (`access_refused`), закрытый чат (`chat_closed`), запрещённое действие (`action_forbidden`, `code` — право) или отказ в новом чате (`chat_creation_refused`); текст возвращается в поле.
|
|
70
|
+
- Права и закрытый чат: кнопки по `capabilities` из истории чат прячет сам, закрытый чат блокирует поле и показывает текст закрытия (скину — `ChatClosedNotice`, договор v20, [docs/skin-v20.md](../../docs/skin-v20.md)). `onChatAccessChange({ capabilities, closed })` сообщает о каждой смене; у `useAgentChat` — `capabilities` и `closed`. `ChatWorkspace` при `chatList: false` показывает только чат: список появляется после первой истории и при запрете больше не запрашивается. После 403 `action_forbidden` права перечитываются. Закрытый чат в списке помечен (`ChatListEntry.closed`, надпись `chatListClosed`). В закрытом чате правка, «Переделать» и стрелки веток доступны по правам: они уводят с точки закрытия.
|
|
71
|
+
- Состояние чата (`model.state`): `onStateChange(state)` у `AgentChat` — после загрузки и при каждой смене (запись в потоке ответа, ветка, правка, событие `state-changed` из другой вкладки); внутри ленты — `useChatState()`, у `useAgentChat` — `chatState`. Служебные ключи (`$…`) не показываются.
|
|
72
|
+
- Отказ в новом чате (`beforeCreateChat` на сервере): `useChatList` — `creationRefusal` и `onCreateRefused`, `ChatWorkspace` отдаёт его в `onTurnRefused` с видом `chat_creation_refused`, текст отказа виден в списке.
|
|
73
|
+
- `reloadKey` (`AgentChat`, `useAgentChat`, `ChatWorkspace`): новое значение — история перечитывается с сервера. Нужно, когда чат изменили не через этот экран, например открыли снова из кода. `onChatUnavailable` у `AgentChat` — служебный, для `ChatWorkspace`.
|
|
74
|
+
- `appEvents={{ type: View }}` рисует события приложения внутри ответа, `onAppEvent(event, { live, messageId? })` сообщает о каждом.
|
|
75
|
+
- `composerActions` — свои кнопки у поля: узел или `(composer) => …` с `value`, `setValue`, `send(text?)`, `addFiles`, `busy`, `blocked`, `canSend`. Скину — `Composer.actions` (договор v19, [docs/skin-v19.md](../../docs/skin-v19.md)); скин v18 работает без кнопок.
|
|
76
|
+
- `useAgentChat` — то же поведение без готовой сборки ленты, если нужна своя. Для веток: `forks`, `selectBranch(messageId)`,
|
|
77
|
+
`canRegenerate`, `regenerate()`, `canEdit`, `edit(messageId, text)` (отвечает `Promise<EditOutcome>`: правка началась, не началась или сервер отказал).
|
|
78
|
+
|
|
79
|
+
Пакет не зависит от дизайн-системы и не импортирует стилей. Договор скина (версия 12: панель агента, отдельный `AgentPanelSkin`, см. выше; версия 11: экран памяти, отдельный `MemorySkin`, см. выше; версия 9: подтверждение действий — [contracts/approvals.md](../../specs/011-tool-approval/contracts/approvals.md); версия 8: необязательные `SpendingNotice` (с `id`, состояние `none`) и `Composer.sendingBlocked` с `sendingBlockedReasonId`; версия 6: ветки и правка — [contracts/branches-and-edit.md](../../specs/007-branches-and-edit/contracts/branches-and-edit.md)) —
|
|
80
|
+
[contracts/skin.md](../../specs/003-models-and-picker/contracts/skin.md) (дополняет [версию 2](../../specs/002-fast-feed-and-liveness/contracts/skin.md)), словарь —
|
|
81
|
+
[contracts/labels.md](../../specs/001-basic-agent-dialog/contracts/labels.md) и
|
|
82
|
+
[дополнение к нему](../../specs/002-fast-feed-and-liveness/contracts/labels.md).
|
|
83
|
+
|
|
84
|
+
## Лента рисует только видимое
|
|
85
|
+
|
|
86
|
+
Длинный чат открывается сразу внизу: на странице стоят только сообщения у экрана (не больше
|
|
87
|
+
40 даже в чате из 2000 сообщений). Для этого пакет берёт библиотеку
|
|
88
|
+
[`virtua`](https://github.com/inokawa/virtua), версия закреплена точно (`0.52.8`) и импортируется
|
|
89
|
+
только в `src/message-feed.tsx`. Ставить её отдельно не нужно.
|
|
90
|
+
|
|
91
|
+
Из-за этого прокруткой управляет чат, а не скин. Что нужно от своего скина:
|
|
92
|
+
|
|
93
|
+
- `Layout` вешает `scrollRef` на прокручиваемый элемент и кладёт `feed` внутрь; лента внутри
|
|
94
|
+
`role="log"` с `aria-live="off"`; `announcement` — в скрытый элемент с `aria-live="polite"`;
|
|
95
|
+
- промежутки между сообщениями — `padding` корня, не `gap` и не `margin`;
|
|
96
|
+
- `Reasoning` и `ToolCallRow` не хранят раскрытие сами, а показывают `open` и зовут `onOpenChange`:
|
|
97
|
+
раскрытое остаётся раскрытым, даже если сообщение уходило за край экрана;
|
|
98
|
+
- стили не зависят от «последний ли элемент» (`:last-child`, `:has()`).
|
|
99
|
+
|
|
100
|
+
## Живая связь
|
|
101
|
+
|
|
102
|
+
Сервер шлёт пинги, вкладка замечает тишину и сама переподключается без повторов и пропусков.
|
|
103
|
+
Состояние — `connection: "online" | "reconnecting" | "offline"` у `useAgentChat`, для скина —
|
|
104
|
+
компонент `ConnectionNotice`. Сроки — проп `liveness`:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<AgentChat
|
|
108
|
+
api="/api/chat"
|
|
109
|
+
chatId={chatId}
|
|
110
|
+
skin={tandemSkin}
|
|
111
|
+
liveness={{
|
|
112
|
+
silenceTimeoutMs: 30_000, // сколько тишины терпеть в потоке ответа
|
|
113
|
+
reconnectDelaysMs: [0, 2000, 5000], // паузы перед попытками; после трёх неудач — «Нет связи с сервером»
|
|
114
|
+
requestTimeoutMs: 10_000, // срок одной попытки и любого запроса без потока
|
|
115
|
+
}}
|
|
116
|
+
/>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Срок тишины никогда не меньше трёх пингов сервера (`heartbeatIntervalMs`, по умолчанию 10 с).
|
|
120
|
+
|
|
121
|
+
Отказ сервера — не обрыв связи. Вход истёк (401) — надпись «Вход истёк. Войдите снова» с «Повторить», без попыток
|
|
122
|
+
переподключения. У человека уже идут ответы в других чатах (429 `too_many_turns`) — своя надпись, текст возвращается в поле.
|
|
123
|
+
Сервер не признал страницу своей (403 `forbidden_origin`: фронт и API на разных адресах, а адреса фронта нет в `allowedOrigins`
|
|
124
|
+
сервера) — надпись «Сервер чата не принимает сообщения с этой страницы», текст возвращается в поле; в режиме разработки
|
|
125
|
+
(`process.env.NODE_ENV !== "production"`) в консоли подсказка, какой адрес вписать.
|
|
126
|
+
Состояние — `refusal: "signed_out" | "too_many_turns" | "forbidden_origin" | null` у `useAgentChat`; скин получает их в `ErrorNotice` как `kind`
|
|
127
|
+
(текст — `labels.errors[kind]`).
|
|
128
|
+
Ответ брошен упавшей копией сервера — экран сам перечитывает историю раз в 3 с и через 30 с показывает «прерван» с «Повторить»; обновлять страницу не нужно.
|
|
129
|
+
Подробности — [contracts/liveness.md](../../specs/002-fast-feed-and-liveness/contracts/liveness.md).
|
|
130
|
+
|
|
131
|
+
Подключение целиком: [docs/getting-started.md](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/getting-started.md).
|
|
132
|
+
|
|
133
|
+
Журнал изменений и что делать при обновлении: [CHANGELOG.md](./CHANGELOG.md). Все пакеты SDK выходят вместе и с одной версией; обновление — `pnpm update "@ykurilov/agent-chat-*" --latest`.
|