@ykurilov/agent-chat-react 0.64.0 → 0.65.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ykurilov/agent-chat-react
2
2
 
3
+ ## 0.65.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 814ee7f: Пометка «Агент написал первым — человек молчал 1 ч 7 мин» перед ответом, который агент написал сам. Ядро: право чата `appNotices` (по умолчанию выключено) — служебные пометки приложения (`kind: "app"`) уходят в историю без текста для модели и только через белый список `appNoticeViews` (имя → безопасные данные для экрана; без функции пометка не уходит); `modelDetails: false` выключает и `appNotices`. React: `noticeLines` у `AgentChat` (имя пометки → строка), договор скина 27 — необязательный `ServiceLine`. Сценарии: в данных пометки `silentMs` (от последнего сообщения человека) и `exit`, проекция для экрана регистрируется в `withChat`, готовые строки `flowNoticeLines()` с подписями `russianFlowNoticeLabels`/`englishFlowNoticeLabels` (`FlowLabels.notices`); `FlowTestChat` передаёт их в `renderChat(chatId, { noticeLines })`. Тандем рисует `ServiceLine`. Как подключить — CHANGES.md, раздел 0.65.0.
8
+
3
9
  ## 0.64.0
4
10
 
5
11
  ### Minor Changes
package/README.md CHANGED
@@ -39,6 +39,11 @@ import { AgentChat, ChatLabelsProvider, russianLabels } from "@ykurilov/agent-ch
39
39
  необязательными `wide` (по ширине ответа со своей пропорцией) и `caption` (подпись под картинкой). Договор скина
40
40
  версии 26; скин версии 25 работает без правок: плитка ближайшей обычной пропорции без подписи —
41
41
  [docs/skin-v26.md](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/skin-v26.md).
42
+ - Служебные пометки приложения (`kind: "app"`) — серой строкой перед ответом агента: «Агент написал первым — человек
43
+ молчал 1 ч 7 мин». Нужны право чата `appNotices` на сервере (по умолчанию выключено), `noticeLines` у `AgentChat`
44
+ (имя пометки → строка; для сценариев — `flowNoticeLines()`) и `ServiceLine` у скина. Договор скина версии 27; скин
45
+ версии 26 работает без правок: пометок не видно —
46
+ [docs/skin-v27.md](https://github.com/ykurilov/agent-chat-sdk/blob/main/docs/skin-v27.md).
42
47
  - `ChatWorkspace` — список чатов и открытый чат вместе: создать, переименовать, удалить (нужен `chatList: true` на сервере). Хук — `useChatList`. Скину дополнительно нужны `ChatWorkspace` и `ChatList` (`ChatListSkin`, договор версии 7).
43
48
  - `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
49
  - Панель агента: вход `@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)).
@@ -2187,8 +2187,17 @@ function useBackgroundTasks({ chatUrl: chatUrl2, enabled, version, fetch: custom
2187
2187
 
2188
2188
  // src/notices/agent-notices.ts
2189
2189
  var AGENT_NOTICE_PART_TYPE = "data-agent-notice";
2190
+ var isAgentNoticePart = (part) => part.type === AGENT_NOTICE_PART_TYPE;
2190
2191
  function agentNoticesOf(message) {
2191
- return rawNoticesOf(message).filter((notice) => notice.kind !== STAFF_NOTICE_KIND);
2192
+ return rawNoticesOf(message).filter((notice) => notice.kind !== STAFF_NOTICE_KIND && notice.kind !== APP_NOTICE_KIND);
2193
+ }
2194
+ var APP_NOTICE_KIND = "app";
2195
+ function appNoticesOf(message) {
2196
+ return rawNoticesOf(message).flatMap((notice) => {
2197
+ if (notice.kind !== APP_NOTICE_KIND) return [];
2198
+ const { name, data } = notice;
2199
+ return typeof name === "string" ? [{ name, data }] : [];
2200
+ });
2192
2201
  }
2193
2202
  var STAFF_NOTICE_KIND = "staff";
2194
2203
  function staffRepliesOf(message) {
@@ -5790,7 +5799,7 @@ function SubjectAgentChat(props) {
5790
5799
  if (found.state === "failed") return /* @__PURE__ */ jsx9(props.skin.ErrorNotice, { kind: "other", onRetry: found.retry });
5791
5800
  return /* @__PURE__ */ jsx9(SubjectChatLoading, { skin: props.skin });
5792
5801
  }
5793
- function AgentChatBody({ api, chatId, skin, liveness, voice, voiceDialog, attachments: attachmentsPlugin, spendingLimits, onBusyChange, appBridge, initialDraft, answerEditing, onFeedChange, messageActions, onTurnFinished, onTurnRefused, composerActions, onAppEvent, onChatAccessChange, onStateChange, onModelChosen, onChatUnavailable, reloadKey, steering, widgets, diagrams, liveDemos, images, videos, appEvents, workView, stepPhrases }) {
5802
+ function AgentChatBody({ api, chatId, skin, liveness, voice, voiceDialog, attachments: attachmentsPlugin, spendingLimits, onBusyChange, appBridge, initialDraft, answerEditing, onFeedChange, messageActions, onTurnFinished, onTurnRefused, composerActions, onAppEvent, onChatAccessChange, onStateChange, onModelChosen, onChatUnavailable, reloadKey, steering, widgets, diagrams, liveDemos, images, videos, appEvents, workView, stepPhrases, noticeLines }) {
5794
5803
  const spendingNoticeId = useId2();
5795
5804
  const closedNoticeId = useId2();
5796
5805
  const chat = useAgentChat({
@@ -5831,9 +5840,10 @@ function AgentChatBody({ api, chatId, skin, liveness, voice, voiceDialog, attach
5831
5840
  ...videos && { videos },
5832
5841
  ...appEvents && { appEvents },
5833
5842
  ...workView && { workView },
5834
- ...stepPhrases && { stepPhrases }
5843
+ ...stepPhrases && { stepPhrases },
5844
+ ...noticeLines && { noticeLines }
5835
5845
  }),
5836
- [widgets, diagrams, liveDemos, imageClients, videos, appEvents, workView, stepPhrases]
5846
+ [widgets, diagrams, liveDemos, imageClients, videos, appEvents, workView, stepPhrases, noticeLines]
5837
5847
  );
5838
5848
  const scrollRef = useRef17(null);
5839
5849
  const feedRef = useRef17(null);
@@ -5999,7 +6009,10 @@ ${text}` : text),
5999
6009
  const NoticeView = skin.AgentNoticeView;
6000
6010
  const notices2 = agentNoticesOf(message);
6001
6011
  const staffReplies = staffRepliesOf(message);
6002
- const shown = staffReplies.length > 0 ? /* @__PURE__ */ jsx9(StaffReplies, { skin, replies: staffReplies, label: labels.notices.staffSaid }) : notices2.length > 0 ? NoticeView ? /* @__PURE__ */ jsx9(Fragment2, { children: notices2.map((notice2, noticeIndex) => /* @__PURE__ */ jsx9(NoticeView, { ...noticeViewOf(notice2, noticeControls) }, noticeIndex)) }) : (
6012
+ const appNotices = appNoticesOf(message);
6013
+ const serviceLines = appNotices.length > 0 && /* @__PURE__ */ jsx9(ServiceLines, { skin, notices: appNotices, lines: extensions.noticeLines });
6014
+ const onlyAppNotices = appNotices.length > 0 && notices2.length === 0 && staffReplies.length === 0 && message.parts.every(isAgentNoticePart);
6015
+ const content = onlyAppNotices ? /* @__PURE__ */ jsx9(Fragment2, {}) : staffReplies.length > 0 ? /* @__PURE__ */ jsx9(StaffReplies, { skin, replies: staffReplies, label: labels.notices.staffSaid }) : notices2.length > 0 ? NoticeView ? /* @__PURE__ */ jsx9(Fragment2, { children: notices2.map((notice2, noticeIndex) => /* @__PURE__ */ jsx9(NoticeView, { ...noticeViewOf(notice2, noticeControls) }, noticeIndex)) }) : (
6003
6016
  // Скин без плашек (v16): короткая строка из словаря, не пустой пузырь; править служебное сообщение нельзя.
6004
6017
  /* @__PURE__ */ jsx9(skin.UserMessage, { text: noticesAsText(notices2, labels.notices), ...branchSwitcher && { branchSwitcher } })
6005
6018
  ) : message.role === "user" ? editingId === message.id ? /* @__PURE__ */ jsx9(
@@ -6072,6 +6085,10 @@ ${text}` : text),
6072
6085
  }
6073
6086
  }
6074
6087
  );
6088
+ const shown = serviceLines ? /* @__PURE__ */ jsxs(Fragment2, { children: [
6089
+ serviceLines,
6090
+ content
6091
+ ] }) : content;
6075
6092
  const markers = dividers.get(message.id);
6076
6093
  return markers ? /* @__PURE__ */ jsxs(Fragment2, { children: [
6077
6094
  shown,
@@ -6269,6 +6286,15 @@ var EDIT_REFUSAL_ERRORS = {
6269
6286
  // Текст сервера идёт в редактор как есть; надпись — на случай, если текста почему-то нет.
6270
6287
  server_refused: "rejected"
6271
6288
  };
6289
+ function ServiceLines({ skin, notices, lines }) {
6290
+ const View = skin.ServiceLine;
6291
+ if (!View || !lines) return null;
6292
+ const texts = notices.flatMap((notice) => {
6293
+ const text = Object.hasOwn(lines, notice.name) ? lines[notice.name](notice) : void 0;
6294
+ return text ? [{ name: notice.name, text }] : [];
6295
+ });
6296
+ return /* @__PURE__ */ jsx9(Fragment2, { children: texts.map(({ name, text }, index) => /* @__PURE__ */ jsx9(View, { text }, `${name}-${index}`)) });
6297
+ }
6272
6298
  function StaffReplies({ skin, replies, label }) {
6273
6299
  const View = skin.StaffMessage;
6274
6300
  return /* @__PURE__ */ jsx9(Fragment2, { children: replies.map(
@@ -7058,4 +7084,4 @@ export {
7058
7084
  activeChatTitle,
7059
7085
  useWorkspaceListSync
7060
7086
  };
7061
- //# sourceMappingURL=chunk-OAQ7TGUB.js.map
7087
+ //# sourceMappingURL=chunk-JLGBVDAR.js.map