@ykurilov/agent-chat-flows 0.80.0 → 0.81.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 +94 -0
- package/dist/{chunk-CZ3EDVYW.js → chunk-7ES2PXNH.js} +2 -2
- package/dist/{chunk-CZ3EDVYW.js.map → chunk-7ES2PXNH.js.map} +1 -1
- package/dist/{chunk-DCTRMCGV.js → chunk-DOKHNTPU.js} +20 -2
- package/dist/chunk-DOKHNTPU.js.map +1 -0
- package/dist/index.js +381 -188
- package/dist/index.js.map +1 -1
- package/dist/postgres.js +56 -7
- package/dist/postgres.js.map +1 -1
- package/dist/react.js +1 -1
- package/dist/sqlite.js +51 -7
- package/dist/sqlite.js.map +1 -1
- package/dist/types/runtime/flow-delivery.d.ts +22 -13
- package/dist/types/runtime/flow-lease.d.ts +19 -0
- package/dist/types/runtime/flow-timers.d.ts +2 -2
- package/dist/types/runtime/flow-types.d.ts +30 -3
- package/dist/types/store/flow-store-shared.d.ts +5 -1
- package/dist/types/store/flow-store.d.ts +56 -2
- package/dist/types/store/memory.d.ts +1 -1
- package/dist/types/store/postgres.d.ts +1 -1
- package/dist/types/store/sqlite.d.ts +1 -1
- package/package.json +4 -4
- package/dist/chunk-DCTRMCGV.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-flows
|
|
2
2
|
|
|
3
|
+
## 0.81.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 58204d2: **Ломает приложения со своим хранилищем мессенджеров или сценариев.** Хранилища из пакетов (память, SQLite,
|
|
8
|
+
Postgres) уже готовы — если вы передаёте их, менять ничего не нужно.
|
|
9
|
+
|
|
10
|
+
- `MessengerStore`: новый обязательный метод `saveLinkIfFree` и признак `guarded: true`. Привязка аккаунта по коду
|
|
11
|
+
идёт только через `saveLinkIfFree`: два кода разных людей на один аккаунт мессенджера больше не переписывают друг
|
|
12
|
+
друга.
|
|
13
|
+
- `FlowStore`: новый обязательный метод `swapDelivery` и признак `guarded: true`.
|
|
14
|
+
- Без `guarded: true` `createMessengers` и `createAgentFlow` сразу бросают `TypeError`. Признак — обещание, что
|
|
15
|
+
хранилище выполняет условия держателя и аренды (список — в шаге 3 ниже).
|
|
16
|
+
|
|
17
|
+
Новое для своей доставки сценария (`attach({ deliver })`):
|
|
18
|
+
|
|
19
|
+
- Исход `{ status: "await_repair" }` — канал сломан и ждёт починки (например, отозван токен бота). Ответ ждёт,
|
|
20
|
+
попытка не тратится, новых ходов и касаний нет. Починили — `flow.resumeDelivery({ ownerId, chatId, messageId })`:
|
|
21
|
+
тот же `messageId`, текст и части уходят ближайшим обходом таймеров. Ответ: `resumed`, `pending`, `busy`,
|
|
22
|
+
`not_found` или `dropped` (человек уже написал после ответа — ответ снят и помечен недоставленным). Ожидание
|
|
23
|
+
переживает перезапуск. В `reportDelivery` этот исход — `TypeError`.
|
|
24
|
+
- Пока идёт `deliver`, аренда чата продлевается: вторая копия сервера ту же попытку не начинает. Копия упала посреди
|
|
25
|
+
отправки — та же попытка повторяется через её паузу. Итог устаревшей копии не пишется.
|
|
26
|
+
- Перед самым `deliver`, уже под резервом, SDK ещё раз сверяет: разговор не закончен после хода (`flow.end`), ответ
|
|
27
|
+
есть в ветке, после починки человек не написал после него. Иначе `deliver` не зовётся, ответ помечен недоставленным.
|
|
28
|
+
- Повтор доставки прощания у законченного разговора теперь доходит — без нового хода и без открытия разговора.
|
|
29
|
+
- «Ровно один раз» снаружи SDK не обещает: после падения копии тот же ответ может уйти ещё раз с тем же `messageId`.
|
|
30
|
+
Двойную отправку отсекает приложение по `messageId`.
|
|
31
|
+
|
|
32
|
+
Остальные исправления аудита работают без правок в приложении:
|
|
33
|
+
|
|
34
|
+
- Ход группы мессенджера остаётся групповым и тогда, когда агент пишет первым, когда человек правит сообщение
|
|
35
|
+
группы, шлёт поправку к ходу или нажимает кнопку-подсказку: без памяти и личных блоков владельца, только
|
|
36
|
+
разрешённые группе инструменты, с пределом сообщений участника.
|
|
37
|
+
- Удаление чата ждёт хода на любой копии сервера: идёт ход — `ChatBusyError`, чат цел.
|
|
38
|
+
- Не удалось отметить вложения сообщения прикреплёнными — ошибка доходит до вызывающего, сообщение не записывается,
|
|
39
|
+
место в счёте сообщений отдаётся назад; повтор того же сообщения проходит.
|
|
40
|
+
- Сценарий, который не сходится с подтверждениями приложения (`confirmations`, `exitGuards`), проверяется до записи
|
|
41
|
+
версии и закрепления чата: чат идёт без сценария, перевод чатов на такую версию — отказ.
|
|
42
|
+
- Копия сервера, у которой забрали аренду таймера сценария или обновления мессенджера, больше не шлёт касание и не
|
|
43
|
+
переписывает срок и итог другой копии.
|
|
44
|
+
|
|
45
|
+
### Как обновить приложение
|
|
46
|
+
|
|
47
|
+
Нужно только если приложение передаёт в `createMessengers` или `createAgentFlow` своё хранилище (не
|
|
48
|
+
`createMemoryMessengerStore`, `createSqliteMessengerStore`, `createPostgresMessengerStore`, `memoryFlowStore`,
|
|
49
|
+
`sqliteFlowStore`, `postgresFlowStore`).
|
|
50
|
+
|
|
51
|
+
1. Найдите свою реализацию `MessengerStore` (поиск по `MessengerStore` или `saveLink(`).
|
|
52
|
+
2. Добавьте метод — одной атомарной операцией базы:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
async saveLinkIfFree(link) {
|
|
56
|
+
// Аккаунт свободен или уже за link.userId — записать (имя и время обновить) и вернуть "saved".
|
|
57
|
+
// Аккаунт за другим пользователем — ничего не менять и вернуть "taken".
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
В SQL это `insert … on conflict (messenger, bot_id, external_user_id) do update set … where user_id = $userId
|
|
62
|
+
returning …`: строка вернулась — `"saved"`, нет — `"taken"`. Отдельные «найти, потом записать» не годятся: между
|
|
63
|
+
ними успевает второй код.
|
|
64
|
+
3. Добавьте признак `guarded: true` в объект хранилища. Он обещает:
|
|
65
|
+
- `finishUpdate(key, status, now, holder)`, `renewUpdates` и `releaseUpdate` пишут, только пока обновление за этим
|
|
66
|
+
держателем; `acquireLease` не отдаёт чужую живую аренду;
|
|
67
|
+
- `saveLinkIfFree` — одна атомарная операция.
|
|
68
|
+
4. Своё `FlowStore` (если есть): метод `swapDelivery(chatId, { expected, next, due, claim, freeAt, endedAt })` одной
|
|
69
|
+
транзакцией. Заменить запись доставки, только если сейчас там `expected` (совпали `messageId`, `attempt` и `token`;
|
|
70
|
+
`null` — записи нет). С `claim` — только если аренда чата свободна, уже у `claim.owner` или у `claim.from`, и взять
|
|
71
|
+
её до `now + leaseMs`. С `freeAt` — только если живой аренды нет. С `endedAt` — только если конец разговора всё
|
|
72
|
+
ещё этот (`null` — не закончен). `due` записать вместе с записью. Вернуть `true`,
|
|
73
|
+
если заменил этот вызов. Плюс `guarded: true`, который обещает:
|
|
74
|
+
- `setDue(…, { leaseOwner })` пишет, только пока аренда у этой копии; `{ unlessDelivery: true }` — только если
|
|
75
|
+
доставки не ждёт;
|
|
76
|
+
- `leaseDue` не берёт живую аренду, а законченные разговоры берёт только со сроком `FLOW_DELIVERY_EXIT`;
|
|
77
|
+
- `endChat` при ждущей доставке не снимает срок и аренду.
|
|
78
|
+
Образец — `postgresFlowStore` и `sqliteFlowStore` в `@ykurilov/agent-chat-flows`.
|
|
79
|
+
5. Проверка: `pnpm typecheck` проходит. Без признака или без `saveLinkIfFree` запуск сразу бросает `TypeError` с
|
|
80
|
+
подсказкой, без `swapDelivery` — `attach({ deliver })`.
|
|
81
|
+
|
|
82
|
+
### Patch Changes
|
|
83
|
+
|
|
84
|
+
- Updated dependencies [038b6e2]
|
|
85
|
+
- Updated dependencies [58204d2]
|
|
86
|
+
- @ykurilov/agent-chat-react@0.81.0
|
|
87
|
+
- @ykurilov/agent-chat-core@0.81.0
|
|
88
|
+
|
|
89
|
+
## 0.80.1
|
|
90
|
+
|
|
91
|
+
### Patch Changes
|
|
92
|
+
|
|
93
|
+
- Updated dependencies [d59ae4e]
|
|
94
|
+
- @ykurilov/agent-chat-core@0.80.1
|
|
95
|
+
- @ykurilov/agent-chat-react@0.80.1
|
|
96
|
+
|
|
3
97
|
## 0.80.0
|
|
4
98
|
|
|
5
99
|
### Patch Changes
|
|
@@ -606,7 +606,7 @@ function createFlowFinish(input) {
|
|
|
606
606
|
...text && { reply: { text } }
|
|
607
607
|
});
|
|
608
608
|
if (result.status !== "delivered" || !result.turnStarted) return;
|
|
609
|
-
if (delivery) await delivery.afterFirstTurn({ ownerId, chatId, answer: result.answer, reasons: [{ kind: "farewell" }], at, timeZone });
|
|
609
|
+
if (delivery) await delivery.afterFirstTurn({ ownerId, chatId, answer: result.answer, reasons: [{ kind: "farewell" }], at, timeZone, endedAt: record?.endedAt ?? null });
|
|
610
610
|
else await firstMessages?.record({ ownerId, at, timeZone });
|
|
611
611
|
},
|
|
612
612
|
async end({ ownerId, chatId, pinned, run, reason, outcome, at }) {
|
|
@@ -835,4 +835,4 @@ export {
|
|
|
835
835
|
clientFactStore,
|
|
836
836
|
factEntry
|
|
837
837
|
};
|
|
838
|
-
//# sourceMappingURL=chunk-
|
|
838
|
+
//# sourceMappingURL=chunk-7ES2PXNH.js.map
|