@ykurilov/agent-chat-flows 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 (151) hide show
  1. package/CHANGELOG.md +252 -0
  2. package/LICENSE +21 -0
  3. package/README.md +124 -2
  4. package/agent-flow.schema.json +1020 -0
  5. package/dist/chunk-3PTJI2XY.js +100 -0
  6. package/dist/chunk-3PTJI2XY.js.map +1 -0
  7. package/dist/chunk-BNMQUNSI.js +9 -0
  8. package/dist/chunk-BNMQUNSI.js.map +1 -0
  9. package/dist/chunk-BOV6FJGU.js +1288 -0
  10. package/dist/chunk-BOV6FJGU.js.map +1 -0
  11. package/dist/chunk-CKY5KG7N.js +165 -0
  12. package/dist/chunk-CKY5KG7N.js.map +1 -0
  13. package/dist/chunk-DCTRMCGV.js +34 -0
  14. package/dist/chunk-DCTRMCGV.js.map +1 -0
  15. package/dist/format.js +147 -0
  16. package/dist/format.js.map +1 -0
  17. package/dist/index.js +3197 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/postgres.js +387 -0
  20. package/dist/postgres.js.map +1 -0
  21. package/dist/react.js +2650 -0
  22. package/dist/react.js.map +1 -0
  23. package/dist/sqlite.js +319 -0
  24. package/dist/sqlite.js.map +1 -0
  25. package/dist/types/check/app-checks.d.ts +16 -0
  26. package/dist/types/check/check-flow.d.ts +8 -0
  27. package/dist/types/check/index.d.ts +2 -0
  28. package/dist/types/engine/data-conditions.d.ts +10 -0
  29. package/dist/types/engine/day-frame.d.ts +17 -0
  30. package/dist/types/engine/first-messages.d.ts +21 -0
  31. package/dist/types/engine/flow-days.d.ts +39 -0
  32. package/dist/types/engine/flow-graph.d.ts +26 -0
  33. package/dist/types/engine/flow-run.d.ts +130 -0
  34. package/dist/types/engine/index.d.ts +14 -0
  35. package/dist/types/engine/migrate-run.d.ts +11 -0
  36. package/dist/types/engine/next-transition.d.ts +40 -0
  37. package/dist/types/engine/nudges.d.ts +78 -0
  38. package/dist/types/engine/run-updates.d.ts +37 -0
  39. package/dist/types/engine/side-questions.d.ts +26 -0
  40. package/dist/types/engine/side-tasks.d.ts +44 -0
  41. package/dist/types/engine/targets.d.ts +9 -0
  42. package/dist/types/engine/timers.d.ts +61 -0
  43. package/dist/types/engine/zoned-time.d.ts +27 -0
  44. package/dist/types/format/catalog-events.d.ts +5 -0
  45. package/dist/types/format/compact-flow.d.ts +8 -0
  46. package/dist/types/format/flow-format.d.ts +286 -0
  47. package/dist/types/format/flow-json-schema.d.ts +2 -0
  48. package/dist/types/format/flow-schema.d.ts +605 -0
  49. package/dist/types/format/index.d.ts +7 -0
  50. package/dist/types/format/migrate-flow.d.ts +4 -0
  51. package/dist/types/format/parse-flow.d.ts +6 -0
  52. package/dist/types/format.d.ts +3 -0
  53. package/dist/types/index.d.ts +4 -0
  54. package/dist/types/labels/client-card.d.ts +20 -0
  55. package/dist/types/labels/editor.d.ts +261 -0
  56. package/dist/types/labels/index.d.ts +14 -0
  57. package/dist/types/labels/migrate.d.ts +19 -0
  58. package/dist/types/labels/test-chat.d.ts +28 -0
  59. package/dist/types/not-yet.d.ts +2 -0
  60. package/dist/types/postgres.d.ts +10 -0
  61. package/dist/types/prompt/client-card-block.d.ts +16 -0
  62. package/dist/types/prompt/flow-rules.d.ts +9 -0
  63. package/dist/types/prompt/rules/after-end.d.ts +3 -0
  64. package/dist/types/prompt/rules/client-facts.d.ts +2 -0
  65. package/dist/types/prompt/rules/day-frame.d.ts +2 -0
  66. package/dist/types/prompt/rules/link-views.d.ts +4 -0
  67. package/dist/types/prompt/rules/rule-part.d.ts +3 -0
  68. package/dist/types/prompt/rules/side-tasks.d.ts +2 -0
  69. package/dist/types/prompt/rules/time-zone.d.ts +2 -0
  70. package/dist/types/prompt/state-card.d.ts +14 -0
  71. package/dist/types/react/client-card/client-card-panel.d.ts +8 -0
  72. package/dist/types/react/client-card/index.d.ts +2 -0
  73. package/dist/types/react/client-card/use-client-card.d.ts +19 -0
  74. package/dist/types/react/client-card-skin.d.ts +27 -0
  75. package/dist/types/react/editor/board-space.d.ts +51 -0
  76. package/dist/types/react/editor/board-styles.d.ts +1 -0
  77. package/dist/types/react/editor/editor-model.d.ts +60 -0
  78. package/dist/types/react/editor/exit-text.d.ts +11 -0
  79. package/dist/types/react/editor/flow-board.d.ts +11 -0
  80. package/dist/types/react/editor/flow-editor.d.ts +13 -0
  81. package/dist/types/react/editor/flow-simulation.d.ts +44 -0
  82. package/dist/types/react/editor/index.d.ts +6 -0
  83. package/dist/types/react/editor/schedule-model.d.ts +47 -0
  84. package/dist/types/react/editor/side-task-model.d.ts +18 -0
  85. package/dist/types/react/editor/use-flow-editor.d.ts +120 -0
  86. package/dist/types/react/flow-editor-skin.d.ts +453 -0
  87. package/dist/types/react/flow-labels.d.ts +8 -0
  88. package/dist/types/react/index.d.ts +6 -0
  89. package/dist/types/react/test-chat/flow-test-chat.d.ts +22 -0
  90. package/dist/types/react/test-chat/index.d.ts +2 -0
  91. package/dist/types/react/test-chat/use-flow-test-chat.d.ts +50 -0
  92. package/dist/types/react.d.ts +3 -0
  93. package/dist/types/runtime/admit.d.ts +15 -0
  94. package/dist/types/runtime/agent-flow.d.ts +20 -0
  95. package/dist/types/runtime/client-card.d.ts +9 -0
  96. package/dist/types/runtime/client-facts.d.ts +22 -0
  97. package/dist/types/runtime/close-day-tool.d.ts +3 -0
  98. package/dist/types/runtime/decisions-client.d.ts +33 -0
  99. package/dist/types/runtime/extra-tool.d.ts +16 -0
  100. package/dist/types/runtime/first-message-retry.d.ts +4 -0
  101. package/dist/types/runtime/first-message-rules.d.ts +55 -0
  102. package/dist/types/runtime/first-reasons-notice.d.ts +9 -0
  103. package/dist/types/runtime/flow-delivery.d.ts +53 -0
  104. package/dist/types/runtime/flow-events.d.ts +126 -0
  105. package/dist/types/runtime/flow-finish.d.ts +68 -0
  106. package/dist/types/runtime/flow-known-texts.d.ts +11 -0
  107. package/dist/types/runtime/flow-signals.d.ts +12 -0
  108. package/dist/types/runtime/flow-timers.d.ts +55 -0
  109. package/dist/types/runtime/flow-tools.d.ts +23 -0
  110. package/dist/types/runtime/flow-types.d.ts +547 -0
  111. package/dist/types/runtime/held-messages.d.ts +25 -0
  112. package/dist/types/runtime/index.d.ts +11 -0
  113. package/dist/types/runtime/judge-context.d.ts +36 -0
  114. package/dist/types/runtime/judge.d.ts +21 -0
  115. package/dist/types/runtime/migrate-chats.d.ts +20 -0
  116. package/dist/types/runtime/note-tools.d.ts +15 -0
  117. package/dist/types/runtime/pause.d.ts +21 -0
  118. package/dist/types/runtime/prepare-turn.d.ts +12 -0
  119. package/dist/types/runtime/side-task-tool.d.ts +5 -0
  120. package/dist/types/runtime/step-tail.d.ts +11 -0
  121. package/dist/types/runtime/tail/day-line.d.ts +2 -0
  122. package/dist/types/runtime/tail/frame-line.d.ts +2 -0
  123. package/dist/types/runtime/tail/side-tasks-line.d.ts +2 -0
  124. package/dist/types/runtime/tail/tail-part.d.ts +21 -0
  125. package/dist/types/runtime/test-clock.d.ts +26 -0
  126. package/dist/types/runtime/time-zone-tool.d.ts +3 -0
  127. package/dist/types/runtime/turn-gate.d.ts +8 -0
  128. package/dist/types/sqlite.d.ts +9 -0
  129. package/dist/types/store/flow-store-shared.d.ts +20 -0
  130. package/dist/types/store/flow-store.d.ts +240 -0
  131. package/dist/types/store/memory.d.ts +3 -0
  132. package/dist/types/store/migration-settings.d.ts +7 -0
  133. package/dist/types/store/postgres-schema.d.ts +775 -0
  134. package/dist/types/store/postgres.d.ts +15 -0
  135. package/dist/types/store/sqlite-schema.d.ts +824 -0
  136. package/dist/types/store/sqlite.d.ts +9 -0
  137. package/drizzle/postgres/0000_init.sql +45 -0
  138. package/drizzle/postgres/0001_days_pause_side_tasks.sql +21 -0
  139. package/drizzle/postgres/0002_chat_placement.sql +1 -0
  140. package/drizzle/postgres/meta/0000_snapshot.json +317 -0
  141. package/drizzle/postgres/meta/0001_snapshot.json +439 -0
  142. package/drizzle/postgres/meta/0002_snapshot.json +445 -0
  143. package/drizzle/postgres/meta/_journal.json +27 -0
  144. package/drizzle/sqlite/0000_init.sql +44 -0
  145. package/drizzle/sqlite/0001_days_pause_side_tasks.sql +21 -0
  146. package/drizzle/sqlite/0002_chat_placement.sql +1 -0
  147. package/drizzle/sqlite/meta/0000_snapshot.json +297 -0
  148. package/drizzle/sqlite/meta/0001_snapshot.json +427 -0
  149. package/drizzle/sqlite/meta/0002_snapshot.json +434 -0
  150. package/drizzle/sqlite/meta/_journal.json +27 -0
  151. package/package.json +98 -3
package/CHANGELOG.md ADDED
@@ -0,0 +1,252 @@
1
+ # @ykurilov/agent-chat-flows
2
+
3
+ ## 0.55.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 7b5ed35: Сценарии: подписи событий приложения — `catalog.events` принимает `{ name, label }`; доска, прогон, карточка условия и
8
+ `describeCondition` с каталогом показывают подпись.
9
+ - 98e1e86: Сценарии: утреннее сообщение перезапускает ряд касаний — молчун каждый день получает утреннее и ряд заново, до потолка
10
+ дня. Смена поведения для сценариев с утренним и `afterSilence`.
11
+ - b17e389: Сценарии: таймер «наступил день N программы» (`{ type: "timer", from: "program_day", day }`) — выход в начале дня N
12
+ по нумерации `readRun().day`, без хода приложения. Дополнение к формату v2; `checkFlow` проверяет день против
13
+ `lengthDays`; на доске «Длится» → «до дня программы», подпись «с дня N».
14
+ Вошёл в ноду уже в день N или позже — выход в том же ходе, один ответ из новой ноды; так же `since_start`, чей срок
15
+ прошёл к входу.
16
+ - f1151a6: Сценарии: свои касания ноды на N дней (`nudges.days`) — потом утреннее и общий ряд сценария с начала. Доска:
17
+ «Свои касания действуют», подпись на карточке.
18
+
19
+ ### Patch Changes
20
+
21
+ - Updated dependencies [51f7b38]
22
+ - Updated dependencies [cdc7dd7]
23
+ - @ykurilov/agent-chat-core@0.55.0
24
+ - @ykurilov/agent-chat-react@0.55.0
25
+
26
+ ## 0.54.0
27
+
28
+ ### Minor Changes
29
+
30
+ - bc3cef1: Доска сценария: больше места графу. Узкая шапка (`header="compact"`), легенда «Условий выхода» по умолчанию свёрнута в кнопку
31
+ (`legend`), панель «Сценарий» сворачивается (`inspector`), мини-карта сворачивается (`minimap`), редактор разворачивается на
32
+ весь экран (`fullscreen`). Свёрнутое запоминается в localStorage (`storageKey`). Договор скина: необязательные `compact` и
33
+ `fullscreen` у шапки, `compact` у рамки, часть `FlowBoardToggle`.
34
+
35
+ ### Patch Changes
36
+
37
+ - Updated dependencies [c8fb0dd]
38
+ - Updated dependencies [73d3aaa]
39
+ - Updated dependencies [fa90219]
40
+ - @ykurilov/agent-chat-react@0.54.0
41
+ - @ykurilov/agent-chat-core@0.54.0
42
+
43
+ ## 0.53.0
44
+
45
+ ### Minor Changes
46
+
47
+ - b6a7786: Сценарии: конец разговора без сбоев, «не сейчас», пояс по умолчанию, реплика сотрудника, тихое утро, касания с
48
+ карточками; расход по списку чатов.
49
+
50
+ - Конец разговора («срок вышел», «не завершил», прощание) больше не зависит от того, начался ли ход касания. Касания
51
+ сценария не режет потолок ядра «5 ходов сервера подряд»; у `deliverNotices` — свой потолок `maxServerTurnsInRow`
52
+ (число или `false`, по умолчанию 5, `MAX_SERVER_TURNS_IN_ROW`).
53
+ - Мягкий потолок сценария: 50 ходов сервера подряд без человека (`timers.maxServerTurnsInRow`), дальше касания ждут
54
+ его сообщения, конец разговора — в свой срок. Срок без причин писать не повторяется каждый час.
55
+ - `canWriteNow` → `false` — «не сейчас»: касание через час; `"never"` — молчать до сообщения человека; `{ retryAt: Date }`
56
+ — в свой момент (негодная дата — как `false`, прошлая — через минуту). Сроки конца разговора не снимаются.
57
+ - Человек писал до начала дня меньше 3 часов назад (`skipMorningIfHumanWithinMin`) — касания в начале дня ждут, не только
58
+ утреннее. Переход ноды по сроку и ответ на ночные сообщения не ждут.
59
+ - Сообщения после жёсткой рамки дня ставят срок на утро сами: ответ на накопленное приходит в `dayStart` при любых
60
+ касаниях. Их время — в данных чата (`flowHeldHuman`); для правила 3 часов, «не завершил» и перехода «человек молчит»
61
+ они — сообщения человека.
62
+ - `attach.deliver` получает `parts` — все части ответа для человека (карточка ролика, картинка, файл, виджет), `text`
63
+ прежний; `deliverNotices({ awaitAnswer }).answer.parts`; `deliverableParts` из ядра.
64
+ - `storage.sumUsageByChat({ chatIds, ownerId?, source?, since? })` — расход по списку чатов одним запросом (память,
65
+ SQLite, PostgreSQL; общие тесты хранилищ).
66
+ - `createAgentFlow({ defaultTimeZone })` — пояс, пока пояс человека неизвестен. Порядок: человек → страница →
67
+ `defaultTimeZone` → пояс службы → сервер. `prepareTurn` получает `pageTimeZone` — пояс, присланный страницей.
68
+ - `service.appendStaffMessage({ ownerId, chatId, text, staffName?, wakeAgent? })` — реплика живого сотрудника: модель
69
+ видит её словами сотрудника, `person_link_view` словами человека её не считает, проверки ответа агента её текст знают,
70
+ ход сама не начинает.
71
+ `flow.noteStaffReply` пишет тем же путём и принимает `staffName`. Экран: необязательный `StaffMessage` скина (договор 25),
72
+ без него — ответ агента с подписью `labels.notices.staffSaid`.
73
+ - `flow.tick()` в публичном типе, `factId` из пакета, перемотка до утра у чата, закреплённого через `adopt` без хода.
74
+
75
+ Как обновить приложение: снимите `it.fails` у теста «молчун все три дня»; ответ эксперта кладите
76
+ `appendStaffMessage` / `noteStaffReply` вместо сообщения собеседника и уберите обёртку `withoutNonPersonWords`; по желанию
77
+ `defaultTimeZone` и `StaffMessage` в своём скине; снимите `it.fails` у теста «касание, отложенное ночью до утра»;
78
+ доставляйте `message.parts` в своей доставке касаний; расход по чатам — `sumUsageByChat`.
79
+
80
+ ### Patch Changes
81
+
82
+ - Updated dependencies [b6a7786]
83
+ - @ykurilov/agent-chat-core@0.53.0
84
+ - @ykurilov/agent-chat-react@0.53.0
85
+
86
+ ## 0.52.0
87
+
88
+ ### Minor Changes
89
+
90
+ - d9b2ea5: Редактор сценариев (`FlowEditor`) для кабинета эксперта: три мелочи.
91
+
92
+ - `readOnly` — доска только для просмотра, пока сценарий правит внешний агент. Нельзя двигать, соединять и удалять узлы,
93
+ править панели, сохранять, загружать JSON и переводить чаты. Открывать узлы, проверять граф, прогонять и смотреть JSON
94
+ можно. В шапке плашка «Только просмотр» (`labels.header.readOnly`).
95
+ - `onSave` может вернуть `{ ok: false, issues?: [{ path, message }] }`: отказ без исключения. Шапка пишет «Не
96
+ сохранено», `issues` встают у нод и выходов и видны в «Проверить граф». Ничего (`void`) и `{ ok: true }` — успех, как
97
+ раньше. Исключение из `onSave` — такой же отказ, без необработанной ошибки в консоли.
98
+ - `className` и `style` у `FlowEditor` идут на корень. Корень по умолчанию занимает высоту родителя, но не меньше 60%
99
+ экрана (не меньше 420 px), на телефоне — экрана целиком (не меньше 640 px): холст не схлопывается.
100
+
101
+ Как обновить приложение: вместо обёртки «inert» на время правок агента передайте `readOnly`; из `onSave` возвращайте
102
+ `{ ok: false, issues }` при отказе сервера; ручную высоту у родителя редактора можно убрать. Договор скина редактора: все
103
+ новые поля необязательные (`saveFailed`, `readOnly` у шапки, `readOnly` у окна JSON, `className` и `style` у раскладки),
104
+ свой скин без них работает.
105
+
106
+ ### Patch Changes
107
+
108
+ - @ykurilov/agent-chat-core@0.52.0
109
+ - @ykurilov/agent-chat-react@0.52.0
110
+
111
+ ## 0.51.0
112
+
113
+ ### Minor Changes
114
+
115
+ - 41b1726: Проверка ответа: **тексты приложения.** В `replyChecks` появилось `knownTexts: ({ ownerId, chatId }) => string[] | Promise<string[]>` — первое сообщение, прощание, названия роликов: слова и ссылки оттуда больше не вырезаются и не считаются чужими. Если `replyChecks` передан в `flow.withChat(…)`, сценарий сам добавляет свои тексты (общая часть, ноды, первые сообщения, прощание, рамка дня, попутные задачи). **Проверка текста вне хода:** `service.checkReply({ ownerId, chatId, text })` → `{ text, notes }` — те же проверки и тот же набор «виденного», что у хода. **Исправление:** служебные сообщения приложения (`app`, «напиши первым») и реплики сотрудника больше не делают ссылку законной — «виденное от человека» берётся только из сообщений человека (итоги фоновых задач остаются виденными). Если агент должен повторять ссылки из своих служебных сообщений, назовите их в `knownTexts`. Подробно — `docs/reply-check.md`.
116
+
117
+ ### Patch Changes
118
+
119
+ - cd55c82: Проверка сценария больше не ругается на ноду, в которую ведёт только «срок вышел» (`schedule.deadlineState`): она считается достижимой.
120
+ - Updated dependencies [41b1726]
121
+ - @ykurilov/agent-chat-core@0.51.0
122
+ - @ykurilov/agent-chat-react@0.51.0
123
+
124
+ ## 0.50.0
125
+
126
+ ### Minor Changes
127
+
128
+ - 68b0629: Свободные факты о человеке в карточке клиента: `createAgentFlow({ clientFacts: true })`. Агент пишет факт
129
+ `flow_note { fact }`, `client_card` показывает и стирает, блок `flow:client` несёт список «Факты о человеке», «забудь всё»
130
+ стирает и поля, и факты. Свои таблицы приложения — необязательное `clientCard.facts: { read, add, forget }`; нет — факты
131
+ лежат в таблице модуля записями `fact:<id>`. Правило в инструкции делит факты (карточка) и правила общения (долгая память
132
+ SDK). `flow.readClientCard` отдаёт факты записями `fact:<id>`, `useClientCard` — опция `factName`. Без `clientFacts` всё как
133
+ в 0.49. Просмотр ссылки (`person_link_view`): «не открылась — сказать один раз» и расход в журнал описаны в
134
+ `docs/flows.md` и README web-tools, закреплены тестами.
135
+ - 25aaf22: Перенос идущих чатов и конец разговора снаружи. Сценарий без новых полей ведёт себя как в 0.49. Подробно —
136
+ `docs/flows.md` и раздел 0.50.0 в `CHANGES.md`.
137
+
138
+ - `flow.adopt({ ownerId, chatId, flowId, versionId, flow, stateId, startedAt, enteredAt, lastHumanAt, lastAgentAt, nudgeStep, today, timeZone })`
139
+ закрепляет идущий чат сразу, без хода, и ставит срок следующего касания. `today: { firstMessages, humanMessages, dayClosed }`
140
+ продолжает дневной потолок и рамки дня. Те же поля принимает `loadFlow`. Перенос переживает перезапуск.
141
+ - `flow.end({ ownerId, chatId, reason, outcome })` — конец разговора со своей причиной (`"switched"`): `onFinish`
142
+ (`reason`, `outcome`), сроки сняты, дальше — как настроено `afterEnd`. `FlowEndReason` принимает любую строку.
143
+ - `agent.stepContext` в ходе «пишет первым» получает `firstReasons` — все причины хода; тип `FlowStepContextInput`.
144
+ - `nudges` в корне сценария — касания без «Дней и времени». Порядок: своё у ноды → `"off"` → `schedule.nudges` →
145
+ `nudges` сценария. Новая находка проверки `nudges_shadowed`.
146
+ - Документация: ночью агент отвечает человеку, тихие часы — только для сообщений первым; `admit` → `hold` бывает
147
+ только после жёсткой рамки дня.
148
+
149
+ ### Как обновить приложение
150
+
151
+ 1. Поднимите все пакеты `@ykurilov/agent-chat-*` до этой версии вместе. Миграций нет.
152
+ 2. Ничего больше не нужно, если вы не используете новое.
153
+ 3. Переносите идущие чаты из своей системы — зовите `flow.adopt` для каждого чата после `createChat`, а не ждите
154
+ `loadFlow` на первом ходе: молчащий чат иначе не получит касаний.
155
+ 4. Если в коде есть исчерпывающая проверка причины конца (`switch (end.reason)` с `never` в `default`), добавьте
156
+ ветку для своих причин: `FlowEndReason` теперь принимает любую строку.
157
+ 5. Своё хранилище сценариев (`FlowStore`) менять не нужно: новые поля переноса лежат в той же JSON-колонке `placement`.
158
+
159
+ ### Patch Changes
160
+
161
+ - @ykurilov/agent-chat-core@0.50.0
162
+ - @ykurilov/agent-chat-react@0.50.0
163
+
164
+ ## 0.49.0
165
+
166
+ ### Minor Changes
167
+
168
+ - 084cef7: **Ломает приложения (типы и своё хранилище сценариев):** у типа поля сценария `FlowFieldType` появилось значение `"boolean"`, у источника
169
+ расхода `UsageSource` — `"first_message"`, у `SteerResult.status` — `"held"`. Исчерпывающий `switch` по ним перестанет
170
+ собираться. Своё хранилище сценариев (`FlowStore`) должно реализовать новый `renewLease()` и третий аргумент `setDue`.
171
+
172
+ Сценарии для приложений: программа по дням (ночь, касания, рамки дня, «срок вышел»), своя служба чата и доставка с
173
+ исходами, пауза сотрудника, конец разговора с итогом, карточка и пояс человека в базе приложения, попутные задачи.
174
+ Проверка готового ответа: «чужие слова» и «выдуманные ссылки». Подробно — `docs/flows.md`, `docs/reply-check.md`,
175
+ раздел 0.49.0 в `CHANGES.md`.
176
+
177
+ - **flows**: формат сценария версии 2 (`schedule`, `nudges`, таймер `state_days`, поле `boolean`, `sideTasks`,
178
+ `afterEnd`; версия 1 читается сама); `attach({ portFor, deliver })`, `admit`, `pause`/`resume`/`noteStaffReply`,
179
+ `reportDelivery`, `onFinish`, `clientCard`, `people`, `settled`, `now`; причина перехода `reason`; перенос чата
180
+ через `loadFlow` (`stateId`, `startedAt`, `enteredAt`); заголовки судьи `judge.openrouter.headers`; встроенная задача
181
+ «узнать город»; `checkFlow(flow, catalog, { checks })` и `FlowAppChecks` из `/format`; в редакторе панели дней,
182
+ касаний, рамок и попутных задач, `catalog.fields`, кнопка «К началу следующего дня» (`advanceToNextDay`). Новые
183
+ таблицы `flow_people`, `flow_side_tasks` и колонки `flow_chats` создаются сами.
184
+ - **core**: `replyChecks` (список или `{ checks, web: "replace" | "hold" }`), `now`, `markUndelivered`, ответы
185
+ `beforeTurn` `{ hold: true }` и `{ reply: { text } }`, `deliverNotices({ timeZone, awaitAnswer, usageSource })`,
186
+ источник расхода `first_message`.
187
+ - **flows, надёжность**: обход таймеров до 5 ходов одновременно; копия продлевает аренду чата перед ходом и во время
188
+ него. В `FlowStore` новые `renewLease()` и `setDue(…, { unlessDelivery })`. Недоставленное касание (`failed`,
189
+ `window_closed`) не засчитывается — тот же шаг через свой срок от отказа; в `FlowRun` новое поле `touch`. «Окно
190
+ закрыто» снимает любое сообщение человека; «не завершил» считает тишину и от конца паузы сотрудника; пока ждёт
191
+ повтор доставки, срок не затирается и новых ходов нет.
192
+ - **server**: `createChatServer` передаёт службе `replyChecks` и `now`.
193
+ - **messengers**: `onAnswerDelivery` — исход доставки каждого ответа; закрытое окно ВК (950) —
194
+ `MessengerWindowClosedError` и исход `window_closed`; с `replyChecks` уходит только проверенный текст.
195
+ - **web-tools**: `createPersonLinkTool` — инструмент `person_link_view`, агент смотрит ссылку, которую прислал человек
196
+ (адрес из почты ссылкой не считается).
197
+ - **reply-check** (новый пакет): `foreignWords` и `unknownLinks`; ответ из одной выдуманной ссылки заменяется запасной
198
+ фразой `labels.linkOnlyReply` (`russianReplyCheckLabels`, `englishReplyCheckLabels`, `ReplyCheckLabels`).
199
+ - **react**: договор скина версии 24 — необязательное `undelivered` у ответа агента и надпись `answerUndelivered`
200
+ («Не доставлено»). Скин версии 23 работает без правок.
201
+
202
+ ### Как обновить приложение
203
+
204
+ 1. Поднимите все пакеты `@ykurilov/agent-chat-*` до этой версии вместе.
205
+ 2. Найдите в коде приложения исчерпывающие `switch` и словари по этим типам и добавьте ветки:
206
+ - по `FlowFieldType` (поля карточки сценария) — `"boolean"`, «да/нет», значения `true`/`false`;
207
+ - по `UsageSource` (отчёты расходов) — `"first_message"`, «агент написал первым»;
208
+ - по `SteerResult.status` — `"held"`, «сообщение записано, хода нет».
209
+ 3. Своё хранилище сценариев (свой `FlowStore`) — добавьте `renewLease({ chatId, owner, now, leaseMs }): Promise<boolean>`
210
+ (продлить аренду до `now + leaseMs`; `false` — чат уже не ваш) и третий аргумент `setDue(chatId, due, { unlessDelivery })`
211
+ (при `unlessDelivery` не писать срок, пока чат ждёт повтора доставки). Готовые хранилища SDK это уже умеют.
212
+ 4. Сценарии сохраняются версией 2, а 0.48 её не откроет. Перед откатом на 0.48 держите копии сценариев версии 1.
213
+ 5. Новое по желанию: каналы SDK и сценарий — `createMessengers({ onAnswerDelivery: (report) => flow.reportDelivery(report) })`;
214
+ проверка ответа — `pnpm add @ykurilov/agent-chat-reply-check` и `replyChecks` в `createChatServer`.
215
+ 6. Проверка: `pnpm typecheck` проходит, чат отвечает, сценарий версии 1 открывается в редакторе.
216
+
217
+ ### Patch Changes
218
+
219
+ - Updated dependencies [084cef7]
220
+ - @ykurilov/agent-chat-core@0.49.0
221
+ - @ykurilov/agent-chat-react@0.49.0
222
+
223
+ ## 0.48.0
224
+
225
+ ### Minor Changes
226
+
227
+ - fa10d5a: Сценарии поведения агента: разговор идёт по шагам с условиями выхода, судьёй, таймерами «написать первым» и карточкой
228
+ клиента, плюс редактор сценария с тестовым чатом. Подробно — `docs/flows.md`.
229
+
230
+ - **flows** (новый пакет): `createAgentFlow`, формат и проверка сценария, судья decision-1 с запасной моделью, таймеры,
231
+ карточка клиента, перевод чатов на новую версию, хранилища SQLite и PostgreSQL, `FlowEditor`, `FlowTestChat`, `ClientCardPanel`.
232
+ - **core**: новые точки для расширений — `agent.prepareTurn` (контекст хода с `resumed`, `audience`, `staff?`),
233
+ служебное сообщение `app`, готовый ответ `deliverNotices({ reply })`, `askModel` и `recordUsage`, источник расхода
234
+ `judge`, `ChatService.assertWithinLimit(ownerId, chatId)`; `chatInstructions(chat, turn?)` — второй аргумент с
235
+ `audience` (при сжатии истории его нет).
236
+ - **server**: `chatInstructions` в настройках принимает тот же второй аргумент `turn`.
237
+ - **messengers**: ответ сервера без модели (точный текст по таймеру сценария) теперь доходит до мессенджера.
238
+ - **skin-tandem**: новые входы `/flows` (`tandemFlowEditorSkin`) и `/client-card` (`tandemClientCardSkin`).
239
+
240
+ ### Как обновить приложение
241
+
242
+ Сценарии не нужны — обновление ничего не требует. Нужны — шаги в разделе «Как обновить приложение» в `CHANGES.md`:
243
+ `pnpm add @ykurilov/agent-chat-flows`, `createAgentFlow` + `flow.withChat(…)`, `flow.attach(service)`, `flow.start()`,
244
+ `OPENROUTER_API_KEY` на сервере. Тестовому чату нужен `readRun(chatId)` в `FlowTestChatConnection`; его адреса
245
+ закройте правами редактора. `firstMessages: false` теперь значит «без тихих часов и потолка», запрет —
246
+ `canWriteNow: () => false`. Проверка: `pnpm typecheck`, новый чат отвечает по первому состоянию сценария.
247
+
248
+ ### Patch Changes
249
+
250
+ - Updated dependencies [fa10d5a]
251
+ - @ykurilov/agent-chat-core@0.48.0
252
+ - @ykurilov/agent-chat-react@0.48.0
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,125 @@
1
- # Temporary Holding Version
1
+ # @ykurilov/agent-chat-flows
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Сценарии поведения агента. Разговор идёт по карте шагов — состояний. У каждого состояния своя короткая инструкция и
4
+ условия выхода: словами (решает судья), по данным, по событию или по таймеру. Агент помнит карточку клиента между
5
+ чатами и пишет первым, когда сработал таймер. Сценарий может идти по дням («программа на 3 дня»): ночь, касания, рамки
6
+ дня, срок. Автор рисует сценарий в редакторе, проверяет и прогоняет его.
7
+
8
+ Полное описание простыми словами, с примерами и замерами: [docs/flows.md](../../docs/flows.md).
9
+
10
+ ## Подключить
11
+
12
+ ```bash
13
+ pnpm add @ykurilov/agent-chat-flows
14
+ ```
15
+
16
+ ```ts
17
+ import { createAgentFlow } from "@ykurilov/agent-chat-flows";
18
+ import { sqliteFlowStore } from "@ykurilov/agent-chat-flows/sqlite";
19
+
20
+ const flow = createAgentFlow({
21
+ loadFlow: async ({ ownerId, chat }) => ({ flowId: "sales-review", versionId: "3", flow: publishedJson }),
22
+ store: sqliteFlowStore("./data/chat.db"),
23
+ judge: { fallback: { modelId: "deepseek-4.1-flash", providerId: "deepseek" } },
24
+ });
25
+
26
+ const { handler, service } = createChatServer(flow.withChat({ ...chatOptions, agent: { instructions, tools } }));
27
+ flow.attach(service);
28
+ flow.start();
29
+ ```
30
+
31
+ Судья — `microsoft/microsoft-decision-1` через OpenRouter: нужен `OPENROUTER_API_KEY` на сервере. Запасная модель
32
+ (`judge.fallback`) — из каталога приложения.
33
+
34
+ ## Настройки `createAgentFlow`
35
+
36
+ | Настройка | Что это | По умолчанию |
37
+ |---|---|---|
38
+ | `loadFlow` | сценарий нового чата: `{ flowId, versionId, flow }` или `null` — без сценария. Перенос чата: `stateId`, `startedAt`, `enteredAt` | обязательна |
39
+ | `store` | `memoryFlowStore()`, `sqliteFlowStore(path)`, `postgresFlowStore(pool)` | обязательна |
40
+ | `judge.fallback` | запасная модель судьи из каталога | обязательна |
41
+ | `judge.model`, `judge.threshold`, `judge.timeoutMs` | основной судья, порог «выполнено», срок | decision-1, 0,7, 5000 мс |
42
+ | `judge.openrouter` | `{ apiKey, baseUrl, headers }`: свой прокси и его заголовки | из окружения |
43
+ | `firstMessages` | тихие часы, потолок в сутки, `canWriteNow`; `false` — без часов и потолка. `canWriteNow` → `false` — «не сейчас», касание через час, `{ retryAt }` — в свой момент; конец разговора от него не зависит. «Дни и время» сценария главнее | 21:00–09:00, 3 в сутки |
44
+ | `onTransition` | каждый переход: `from`, `to`, `exitId`, `decidedBy`, `tags`, `reason`, `day` | — |
45
+ | `onFinish` | конец разговора: `reason` (`final`, `deadline`, `abandoned`, `blocked`), `day`, `state`, `tags`, `run` | — |
46
+ | `clientCard` | карточка клиента в базе приложения: `read`, `write`, `forget` | таблица модуля |
47
+ | `clientFacts` | свободные факты о человеке в карточке («ведёт блог»): `flow_note { fact }`, список в блоке `flow:client`, «забудь» стирает. Свои таблицы фактов — `clientCard.facts`; правило делит факты (карточка) и правила общения (память SDK) | выключено |
48
+ | `people` | пояс человека в базе приложения: `readTimeZone`, `writeTimeZone` | таблица модуля |
49
+ | `defaultTimeZone` | пояс, пока пояс человека неизвестен: человек → страница → он → `agent.timeZone` → сервер | — |
50
+ | `pause.staffSilenceHours` | через сколько часов молчания сотрудника пауза снимается сама | 2 |
51
+ | `timers` | `tickMs` — как часто смотреть таймеры, `leaseMs` — аренда копией сервера | 15 000 и 60 000 мс |
52
+ | `logError` | строки журнала | `console.error` |
53
+ | `now` | часы: тесты подменяют время целиком | сейчас |
54
+
55
+ Что есть у `flow`: `withChat`, `attach`, `start`, `stop`, `settled`, `signal`, `adopt`, `end`, `admit`, `pause`, `resume`,
56
+ `noteStaffReply` (реплика сотрудника — путём `service.appendStaffMessage`), `reportDelivery`, `readRun`, `chatsByState`,
57
+ `migrateChats`, `readClientCard`, `forgetClientCard`, `advanceTestClock`, `tick` (один обход таймеров: тесты, свой
58
+ планировщик). Из пакета — ещё `factId(text)`: id факта карточки.
59
+
60
+ - `attach(service)` — одна служба на всё приложение. `attach({ portFor, deliver })` — служба на чат и своя доставка
61
+ того, что агент пишет первым. `deliver` получает текст (`text`) и все части ответа для человека (`parts`: карточка
62
+ ролика, картинка, файл, виджет — с 0.53) и возвращает исход: `delivered`, `retry`, `window_closed`, `blocked`, `failed`.
63
+ - Каналы SDK сообщают исход сами: `createMessengers({ onAnswerDelivery: (report) => flow.reportDelivery(report) })`.
64
+ - Недоставленное касание (`failed`, `window_closed`) не засчитывается: тот же шаг повторится через свой срок от момента
65
+ отказа. Пока ждёт повтор доставки, новых ходов нет.
66
+ - Свой канал перед ходом зовёт `flow.admit`: ответить, ответить готовой фразой, промолчать до утра (после жёсткой рамки
67
+ дня), разговор закончен или отвечает сотрудник. Ночью агент человеку отвечает.
68
+ - `flow.adopt` переносит идущий чат из вашей системы сразу, без хода: место, последние реплики, шаг касаний, счёт дня.
69
+ - `flow.end({ reason: "switched" })` заканчивает разговор со своей причиной: `onFinish`, как у остальных концов.
70
+
71
+ - Место чата (ключ `flow` в состоянии) посетителю не уходит: SDK прячет его сам (`privateStateKeys`). Читайте его
72
+ через `flow.readRun`.
73
+ - В групповых чатах сценарий выключен. Сотрудник в песочнице карточку клиента только читает.
74
+ - Лимит расходов проверяется до каждого обращения к судье: исчерпан — запроса нет, условие «не проверено».
75
+ - `attach` ждёт службу чата с `assertWithinLimit` — её даёт `createChatServer` этой версии.
76
+
77
+ ## Тестовый чат
78
+
79
+ `FlowTestChat` ждёт от приложения `start`, `advance`, `readRun` и `renderChat` (`FlowTestChatConnection`). На сервере это
80
+ `service.createChat(userId, { data: flowTestChatData() })`, `flow.advanceTestClock` и `flow.readRun`. Кнопка «К началу
81
+ следующего дня» — необязательный `advanceToNextDay`: на сервере `flow.advanceTestClock({ ownerId, chatId, to:
82
+ "next_day_start" })`.
83
+
84
+ `FlowEditor`: `readOnly` — доска только для просмотра, пока сценарий правит внешний агент; `onSave` может вернуть
85
+ `{ ok: false, issues }` — отказ без исключения, находки встают у нод; `className` и `style` идут на корень, высота по
86
+ умолчанию — родителя, не меньше разумной. Подробно — [docs/flows.md](../../docs/flows.md).
87
+
88
+ Свои проверки приложения: `checks` у `FlowEditor` и `FlowTestChat`, на сервере те же — `checkFlow(flow, catalog, {
89
+ checks })`. Поля приложения для карточки и попутных задач — `catalog.fields`.
90
+
91
+ Эндпоинты тестового чата (advanceTestClock, readRun) приложение закрывает правами само: только редактору и только для
92
+ тестовых чатов.
93
+
94
+ ## Входы
95
+
96
+ | Вход | Что внутри |
97
+ |---|---|
98
+ | `.` | сервер: `createAgentFlow`, `memoryFlowStore`, `flowTestChatData`, всё из `./format` |
99
+ | `./format` | формат (`parseFlow`, `compactFlow`), проверка (`checkFlow`, `FlowAppChecks`), движок — без серверных зависимостей, для браузера |
100
+ | `./react` | `FlowEditor`, `FlowTestChat`, `ClientCardPanel`, договоры скинов, надписи ru/en |
101
+ | `./sqlite`, `./postgres` | хранилище сценариев в базе приложения |
102
+ | `./agent-flow.schema.json` | JSON Schema формата для внешних редакторов и агентов |
103
+
104
+ Скины Тандема: `@ykurilov/agent-chat-skin-tandem/flows` (`tandemFlowEditorSkin`) и
105
+ `@ykurilov/agent-chat-skin-tandem/client-card` (`tandemClientCardSkin`).
106
+
107
+ ## Хранилище
108
+
109
+ Своё хранилище реализует договор `FlowStore`. С 0.49 в нём ещё `renewLease()` — продлить аренду чата перед ходом и во
110
+ время него — и `setDue(chatId, due, { unlessDelivery })` — не затирать срок повтора доставки. Обход таймеров идёт до 5
111
+ ходов одновременно.
112
+
113
+ Таблицы `flow_chats`, `flow_versions`, `flow_client_cards`, `flow_first_messages`, `flow_people`, `flow_side_tasks` и свой журнал миграций
114
+ `__flows_migrations`. Создаются сами при первом обращении. SQLite — файл может быть общим с чатами. PostgreSQL —
115
+ схема `agent_chat` на пуле приложения, пул закрывает приложение.
116
+
117
+ ## Формат версии 2
118
+
119
+ С 0.49 сценарий пишется версией 2: «Дни и время» (`schedule`), касания (`nudges` у сценария и у состояния), таймер
120
+ `state_days`, поле «да/нет» (`boolean`), попутные задачи (`sideTasks`), режим после конца (`afterEnd`). Версия 1
121
+ читается и переводится сама. Версия 0.48 JSON версии 2 не откроет. Образец со всеми частями —
122
+ [demo/three-day-program.json](demo/three-day-program.json).
123
+
124
+ С 0.55 к версии 2 добавился таймер «наступил день N программы» (`{ "type": "timer", "from": "program_day", "day": 3 }`):
125
+ выход в начале дня N, когда бы человек ни пришёл в ноду. SDK до 0.55 такой сценарий не откроет.