@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.
- package/CHANGELOG.md +252 -0
- package/LICENSE +21 -0
- package/README.md +124 -2
- package/agent-flow.schema.json +1020 -0
- package/dist/chunk-3PTJI2XY.js +100 -0
- package/dist/chunk-3PTJI2XY.js.map +1 -0
- package/dist/chunk-BNMQUNSI.js +9 -0
- package/dist/chunk-BNMQUNSI.js.map +1 -0
- package/dist/chunk-BOV6FJGU.js +1288 -0
- package/dist/chunk-BOV6FJGU.js.map +1 -0
- package/dist/chunk-CKY5KG7N.js +165 -0
- package/dist/chunk-CKY5KG7N.js.map +1 -0
- package/dist/chunk-DCTRMCGV.js +34 -0
- package/dist/chunk-DCTRMCGV.js.map +1 -0
- package/dist/format.js +147 -0
- package/dist/format.js.map +1 -0
- package/dist/index.js +3197 -0
- package/dist/index.js.map +1 -0
- package/dist/postgres.js +387 -0
- package/dist/postgres.js.map +1 -0
- package/dist/react.js +2650 -0
- package/dist/react.js.map +1 -0
- package/dist/sqlite.js +319 -0
- package/dist/sqlite.js.map +1 -0
- package/dist/types/check/app-checks.d.ts +16 -0
- package/dist/types/check/check-flow.d.ts +8 -0
- package/dist/types/check/index.d.ts +2 -0
- package/dist/types/engine/data-conditions.d.ts +10 -0
- package/dist/types/engine/day-frame.d.ts +17 -0
- package/dist/types/engine/first-messages.d.ts +21 -0
- package/dist/types/engine/flow-days.d.ts +39 -0
- package/dist/types/engine/flow-graph.d.ts +26 -0
- package/dist/types/engine/flow-run.d.ts +130 -0
- package/dist/types/engine/index.d.ts +14 -0
- package/dist/types/engine/migrate-run.d.ts +11 -0
- package/dist/types/engine/next-transition.d.ts +40 -0
- package/dist/types/engine/nudges.d.ts +78 -0
- package/dist/types/engine/run-updates.d.ts +37 -0
- package/dist/types/engine/side-questions.d.ts +26 -0
- package/dist/types/engine/side-tasks.d.ts +44 -0
- package/dist/types/engine/targets.d.ts +9 -0
- package/dist/types/engine/timers.d.ts +61 -0
- package/dist/types/engine/zoned-time.d.ts +27 -0
- package/dist/types/format/catalog-events.d.ts +5 -0
- package/dist/types/format/compact-flow.d.ts +8 -0
- package/dist/types/format/flow-format.d.ts +286 -0
- package/dist/types/format/flow-json-schema.d.ts +2 -0
- package/dist/types/format/flow-schema.d.ts +605 -0
- package/dist/types/format/index.d.ts +7 -0
- package/dist/types/format/migrate-flow.d.ts +4 -0
- package/dist/types/format/parse-flow.d.ts +6 -0
- package/dist/types/format.d.ts +3 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/labels/client-card.d.ts +20 -0
- package/dist/types/labels/editor.d.ts +261 -0
- package/dist/types/labels/index.d.ts +14 -0
- package/dist/types/labels/migrate.d.ts +19 -0
- package/dist/types/labels/test-chat.d.ts +28 -0
- package/dist/types/not-yet.d.ts +2 -0
- package/dist/types/postgres.d.ts +10 -0
- package/dist/types/prompt/client-card-block.d.ts +16 -0
- package/dist/types/prompt/flow-rules.d.ts +9 -0
- package/dist/types/prompt/rules/after-end.d.ts +3 -0
- package/dist/types/prompt/rules/client-facts.d.ts +2 -0
- package/dist/types/prompt/rules/day-frame.d.ts +2 -0
- package/dist/types/prompt/rules/link-views.d.ts +4 -0
- package/dist/types/prompt/rules/rule-part.d.ts +3 -0
- package/dist/types/prompt/rules/side-tasks.d.ts +2 -0
- package/dist/types/prompt/rules/time-zone.d.ts +2 -0
- package/dist/types/prompt/state-card.d.ts +14 -0
- package/dist/types/react/client-card/client-card-panel.d.ts +8 -0
- package/dist/types/react/client-card/index.d.ts +2 -0
- package/dist/types/react/client-card/use-client-card.d.ts +19 -0
- package/dist/types/react/client-card-skin.d.ts +27 -0
- package/dist/types/react/editor/board-space.d.ts +51 -0
- package/dist/types/react/editor/board-styles.d.ts +1 -0
- package/dist/types/react/editor/editor-model.d.ts +60 -0
- package/dist/types/react/editor/exit-text.d.ts +11 -0
- package/dist/types/react/editor/flow-board.d.ts +11 -0
- package/dist/types/react/editor/flow-editor.d.ts +13 -0
- package/dist/types/react/editor/flow-simulation.d.ts +44 -0
- package/dist/types/react/editor/index.d.ts +6 -0
- package/dist/types/react/editor/schedule-model.d.ts +47 -0
- package/dist/types/react/editor/side-task-model.d.ts +18 -0
- package/dist/types/react/editor/use-flow-editor.d.ts +120 -0
- package/dist/types/react/flow-editor-skin.d.ts +453 -0
- package/dist/types/react/flow-labels.d.ts +8 -0
- package/dist/types/react/index.d.ts +6 -0
- package/dist/types/react/test-chat/flow-test-chat.d.ts +22 -0
- package/dist/types/react/test-chat/index.d.ts +2 -0
- package/dist/types/react/test-chat/use-flow-test-chat.d.ts +50 -0
- package/dist/types/react.d.ts +3 -0
- package/dist/types/runtime/admit.d.ts +15 -0
- package/dist/types/runtime/agent-flow.d.ts +20 -0
- package/dist/types/runtime/client-card.d.ts +9 -0
- package/dist/types/runtime/client-facts.d.ts +22 -0
- package/dist/types/runtime/close-day-tool.d.ts +3 -0
- package/dist/types/runtime/decisions-client.d.ts +33 -0
- package/dist/types/runtime/extra-tool.d.ts +16 -0
- package/dist/types/runtime/first-message-retry.d.ts +4 -0
- package/dist/types/runtime/first-message-rules.d.ts +55 -0
- package/dist/types/runtime/first-reasons-notice.d.ts +9 -0
- package/dist/types/runtime/flow-delivery.d.ts +53 -0
- package/dist/types/runtime/flow-events.d.ts +126 -0
- package/dist/types/runtime/flow-finish.d.ts +68 -0
- package/dist/types/runtime/flow-known-texts.d.ts +11 -0
- package/dist/types/runtime/flow-signals.d.ts +12 -0
- package/dist/types/runtime/flow-timers.d.ts +55 -0
- package/dist/types/runtime/flow-tools.d.ts +23 -0
- package/dist/types/runtime/flow-types.d.ts +547 -0
- package/dist/types/runtime/held-messages.d.ts +25 -0
- package/dist/types/runtime/index.d.ts +11 -0
- package/dist/types/runtime/judge-context.d.ts +36 -0
- package/dist/types/runtime/judge.d.ts +21 -0
- package/dist/types/runtime/migrate-chats.d.ts +20 -0
- package/dist/types/runtime/note-tools.d.ts +15 -0
- package/dist/types/runtime/pause.d.ts +21 -0
- package/dist/types/runtime/prepare-turn.d.ts +12 -0
- package/dist/types/runtime/side-task-tool.d.ts +5 -0
- package/dist/types/runtime/step-tail.d.ts +11 -0
- package/dist/types/runtime/tail/day-line.d.ts +2 -0
- package/dist/types/runtime/tail/frame-line.d.ts +2 -0
- package/dist/types/runtime/tail/side-tasks-line.d.ts +2 -0
- package/dist/types/runtime/tail/tail-part.d.ts +21 -0
- package/dist/types/runtime/test-clock.d.ts +26 -0
- package/dist/types/runtime/time-zone-tool.d.ts +3 -0
- package/dist/types/runtime/turn-gate.d.ts +8 -0
- package/dist/types/sqlite.d.ts +9 -0
- package/dist/types/store/flow-store-shared.d.ts +20 -0
- package/dist/types/store/flow-store.d.ts +240 -0
- package/dist/types/store/memory.d.ts +3 -0
- package/dist/types/store/migration-settings.d.ts +7 -0
- package/dist/types/store/postgres-schema.d.ts +775 -0
- package/dist/types/store/postgres.d.ts +15 -0
- package/dist/types/store/sqlite-schema.d.ts +824 -0
- package/dist/types/store/sqlite.d.ts +9 -0
- package/drizzle/postgres/0000_init.sql +45 -0
- package/drizzle/postgres/0001_days_pause_side_tasks.sql +21 -0
- package/drizzle/postgres/0002_chat_placement.sql +1 -0
- package/drizzle/postgres/meta/0000_snapshot.json +317 -0
- package/drizzle/postgres/meta/0001_snapshot.json +439 -0
- package/drizzle/postgres/meta/0002_snapshot.json +445 -0
- package/drizzle/postgres/meta/_journal.json +27 -0
- package/drizzle/sqlite/0000_init.sql +44 -0
- package/drizzle/sqlite/0001_days_pause_side_tasks.sql +21 -0
- package/drizzle/sqlite/0002_chat_placement.sql +1 -0
- package/drizzle/sqlite/meta/0000_snapshot.json +297 -0
- package/drizzle/sqlite/meta/0001_snapshot.json +427 -0
- package/drizzle/sqlite/meta/0002_snapshot.json +434 -0
- package/drizzle/sqlite/meta/_journal.json +27 -0
- package/package.json +98 -3
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AgentFlow } from "../format/flow-format.js";
|
|
2
|
+
import type { StateMap } from "../engine/migrate-run.js";
|
|
3
|
+
import type { FlowChatRecord, FlowStore, SaveFlowVersionResult } from "../store/flow-store.js";
|
|
4
|
+
import type { ChatMigrator, LoadedFlow } from "./flow-types.js";
|
|
5
|
+
export interface ChatMigratorDeps {
|
|
6
|
+
store: FlowStore;
|
|
7
|
+
now: () => Date;
|
|
8
|
+
/** Разобрать и проверить сценарий приложения; с ошибками — `null`. */
|
|
9
|
+
checkedFlow(loaded: LoadedFlow): AgentFlow | null;
|
|
10
|
+
/** Сохранить уже проверенный сценарий версии. */
|
|
11
|
+
saveVersion(loaded: LoadedFlow, flow: AgentFlow): Promise<SaveFlowVersionResult>;
|
|
12
|
+
/** Пересчитать таймер переведённого чата по новой версии. Запись чата к этому времени уже на новой версии. */
|
|
13
|
+
rescheduleMigrated(input: {
|
|
14
|
+
record: FlowChatRecord;
|
|
15
|
+
flow: AgentFlow;
|
|
16
|
+
map: StateMap;
|
|
17
|
+
}): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/** Перевод чатов на новую версию пачками: версия меняется сразу, состояние — в начале следующего хода чата. */
|
|
20
|
+
export declare function createChatMigrator(deps: ChatMigratorDeps): ChatMigrator;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ToolSet } from "ai";
|
|
2
|
+
import type { FlowStore } from "../store/flow-store.js";
|
|
3
|
+
import type { CardToolsTurn, ClientFactStore } from "./flow-types.js";
|
|
4
|
+
export declare const FLOW_NOTE_TOOL = "flow_note";
|
|
5
|
+
export declare const CLIENT_CARD_TOOL = "client_card";
|
|
6
|
+
/**
|
|
7
|
+
* `flow_note` (записать узнанное: поле карточки или заметку чата; отметить вопрос между делом) и `client_card` (показать
|
|
8
|
+
* или стереть то, что агент знает о человеке). Собираются на ход чата: им нужны человек, состояние чата и сценарий.
|
|
9
|
+
*/
|
|
10
|
+
export declare function noteTools(input: {
|
|
11
|
+
store: FlowStore;
|
|
12
|
+
now: () => Date;
|
|
13
|
+
turn: CardToolsTurn;
|
|
14
|
+
facts?: ClientFactStore;
|
|
15
|
+
}): ToolSet;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FlowPauseInput, FlowPauseSettings, FlowPort, FlowStaffReply } from "./flow-types.js";
|
|
2
|
+
import type { FlowRuntime } from "./flow-events.js";
|
|
3
|
+
/** Пауза длится столько часов после последнего ответа сотрудника; каждый его ответ продлевает (→ В4). */
|
|
4
|
+
export declare const DEFAULT_PAUSE_STAFF_SILENCE_HOURS = 2;
|
|
5
|
+
export interface FlowPauseControl {
|
|
6
|
+
pause(input: FlowPauseInput): Promise<void>;
|
|
7
|
+
resume(input: {
|
|
8
|
+
ownerId: string;
|
|
9
|
+
chatId: string;
|
|
10
|
+
}): Promise<void>;
|
|
11
|
+
/** Ответ сотрудника продлевает паузу на `staffSilenceHours` и попадает в контекст агента. */
|
|
12
|
+
noteStaffReply(input: FlowStaffReply): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare function createFlowPause({ runtime, settings, port, }: {
|
|
15
|
+
runtime: FlowRuntime;
|
|
16
|
+
settings: FlowPauseSettings;
|
|
17
|
+
port: (chat: {
|
|
18
|
+
ownerId: string;
|
|
19
|
+
chatId: string;
|
|
20
|
+
}) => Promise<FlowPort>;
|
|
21
|
+
}): FlowPauseControl;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PrepareTurn } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import { type FlowRuntime } from "./flow-events.js";
|
|
3
|
+
import { type FlowFinisher } from "./flow-finish.js";
|
|
4
|
+
/** Имена служебных сообщений `app`, которые сценарий применяет в начале хода. */
|
|
5
|
+
export declare const FLOW_TIMER_NOTICE = "flow_timer";
|
|
6
|
+
export declare const FLOW_EVENT_NOTICE = "flow_event";
|
|
7
|
+
/**
|
|
8
|
+
* `agent.prepareTurn` сценария: в начале хода, до застывших блоков, применяет всё, что случилось вне хода — ожидающие
|
|
9
|
+
* переходы судьи (только на своей ветке), события приложения, перевод версии, наступившие таймеры, — и сообщение
|
|
10
|
+
* человека («назад» после касаний). Модель получает служебное сообщение «Сработало: …» и уже новую карточку.
|
|
11
|
+
*/
|
|
12
|
+
export declare function flowPrepareTurn(runtime: FlowRuntime, appTimeZone: () => string | undefined, finisher?: () => FlowFinisher): PrepareTurn;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { FlowExtraTool } from "./extra-tool.js";
|
|
2
|
+
export declare const FLOW_SIDE_TASK_TOOL = "flow_side_task";
|
|
3
|
+
/** «осталась 1 попытка», «осталось 2 попытки»: для строки хвоста и ответов инструмента. */
|
|
4
|
+
export declare const sideTaskAttemptsText: (left: number) => string;
|
|
5
|
+
export declare const sideTaskTool: FlowExtraTool;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StepContext } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import { type FlowRuntime } from "./flow-events.js";
|
|
3
|
+
import type { FlowTailPart } from "./tail/tail-part.js";
|
|
4
|
+
/** Строки хвоста по порядку: день, рамка дня, попутные задачи. Каждую делает свой модуль. */
|
|
5
|
+
export declare const FLOW_TAIL_PARTS: readonly FlowTailPart[];
|
|
6
|
+
/**
|
|
7
|
+
* `agent.stepContext` со строками сценария. Номер дня, рамки и попутные задачи — только здесь: хвост не пишется в историю
|
|
8
|
+
* и стоит после всех кэшируемых частей, постоянная инструкция от дня не зависит. Сначала хвост приложения, затем строки
|
|
9
|
+
* сценария. Сценарий без «Дней и времени» и попутных задач — хвост приложения как есть.
|
|
10
|
+
*/
|
|
11
|
+
export declare function withStepTail(own: StepContext | undefined, runtime: FlowRuntime, parts?: readonly FlowTailPart[]): StepContext;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AgentFlow } from "../../format/flow-format.js";
|
|
2
|
+
import type { FlowRun } from "../../engine/flow-run.js";
|
|
3
|
+
import type { FlowRuntime } from "../flow-events.js";
|
|
4
|
+
/** Что видит строка хвоста шага: сценарий чата и место. Моменты — по часам чата. */
|
|
5
|
+
export interface FlowTailInput {
|
|
6
|
+
ownerId: string;
|
|
7
|
+
chatId: string;
|
|
8
|
+
flow: AgentFlow;
|
|
9
|
+
run: FlowRun;
|
|
10
|
+
now: number;
|
|
11
|
+
/** Пояс человека: известный, иначе приложения или сервера. Нет — UTC (строки без «Дней и времени» его не читают). */
|
|
12
|
+
timeZone?: string;
|
|
13
|
+
/** Хранилище и карточка клиента: строке, которой нужны данные человека (попутные задачи). Нет — такая строка молчит. */
|
|
14
|
+
runtime?: FlowRuntime;
|
|
15
|
+
/** Ход ведёт сотрудник, а не человек: личное ему не предлагаем. */
|
|
16
|
+
staff?: boolean;
|
|
17
|
+
/** Пояс человека неизвестен, а сегодня его первый день до первой ночи (В1): тогда агент узнаёт город. Считает этап 4. */
|
|
18
|
+
askTimeZone?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Одна строка хвоста шага; нечего сказать — `null`. */
|
|
21
|
+
export type FlowTailPart = (input: FlowTailInput) => string | null | Promise<string | null>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type FlowRun } from "../engine/flow-run.js";
|
|
2
|
+
import { type FlowRuntime } from "./flow-events.js";
|
|
3
|
+
import type { FlowPort, FlowTestClockInput, FlowTimers } from "./flow-types.js";
|
|
4
|
+
/** Ключ данных чата (`Chat.data`) с пометкой тестового чата и сдвигом его часов. */
|
|
5
|
+
export declare const FLOW_TEST_CHAT_KEY = "flowTestChat";
|
|
6
|
+
/** Данные нового тестового чата: `service.createChat(userId, { data: flowTestChatData() })`. */
|
|
7
|
+
export declare function flowTestChatData(): Record<string, unknown>;
|
|
8
|
+
/** Сдвиг часов из данных чата, мс; `null` — чат не тестовый. */
|
|
9
|
+
export declare function testChatOffset(data: Record<string, unknown> | undefined): number | null;
|
|
10
|
+
/** Часы чата, мс: часы сервера плюс сдвиг тестового чата. */
|
|
11
|
+
export declare const chatTime: (run: Pick<FlowRun, "timeOffset"> | null | undefined, serverNow: number) => number;
|
|
12
|
+
/**
|
|
13
|
+
* Промотать часы тестового чата вперёд: на `ms` или до начала следующего дня сценария (`to: "next_day_start"`). Сдвиг
|
|
14
|
+
* в данные чата, ближайший таймер пересчитан по новым часам и, если наступил, срабатывает сразу (агент пишет первым по
|
|
15
|
+
* обычным правилам); возврат — после конца этого хода. Чат не тестовый — ошибка.
|
|
16
|
+
*/
|
|
17
|
+
export declare function advanceTestClock(input: {
|
|
18
|
+
runtime: FlowRuntime;
|
|
19
|
+
port: FlowPort;
|
|
20
|
+
timers: FlowTimers | null;
|
|
21
|
+
ownerId: string;
|
|
22
|
+
chatId: string;
|
|
23
|
+
clock: FlowTestClockInput;
|
|
24
|
+
}): Promise<{
|
|
25
|
+
timeOffset: number;
|
|
26
|
+
}>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BeforeTurnHandler } from "@ykurilov/agent-chat-core";
|
|
2
|
+
import type { FlowAdmit } from "./admit.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ворота хода сценария: сообщение человека (`send`) проходит через `admit`. Готовая фраза — `{ reply }`, промолчать —
|
|
5
|
+
* `{ hold }`. Закончен разговор — по режиму сценария (→ В6): `reply` — ход идёт, агент ответит по общей части;
|
|
6
|
+
* `silent` — сообщение записано, агент молчит.
|
|
7
|
+
*/
|
|
8
|
+
export declare function flowTurnGate(admit: FlowAdmit): BeforeTurnHandler;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type SqliteFlowStore } from "./store/sqlite.js";
|
|
2
|
+
export type { SqliteFlowStore } from "./store/sqlite.js";
|
|
3
|
+
export { FLOWS_MIGRATIONS_TABLE } from "./store/migration-settings.js";
|
|
4
|
+
export { flowChats, flowClientCards, flowFirstMessages, flowVersions } from "./store/sqlite-schema.js";
|
|
5
|
+
/**
|
|
6
|
+
* Сценарии в файле SQLite; файл может быть общим с хранилищем чатов (`createSqliteChatStorage`).
|
|
7
|
+
* Таблицы приводятся к последней миграции при открытии.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sqliteFlowStore(filePath: string): SqliteFlowStore;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StateMap } from "../engine/migrate-run.js";
|
|
2
|
+
import type { ChatsInState, MigrateBatchInput, PendingFlowChange } from "./flow-store.js";
|
|
3
|
+
/** Ожидающий перевод версии. Ключ с временем: перевод v1 → v2 → v1 → v2 не схлопывается в один. */
|
|
4
|
+
export declare function migratePending(input: MigrateBatchInput): PendingFlowChange;
|
|
5
|
+
/** Переход, применённый в срок без хода: «забрать» его не снимает — «Переделать» на той же ветке применит его снова. */
|
|
6
|
+
export declare const appliedInTime: (change: PendingFlowChange) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Ожидающее после `addPending`: новый ключ — в конец; тот же ключ — прежний остаётся, но `appliedAt` нового дописывается,
|
|
9
|
+
* если его не было (переход отложили ночью, а утром применили в срок). Ничего не изменилось — `null`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pendingAdded(pending: readonly PendingFlowChange[], change: PendingFlowChange): PendingFlowChange[] | null;
|
|
12
|
+
/** Состояние после перевода: удалённое — по карте, остальное как было. Зеркало для подсчёта до следующего хода. */
|
|
13
|
+
export declare const mappedState: (stateId: string, map: StateMap) => string;
|
|
14
|
+
export declare const byVersionAndState: (left: ChatsInState, right: ChatsInState) => -1 | 0 | 1;
|
|
15
|
+
/** Порядок строк как у базы (`COLLATE "C"` и `BINARY`): по кодам символов, без учёта языка. */
|
|
16
|
+
export declare const compareText: (left: string, right: string) => -1 | 0 | 1;
|
|
17
|
+
/** Время к одному виду: `toISOString` с миллисекундами, как его вернёт база. */
|
|
18
|
+
export declare const normalizeTime: (iso: string) => string;
|
|
19
|
+
/** PostgreSQL не хранит символ NUL ни в тексте, ни в JSON: вырезаем его до записи. */
|
|
20
|
+
export declare function withoutNul<T>(value: T): T;
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import type { AgentFlow } from "../format/flow-format.js";
|
|
2
|
+
import type { FlowEndReason, Transition } from "../engine/flow-run.js";
|
|
3
|
+
import type { StateMap } from "../engine/migrate-run.js";
|
|
4
|
+
/** Что случилось с чатом вне хода; применит `prepareTurn` следующего хода. Повтор с тем же `key` ничего не добавляет. */
|
|
5
|
+
export type PendingFlowChange = {
|
|
6
|
+
kind: "transition";
|
|
7
|
+
key: string;
|
|
8
|
+
transition: Transition;
|
|
9
|
+
/** Последнее сообщение ветки, на которой решён переход; `null` — пустой чат. Ветку сменили — ожидание снимается. */
|
|
10
|
+
branchHead: string | null;
|
|
11
|
+
/**
|
|
12
|
+
* Переход по таймеру уже применён в срок без хода (писать первым нельзя): запись чата и `onTransition` сделаны,
|
|
13
|
+
* таймеры идут от новой ноды. Ход только переносит его в состояние чата, не сообщая заново.
|
|
14
|
+
*/
|
|
15
|
+
appliedAt?: string;
|
|
16
|
+
} | {
|
|
17
|
+
kind: "event";
|
|
18
|
+
key: string;
|
|
19
|
+
name: string;
|
|
20
|
+
data?: unknown;
|
|
21
|
+
at: string;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "migrate";
|
|
24
|
+
key: string;
|
|
25
|
+
versionId: string;
|
|
26
|
+
map: StateMap;
|
|
27
|
+
at: string;
|
|
28
|
+
};
|
|
29
|
+
/** Чат, который идёт по сценарию: версия закреплена, состояние и ближайший таймер — для выборок и тика. */
|
|
30
|
+
export interface FlowChatRecord {
|
|
31
|
+
chatId: string;
|
|
32
|
+
ownerId: string;
|
|
33
|
+
flowId: string;
|
|
34
|
+
versionId: string;
|
|
35
|
+
/** Копия состояния из `FlowRun` для счёта чатов по состояниям. Правда — в состоянии чата. */
|
|
36
|
+
stateId: string;
|
|
37
|
+
pending: PendingFlowChange[];
|
|
38
|
+
/** Ближайший таймер: когда, какое условие и на какой ветке он посчитан. */
|
|
39
|
+
dueAt: string | null;
|
|
40
|
+
dueExitId: string | null;
|
|
41
|
+
dueBranchHead: string | null;
|
|
42
|
+
/** Пояс человека (IANA): от него «время суток» и тихие часы. Запасной: сначала — пояс человека (`readTimeZone`). */
|
|
43
|
+
timeZone: string;
|
|
44
|
+
updatedAt: string;
|
|
45
|
+
/** Разговор закончился: таймеров и касаний больше нет. */
|
|
46
|
+
endedAt: string | null;
|
|
47
|
+
endReason: FlowEndReason | null;
|
|
48
|
+
/** Пауза «отвечает живой сотрудник» до этого момента; таймеры не берутся. */
|
|
49
|
+
pausedUntil: string | null;
|
|
50
|
+
/** Канал приложения закрыл окно: первым не писать до сообщения человека. */
|
|
51
|
+
windowClosed: boolean;
|
|
52
|
+
/** День сценария («ГГГГ-ММ-ДД»), который агент закрыл (`flow_close_day`): сегодня первым не пишет. */
|
|
53
|
+
dayClosedOn: string | null;
|
|
54
|
+
/** Недоставленный ответ, который ждёт повтора. */
|
|
55
|
+
delivery: FlowPendingDelivery | null;
|
|
56
|
+
/** Куда приложение перенесло чат при закреплении; первый ход кладёт это место в состояние чата и снимает запись. */
|
|
57
|
+
placement: FlowChatPlacement | null;
|
|
58
|
+
}
|
|
59
|
+
/** Моменты, от которых считаются дни и сроки перенесённого чата (ISO). */
|
|
60
|
+
export interface FlowChatPlacement {
|
|
61
|
+
startedAt: string;
|
|
62
|
+
enteredAt: string;
|
|
63
|
+
/** Последнее сообщение человека. */
|
|
64
|
+
lastHumanAt?: string;
|
|
65
|
+
/** Последнее сообщение агента: ответ или касание. */
|
|
66
|
+
lastAgentAt?: string;
|
|
67
|
+
/** Следующий шаг ряда касаний. */
|
|
68
|
+
nudgeStep?: number;
|
|
69
|
+
/** Сколько сообщений человек написал за день сценария к моменту `at`: день считается по поясу человека, когда он известен. */
|
|
70
|
+
humanToday?: {
|
|
71
|
+
at: string;
|
|
72
|
+
count: number;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Повтор доставки того же текста по ключу `messageId`, без нового хода модели. */
|
|
76
|
+
export interface FlowPendingDelivery {
|
|
77
|
+
messageId: string;
|
|
78
|
+
/** Номер следующей попытки, с 1. */
|
|
79
|
+
attempt: number;
|
|
80
|
+
retryAt: string;
|
|
81
|
+
/** Причины хода «пишет первым» — для `FlowOutgoing.reasons`. */
|
|
82
|
+
reasons: string[];
|
|
83
|
+
}
|
|
84
|
+
export interface PinFlowChatInput {
|
|
85
|
+
chatId: string;
|
|
86
|
+
ownerId: string;
|
|
87
|
+
flowId: string;
|
|
88
|
+
versionId: string;
|
|
89
|
+
stateId: string;
|
|
90
|
+
timeZone: string;
|
|
91
|
+
/** Чат перенесён в заданное место: до первого хода хранится здесь, переживая перезапуск сервера. */
|
|
92
|
+
placement?: FlowChatPlacement;
|
|
93
|
+
at: string;
|
|
94
|
+
}
|
|
95
|
+
export type FlowChatPatch = Partial<Pick<FlowChatRecord, "versionId" | "stateId" | "timeZone" | "placement">>;
|
|
96
|
+
export interface FlowDueInput {
|
|
97
|
+
at: string;
|
|
98
|
+
exitId: string;
|
|
99
|
+
branchHead: string | null;
|
|
100
|
+
}
|
|
101
|
+
export interface RenewLeaseInput {
|
|
102
|
+
chatId: string;
|
|
103
|
+
owner: string;
|
|
104
|
+
now: string;
|
|
105
|
+
leaseMs: number;
|
|
106
|
+
}
|
|
107
|
+
export interface SetDueOptions {
|
|
108
|
+
/** Не писать, если чат ждёт повтора доставки: у повтора свой срок, его не затереть. */
|
|
109
|
+
unlessDelivery?: boolean;
|
|
110
|
+
}
|
|
111
|
+
export interface LeaseDueInput {
|
|
112
|
+
now: string;
|
|
113
|
+
/** Копия сервера, которая берёт таймеры. */
|
|
114
|
+
owner: string;
|
|
115
|
+
leaseMs: number;
|
|
116
|
+
limit: number;
|
|
117
|
+
}
|
|
118
|
+
export interface SavedFlowVersion {
|
|
119
|
+
flowId: string;
|
|
120
|
+
versionId: string;
|
|
121
|
+
/** Отпечаток сценария: одна версия — один отпечаток. */
|
|
122
|
+
hash: string;
|
|
123
|
+
flow: AgentFlow;
|
|
124
|
+
createdAt: string;
|
|
125
|
+
}
|
|
126
|
+
/** `same` — эта версия уже сохранена с тем же отпечатком; `conflict` — под тем же номером другой сценарий. */
|
|
127
|
+
export type SaveFlowVersionResult = "new" | "same" | "conflict";
|
|
128
|
+
export interface ChatsInState {
|
|
129
|
+
versionId: string;
|
|
130
|
+
stateId: string;
|
|
131
|
+
chats: number;
|
|
132
|
+
}
|
|
133
|
+
export interface MigrateBatchInput {
|
|
134
|
+
flowId: string;
|
|
135
|
+
toVersionId: string;
|
|
136
|
+
/** Куда перевести чаты из удалённых состояний. */
|
|
137
|
+
map: StateMap;
|
|
138
|
+
limit: number;
|
|
139
|
+
at: string;
|
|
140
|
+
}
|
|
141
|
+
/** Поле карточки клиента: долгая память о человеке по всем его чатам. */
|
|
142
|
+
export interface ClientCardEntry {
|
|
143
|
+
fieldId: string;
|
|
144
|
+
value: unknown;
|
|
145
|
+
updatedAt: string;
|
|
146
|
+
/** Где узнали. */
|
|
147
|
+
chatId: string;
|
|
148
|
+
flowId: string;
|
|
149
|
+
}
|
|
150
|
+
/** Свободный факт о человеке («ведёт блог»): не поле сценария, а короткая фраза, которую агент записал сам. */
|
|
151
|
+
export interface ClientFact {
|
|
152
|
+
/** Стабильный по тексту (`factId`): тот же факт — тот же id. */
|
|
153
|
+
id: string;
|
|
154
|
+
text: string;
|
|
155
|
+
updatedAt: string;
|
|
156
|
+
/** Где узнали. */
|
|
157
|
+
chatId: string;
|
|
158
|
+
flowId: string;
|
|
159
|
+
}
|
|
160
|
+
export interface WriteCardFieldInput {
|
|
161
|
+
ownerId: string;
|
|
162
|
+
fieldId: string;
|
|
163
|
+
value: unknown;
|
|
164
|
+
chatId: string;
|
|
165
|
+
flowId: string;
|
|
166
|
+
at: string;
|
|
167
|
+
}
|
|
168
|
+
/** Попытки попутной задачи: на человека (`chatId: null`) или на разговор. */
|
|
169
|
+
export interface SideTaskRecord {
|
|
170
|
+
taskId: string;
|
|
171
|
+
chatId: string | null;
|
|
172
|
+
/** Сколько раз агент предложил. */
|
|
173
|
+
asks: number;
|
|
174
|
+
doneAt: string | null;
|
|
175
|
+
}
|
|
176
|
+
export interface NoteSideTaskInput {
|
|
177
|
+
ownerId: string;
|
|
178
|
+
taskId: string;
|
|
179
|
+
/** `null` — попытки на человека; id чата — у задач «заново в каждом разговоре». */
|
|
180
|
+
chatId: string | null;
|
|
181
|
+
status: "asked" | "done";
|
|
182
|
+
at: string;
|
|
183
|
+
}
|
|
184
|
+
export interface FlowStore {
|
|
185
|
+
/** Закрепить версию за чатом. Чат уже закреплён — вернуть как есть, ничего не менять. */
|
|
186
|
+
pinChat(input: PinFlowChatInput): Promise<FlowChatRecord>;
|
|
187
|
+
getChat(chatId: string): Promise<FlowChatRecord | null>;
|
|
188
|
+
updateChat(chatId: string, patch: FlowChatPatch, at: string): Promise<FlowChatRecord | null>;
|
|
189
|
+
deleteChat(chatId: string): Promise<void>;
|
|
190
|
+
/** Новый ключ — в конец; тот же ключ — не дублируется, но `appliedAt` дописывается к ожидающему без него. */
|
|
191
|
+
addPending(chatId: string, change: PendingFlowChange): Promise<void>;
|
|
192
|
+
/** Забрать всё ожидающее, в порядке добавления, и очистить; переходы, применённые в срок (`appliedAt`), остаются. */
|
|
193
|
+
takePending(chatId: string): Promise<PendingFlowChange[]>;
|
|
194
|
+
/** `null` — таймеров нет. Снимает аренду. */
|
|
195
|
+
setDue(chatId: string, due: FlowDueInput | null, options?: SetDueOptions): Promise<void>;
|
|
196
|
+
/** Взять в аренду наступившие таймеры, которые никто не держит; ранние — первыми. Законченные и стоящие на паузе — пропустить. */
|
|
197
|
+
leaseDue(input: LeaseDueInput): Promise<FlowChatRecord[]>;
|
|
198
|
+
releaseLease(chatId: string, owner: string): Promise<void>;
|
|
199
|
+
/** Продлить свою аренду до `now + leaseMs`. `false` — строка уже не наша: взяла другая копия или срок переписан. */
|
|
200
|
+
renewLease(input: RenewLeaseInput): Promise<boolean>;
|
|
201
|
+
saveVersion(input: Omit<SavedFlowVersion, "createdAt"> & {
|
|
202
|
+
at: string;
|
|
203
|
+
}): Promise<SaveFlowVersionResult>;
|
|
204
|
+
getVersion(flowId: string, versionId: string): Promise<SavedFlowVersion | null>;
|
|
205
|
+
countChatsByState(input: {
|
|
206
|
+
flowId: string;
|
|
207
|
+
}): Promise<ChatsInState[]>;
|
|
208
|
+
/** Перевести до `limit` чатов на версию `toVersionId`: версия меняется сразу, перевод состояния — ожидающим `migrate`. */
|
|
209
|
+
migrateBatch(input: MigrateBatchInput): Promise<{
|
|
210
|
+
moved: string[];
|
|
211
|
+
}>;
|
|
212
|
+
readCard(ownerId: string): Promise<ClientCardEntry[]>;
|
|
213
|
+
writeCardField(input: WriteCardFieldInput): Promise<void>;
|
|
214
|
+
forgetCard(ownerId: string, fieldId: string | "all"): Promise<void>;
|
|
215
|
+
/** Сколько сообщений агент написал первым за сутки человека (`day` — «ГГГГ-ММ-ДД» в его поясе). */
|
|
216
|
+
countFirstMessages(ownerId: string, day: string): Promise<number>;
|
|
217
|
+
/** Записать ещё одно; вернуть новый счёт. */
|
|
218
|
+
addFirstMessage(ownerId: string, day: string): Promise<number>;
|
|
219
|
+
/** Разговор закончен: ставит время и причину, снимает таймер. Уже закончен — ничего не меняет. */
|
|
220
|
+
endChat(chatId: string, input: {
|
|
221
|
+
reason: FlowEndReason;
|
|
222
|
+
at: string;
|
|
223
|
+
}): Promise<FlowChatRecord | null>;
|
|
224
|
+
/** `null` — снять паузу. */
|
|
225
|
+
setPause(chatId: string, until: string | null): Promise<FlowChatRecord | null>;
|
|
226
|
+
setWindowClosed(chatId: string, closed: boolean): Promise<void>;
|
|
227
|
+
setDayClosed(chatId: string, day: string | null): Promise<void>;
|
|
228
|
+
setDelivery(chatId: string, delivery: FlowPendingDelivery | null): Promise<void>;
|
|
229
|
+
/** Пояс человека (IANA); `null` — неизвестен. Общий для всех его чатов. */
|
|
230
|
+
readTimeZone(ownerId: string): Promise<string | null>;
|
|
231
|
+
writeTimeZone(ownerId: string, timeZone: string, at: string): Promise<void>;
|
|
232
|
+
/** Попытки попутных задач человека: на человека и в этом разговоре. По `taskId`. */
|
|
233
|
+
readSideTasks(ownerId: string, chatId: string): Promise<SideTaskRecord[]>;
|
|
234
|
+
/** `asked` — ещё одна попытка, `done` — задача решена. Вернуть запись после изменения. */
|
|
235
|
+
noteSideTask(input: NoteSideTaskInput): Promise<SideTaskRecord>;
|
|
236
|
+
/** «Забудь обо мне»: стереть все попытки попутных задач человека — и на него, и на его разговоры. */
|
|
237
|
+
forgetSideTasks(ownerId: string): Promise<void>;
|
|
238
|
+
/** Остановка сервера: SQLite закрывает файл, PostgreSQL дожидается миграции (пул приложения не закрывает). */
|
|
239
|
+
close?(): Promise<void>;
|
|
240
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Своя таблица учёта: хранилище чатов, песочница, фон и мессенджеры живут в той же базе и ведут свои. */
|
|
2
|
+
export declare const FLOWS_MIGRATIONS_TABLE = "__flows_migrations";
|
|
3
|
+
/**
|
|
4
|
+
* Постоянное число для блокировки базы миграциями сценариев. Не совпадает с ключами ядра (…442), песочницы (…443),
|
|
5
|
+
* фона (…444), мессенджеров (…445) и картинок (…446).
|
|
6
|
+
*/
|
|
7
|
+
export declare const FLOWS_MIGRATION_LOCK_KEY = 7311900447;
|